Візьми будь-яку фотографію й скажи, скільки метрів до предмета на ній. Ти майже напевно назвеш число — і майже напевно вгадаєш. Але вгадаєш не тому, що виміряв: ти знаєш, якого розміру бувають двері, машини й люди, і підставляєш цей розмір замість вимірювання. Забери знайомі предмети — і здогад розсиплеться. Ця тема про те, звідки береться третій вимір, коли знайомих предметів немає.
МістокВимір, якого в кадрі немає
Блок 6 закінчився питанням «якому предмету належить цей піксель». Блок 7 узявся додавати до знімка виміри, яких у ньому немає. Тема 33 витягла з картинки рядок тексту — відповідь, яка взагалі не є зображенням. Тема 34 і тема 35 додали час: спершу як сталість номера предмета між кадрами, потім як порядок кадрів усередині дії.
Лишився третій вимір — глибина. Ми називали її ще в темі 02: модель віддає масив розміру фото, але в кожній клітинці не клас, а відстань від камери в метрах. Формою це сегментація, змістом — регресія на кожному пікселі.
Тільки ось із часом і текстом усе було чесно: у відео справді є сусідні кадри, у знімку вивіски справді є літери. А глибини в одному знімку немає фізично: камера кидає тривимірний світ на пласку матрицю, і те, що відрізняло далеке від близького, втрачається безповоротно. Тому починати доводиться не з архітектури мережі, а з доводу, що саме втрачається.
НеоднозначністьОдна картинка — нескінченно багато світів
Найпростіша модель камери зветься діркова (pinhole): світло йде прямо крізь одну точку й падає на матрицю. З неї виходить одна-єдина формула, яку варто вивчити напамʼять:
Словами: видимий розмір предмета в пікселях дорівнює справжньому розміру, поділеному на відстань і помноженому на сталу камери. Тут R — справжній радіус предмета в метрах, Z — відстань від камери до предмета в метрах, r — радіус того самого предмета на знімку в пікселях, а F — фокусна відстань, теж у пікселях. Фокусна відстань — це просто число, яким камера переводить метри у пікселі; для наших прикладів вона дорівнює 500.
Порахуємо руками. Куля радіуса 0.10 м на 2 м дає r = 500 · 0.10 / 2 = 25 пікселів. Збільшимо й кулю, й відстань упʼятеро: r = 500 · 0.50 / 10 = 25. Ще раз упʼятеро: r = 500 · 2.50 / 50 = 25.
| сцена | R, м | Z, м | r, px | різних пікселів |
|---|---|---|---|---|
| яблуко зблизька | 0.10 | 2 | 25.0000 | — |
| мʼяч удалині | 0.50 | 10 | 25.0000 | 0 |
| цистерна дуже далеко | 2.50 | 50 | 25.0000 | 0 |
Між першою й третьою сценою — 25 разів: яблуко радіуса 0.10 м за два метри й цистерна радіуса 2.50 м за пʼятдесят. Причина, чому r не змінився, видна прямо у формулі: помножили і чисельник, і знаменник на те саме число, а дріб від цього не міняється. Не важать R і Z окремо — важить лише їхнє відношення. Тому світів, що дають той самий круг, не три, а нескінченно багато: кожна пара (R, Z) із тим самим відношенням R/Z.
Однаковий радіус — ще пів біди: може, кулі відрізняються яскравістю чи тінню? Ні,
і ось механізм. Яскравість точки на кулі задає нахил поверхні до світла; нахил у
точці сферичної поверхні залежить тільки від того, наскільки ця точка далеко від
центра у частках радіуса — на кулі будь-якого розміру точка «на пів радіуса
від центра» нахилена однаково. Отже нахил, а з ним і яскравість, — це функція від
частки, а сама картинка — функція від однієї величини r, яка задає, у
скільки пікселів ту частку перевести. Три сцени з однаковим r підставляють у цю
функцію однаковий аргумент і дістають однаковий результат. Порахована попіксельно
різниця всіх трьох зображень дорівнює рівно нулю — не «мало», не «в межах
шуму», а нуль: однакове r дає однакову картинку, байт у байт.
Три світи, одна картинка
Угорі — вигляд збоку: камера ліворуч, три кулі різного розміру на різних відстанях. Унизу — те, що бачить камера, і різниця першої та третьої сцен. Повзунок радіуса міняє всі три світи разом, повзунок бази вмикає друге око.
Два окаДруге око: звідки береться диспаритет
Постав дві однакові камери поруч, обʼєктивами в один бік, на відстані B одна від одної — ця відстань зветься базою (baseline). Тепер точка світу потрапляє на обидві матриці, але не в те саме місце. Різниця горизонтальних координат двох відбитків і зветься диспаритетом (disparity):
Звідки береться формула для нього — видно з подібних трикутників, і це той випадок, коли варто пройти виведення повільно.
Візьмемо точку світу з координатами (X, Y, Z): X — скільки метрів праворуч від лівої камери, Z — скільки метрів уперед. Діркова камера кидає її на матрицю за тим самим правилом «поділи на відстань і помнож на F»:
Права камера стоїть на B метрів правіше. Для неї та сама точка світу має координату X − B замість X: та сама точка, але відлічена від іншого початку.
Тепер віднімемо друге від першого. X скорочується — і це найважливіше, що тут стається: диспаритет не залежить від того, де точка стоїть по горизонталі, а залежить лише від того, як далеко вона:
Нам потрібне Z, а не d. Переставляємо:
Оце й уся стереогеометрія. Диспаритет і глибина — обернено пропорційні: чим ближче предмет, тим сильніше він «стрибає» між двома кадрами.
Звідки береться віднімання
Ліворуч — вигляд згори: та сама точка світу й два трикутники, з яких беруться дві координати. Праворуч — де вона опиняється в кожному кадрі. Схема пояснює крок 3 виведення; довжини на ній не в масштабі.
Підставимо наші числа: F = 500 px, B = 0.10 м, отже F · B = 50. Для предмета на 2 м диспаритет дорівнює 50 / 2 = 25 пікселів. На 10 м — 50 / 10 = 5. На 50 м — 1 піксель. Ті самі три сцени, які знімок не розрізняв узагалі, стерео розводить трьома різними числами.
Одразу видно й межу. На 50 м диспаритет дорівнює одному пікселю: відбитки точки в двох кадрах стоять у сусідніх клітинках, а ще далі злипаються в одну. Стерео не «стає неточним» поступово — воно впирається в піксельну сітку. А де саме впирається, вирішує база.
БазаБаза: за що платимо за точність
З формули d = F·B/Z здається, що рішення очевидне: розсунь камери
ширше, дістань більший диспаритет, отримай кращу точність задарма. Розсунемо. І
одразу заплатимо двічі.
Перша плата — спільне поле зору. Ліва камера бачить смугу світу, права — таку саму смугу, зсунуту вбік. Спільна частина — це перетин двох смуг, і він тим менший, чим більша база. Формулу для нього виведемо так само повільно, як попередню — вона коротша, і в ній усього три кроки:
Візьмімо плоску стіну на глибині Z. Кожна її точка потрапляє в правий кадр лівіше, ніж у лівий, рівно на диспаритет — а він у всіх точок стіни один і той самий, бо глибина одна: d = F · B / Z. Тобто правий кадр — це той самий лівий, зсунутий на d пікселів.
Позначмо ширину кадру через W — це просто скільки в ньому пікселів по горизонталі; у наших прикладах 320. Дві однакові смуги завширшки W, зсунуті одна відносно одної на d, перекриваються на W − d пікселях. Смужка завширшки d з одного боку пари не має: у лівому кадрі вона є, у правому її вже немає.
Ділимо на всю ширину W, щоб дістати частку, а не пікселі:
Підставмо руками: кадр 320 px, F = 500, стіна на 3 м. При базі 0.02 м зсув дорівнює 500 · 0.02 / 3 = 3.33 пікселя, а це 3.33 ÷ 320 = 1.04 % ширини, тож спільними лишаються 99.0 %. При базі 0.40 м зсув уже 500 · 0.40 / 3 = 66.67 пікселя, тобто 20.8 % ширини, і спільними лишаються 79.2 %. Пʼята частина кадру просто не має пари, і глибини там не буде ніколи.
Одразу видно й межу формули: коли F · B / Z доростає до W, спільного поля не лишається взагалі. При F = 500 і W = 320 це станеться, щойно база перевищить 0.64 · Z — для стіни на 3 м це майже два метри між камерами. Формула не «псується» на цій позначці, вона просто чесно доходить до нуля.
Друга плата — затінення (occlusion). Ближній предмет затуляє від лівої й правої камери різні шматки фону, і ширина цих однобоких смужок теж росте з базою. Тому карта глибини стереопари завжди має «тіні» вздовж контурів ближніх предметів — це не поломка алгоритму, а геометрія.
Замір показує обидва боки угоди. Стіна на 3 м, знімок 320×240,
StereoSGBM, для кожної бази свій діапазон пошуку:
| база B, м | d, px | спільне поле | покриття | похибка d, px | похибка Z, м |
|---|---|---|---|---|---|
| 0.02 | 3.33 | 99.0 % | 94.8 % | 0.227 | 0.220 |
| 0.05 | 8.33 | 97.4 % | 89.7 % | 0.227 | 0.084 |
| 0.10 | 16.67 | 94.8 % | 89.6 % | 0.291 | 0.051 |
| 0.20 | 33.33 | 89.6 % | 84.7 % | 0.227 | 0.021 |
| 0.40 | 66.67 | 79.2 % | 74.7 % | 0.290 | 0.013 |
Читай таблицю по двох стовпчиках справа. Похибка диспаритету не змінюється взагалі — 0.227-0.291 пікселя незалежно від бази, бо це властивість алгоритму, а не геометрії. А похибка глибини падає з 22 до 1.3 сантиметра, тобто у сімнадцять разів. Заплатили двадцятьма відсотками кадру: покриття впало з 94.8 % до 74.7 %.
Що дає й що забирає ширша база
Вигляд згори: дві камери, їхні поля зору й спільна частина. Смуга праворуч від сірої межі видима лише лівій камері — глибини там немає.
Z²Ціна одного пікселя росте як Z²
Найважливіша практична властивість стерео ховається в тій самій формулі
Z = F·B/d, і побачити її можна лише підставивши числа двічі.
Хай алгоритм помилився в диспаритеті рівно на один піксель. Для предмета на 1 метрі диспаритет дорівнює 50 px; помилившись на піксель, дістанемо 50 / 51 = 0.9804 м, тобто помилку 1.96 сантиметра. Для предмета на 20 метрах диспаритет дорівнює 2.5 px, і той самий піксель дає 50 / 3.5 = 14.29 м замість 20 — помилку 5.71 метра. Один і той самий піксель коштує то два сантиметри, то шість метрів. Загальна формула — просто різниця двох значень Z:
Її незручно тримати в голові, тому зазвичай наводять наближення: якщо знехтувати
одиницею поряд із d, вийде F·B/d², а оскільки d = F·B/Z, то
Ось звідки береться фраза «похибка стерео росте як квадрат відстані». Вона правильна — але має область застосовності, і знайти її можна прямо в таблиці.
| Z, м | d, px | ціна 1 px, точно | наближення Z²/(F·B) | завищення |
|---|---|---|---|---|
| 1 | 50.00 | 1.96 см | 2.00 см | 1.020 |
| 3 | 16.67 | 16.98 см | 18.00 см | 1.060 |
| 5 | 10.00 | 45.45 см | 50.00 см | 1.100 |
| 9 | 5.56 | 1.37 м | 1.62 м | 1.180 |
| 20 | 2.50 | 5.71 м | 8.00 м | 1.400 |
Наближення завищує похибку, і завищує тим сильніше, чим далі. На метрі різниця два відсотки, на двадцяти метрах — сорок. Причина видна, якщо поділити точну формулу на наближену: одиниця, якою ми знехтували, дає рівно множник
Отже похибка самої формули для похибки дорівнює оберненому диспаритету. Поки d великий, наближення чудове; щойно d падає до одиниць пікселів — а це саме та зона, заради якої формулу й дістають, — воно перестає бути наближенням. Урок ширший за стерео: перевіряй область застосовності навіть у тієї формули, яку взяв, щоб оцінити похибку.
Як росте похибка глибини
Точна крива й підручникове наближення на одному графіку. Повзунки міняють базу й субпіксельну точність зіставлення.
ВирівнюванняВирівнювання пари: чому пошук іде по рядку
Досі ми мовчки припускали, що камери стоять ідеально: обидві дивляться строго вперед, обидві на одній висоті, обидві не перекошені. Тоді точка, що в лівому кадрі лежить у рядку 137, у правому теж лежить у рядку 137 — і щоб знайти відповідність, досить пробігти один рядок.
Реальні камери так не стоять ніколи. Достатньо повернути одну з них на градус — і відповідник поїде з рядка. Наскільки поїде, залежить від того, навколо якої осі поворот. Розведімо три випадки — замір зроблено на сітці з 20 точок у кадрі:
| перекіс правої камери | 1° | 2° | 5° |
|---|---|---|---|
| нахил уперед (вісь X) | 8.86 px | 17.71 px | 44.36 px |
| поворот убік (вісь Y) | 0.13 px | 0.26 px | 0.67 px |
| крен, навколо осі зору | 1.20 px | 2.40 px | 6.00 px |
Числа — середній вертикальний розбіг у пікселях.
- Нахил уперед зсуває весь кадр угору або вниз майже однаково. Це найбільша поломка за величиною, але й найпростіша: відповідники лежать в іншому рядку, зате в одному й тому самому для всього кадру.
- Поворот убік майже не псує вертикаль — він здебільшого просто додає до всіх диспаритетів сталу. Саме тому дешеві стереомодулі допускають, щоб камери трохи «косили» вбік, але не кивали.
- Крен — найпідступніший. Кадр повертається навколо власного центра, тож точка тим сильніше йде вгору або вниз, чим далі вона від центра по горизонталі: зсув дорівнює приблизно x · sin(кут), де x — відстань до центра в пікселях. На нашій сітці з 20 точок це дає в середньому 1.20 px на градус, а на найдальшій від центра точці — 2.11 px, тобто майже вдвічі більше. Одним вибором іншого рядка це не лікується: різні місця кадру треба зсувати на різне.
Операція, яка прибирає всі три випадки одразу, зветься вирівнюванням пари (rectification): замість того щоб пересувати камери, ми перебудовуємо зображення так, ніби камери стояли ідеально. Це поворот обох кадрів у спільну площину — дві гомографії, по одній на кадр.
В OpenCV це cv2.stereoRectify: на вхід — параметри обох камер і взаємне
положення, на виході — два повороти й дві нові матриці проєкції. На парі з
перекосом на 2° вертикальний розбіг після вирівнювання дорівнює
4.26·10⁻¹⁵ пікселя. Це не «майже нуль», це нуль із точністю до
похибки чисел із рухомою комою.
Поруч живе друга функція — cv2.triangulatePoints. Вона робить
зворотну дію: маючи дві матриці проєкції й пару відбитків однієї точки, повертає її
тривимірні координати. На вирівняній парі вона відновила всі точки з похибкою
1.16·10⁻¹⁴ метра. Тобто геометрія працює точно; уся справжня похибка стерео
живе не в геометрії, а в пошуку відповідностей.
StereoSGBM впало з 99.9 % до 17.1 %, а середня похибка
диспаритету зросла з 0.390 до 21.07 пікселя. Частка грубих помилок (більше
пікселя) підскочила з 0.8 % до 99.0 %. Уже 0.25° — зсув на 2.18 пікселя —
коштують чверті покриття.Куди тікає відповідник, коли камера перекошена
Ліворуч — лівий кадр із поміченою точкою. Праворуч — правий кадр: хрестик показує, де відповідник насправді, рожева смуга — де його шукали б, рахуючи, що камери стоять ідеально.
ЗіставленняЯк шукають відповідність: BM і SGBM
Вирівняна пара звела задачу до одновимірної: для пікселя лівого кадру треба знайти
його близнюка в тому самому рядку правого. Найпростіший спосіб — блокове
зіставлення (block matching): вирізаємо навколо пікселя квадратик, скажімо 7×7,
і зсуваємо його вздовж правого рядка, рахуючи для кожного зсуву суму абсолютних
різниць яскравостей. Де сума найменша — там і відповідник, а зсув до нього і є
диспаритет. Це cv2.StereoBM.
Спосіб працює, поки в квадратику є за що зачепитись. Посеред білої стіни всі зсуви
дають майже однакову суму, і переможця визначає шум. StereoBM тоді
відмовляється відповідати й лишає піксель порожнім.
Напівглобальне зіставлення (semi-global matching, SGM) додає до суми другий
доданок: штраф за те, що диспаритет сусіда інший. Рішення для пікселя перестає
бути автономним — посеред білої стіни він бере відповідь у сусіда, який доказ мав.
Це cv2.StereoSGBM, а параметри P1 і P2 — це
рівно ці штрафи: перший за зміну на один диспаритет, другий за стрибок більше.
Замір на парі з навмисно гладкою ділянкою посередині — 320×240,
numDisparities=64, blockSize=7, середнє з пʼяти прогонів:
| алгоритм | час | покриття | похибка | грубих | гладка ділянка |
|---|---|---|---|---|---|
| StereoBM | 5.3 мс | 88.7 % | 0.390 px | 1.2 % | 20.0 % |
| StereoSGBM | 13.3 мс | 99.9 % | 0.390 px | 0.8 % | 100.0 % |
Дивись, де саме SGBM виграв. Не в точності: 0.390 проти 0.390, тобто взагалі ніяк. Не в частці грубих помилок: 0.8 % проти 1.2 %. Виграш увесь в останньому стовпчику — на гладкій ділянці BM відповів на 20 % пікселів, а SGBM на 100 %, і там він ще й точніший: 0.321 px проти 0.941. Ціна теж в одному стовпчику: 13.3 мілісекунди проти 5.3, тобто у два з половиною раза. Час залежить від машини, тому дивись на відношення, а не на самі числа.
Блокове проти напівглобального, на одному рядку
Угорі — лівий і правий рядки текстури з гладкою ділянкою посередині. Унизу — істинний профіль диспаритету й те, що знайшли два алгоритми. Обидва рахуються тут-таки, у браузері.
ПасткаnumDisparities переселяє предмет мовчки
Параметр numDisparities задає, скільки пікселів переглядати,
шукаючи відповідник. Виглядає як налаштування швидкості, а насправді це межа
найближчої відстані, яку камера здатна побачити: диспаритет ближнього предмета
великий, а поза діапазоном пошуку його немає.
Здавалося б, помилка з таким параметром має бути помітною: предмет зникне з карти.
Замір показує гірше. Сцена — три смуги текстури на глибинах 1, 3 і 9 метрів,
тобто істинні диспаритети 50.00, 16.67 і 5.56 пікселя, і StereoSGBM із
різним діапазоном пошуку:
| numDisparities | покриття | смуга 1 м | смуга 3 м | смуга 9 м |
|---|---|---|---|---|
| 16 | 76.7 % | Z = 6.90 м | Z = 3.33 м | Z = 8.51 м |
| 32 | 71.3 % | Z = 3.10 м | Z = 2.94 м | Z = 8.51 м |
| 48 | 64.8 % | Z = 1.97 м | Z = 2.94 м | Z = 8.51 м |
| 64 | 79.7 % | Z = 1.00 м | Z = 2.94 м | Z = 8.51 м |
| 80 | 74.7 % | Z = 1.00 м | Z = 2.94 м | Z = 8.51 м |
| 96 | 69.7 % | Z = 1.00 м | Z = 2.94 м | Z = 8.51 м |
| 112 | 64.7 % | Z = 1.00 м | Z = 2.94 м | Z = 8.51 м |
| 128 | 59.7 % | Z = 1.00 м | Z = 2.94 м | Z = 8.51 м |
Три речі варто прочитати окремо.
Перше: предмет не зникає — він переїжджає. При
numDisparities=16 смуга, що стоїть за метр від камери, дістає
глибину 6.90 метра. Не «немає значення» й не попередження в консолі — просто
число, майже всемеро більше за правду, у карті, яка виглядає цілком нормально.
Алгоритм зробив рівно те, що йому сказали: знайшов найкращий збіг у дозволеному
діапазоні. Правильної відповіді там не було.
Друге: помилка спадає плавно, а не стрибком. 6.90 → 3.10 → 1.97 → 1.00.
Немає порогу, за яким «стало добре». Тому підбирати numDisparities «поки
не виглядає правдоподібно» — найгірша стратегія: правдоподібно воно виглядає завжди.
Третє: за широкий діапазон платить край кадру. Починаючи з 64, покриття
падає рівно на 5 відсоткових пунктів на кожні 16 додаткових диспаритетів: 79.7 →
74.7 → 69.7 → 64.7 → 59.7. Це не збіг: перші numDisparities стовпчиків
лівого кадру пари в правому не мають, а на кадрі шириною 320 пікселів 16
диспаритетів — рівно 5 % ширини.
А от перші три рядки цього правила не слухаються: 76.7 → 71.3 → 64.8, і аж потім покриття підскакує до 79.7. Виглядає як шум, але це не шум — і побачити чому можна, не виходячи за межі таблиці. Відніми від сотні спершу втрачений край, а потім покриття, і дістанеш, скільки кадру алгоритм не зміг прочитати з власної вини:
Поки діапазон менший за 64, приблизно пʼята частина кадру лишається без відповіді — і це рівно та ближня смуга, істинний диспаритет якої (50 px) у діапазон не вміщається. Щойно діапазон її накрив, невідповідених пікселів лишається 0.3 %, і далі покриття їсть тільки край. Тобто спад 76.7 → 71.3 → 64.8 — це майже цілком той самий край, що росте по 5 пунктів, а не погіршення роботи. Рівний спад по 5 пунктів починається рівно там, де закінчуються справжні помилки — це й є найдешевша ознака, за якою видно, що діапазону вже вистачає.
numDisparities ≥ F·B/Zmin і округлюєш угору до кратного 16 (OpenCV
вимагає кратності). Робити навпаки — брати діапазон «із запасом» — означає задарма
викидати смугу кадру.І остання деталь тієї самої таблиці, на яку легко не звернути уваги. Далека смуга стоїть на 9 метрах, а виміряна глибина скрізь дорівнює 8.51 м — похибка майже пів метра, і жоден діапазон пошуку її не виправляє. Причина не в діапазоні: знайдений диспаритет дорівнює 5.88 замість істинних 5.56, тобто помилка в 0.32 пікселя. Порівняй із середньою смугою: там диспаритет 17.00 замість 16.67 — помилка 0.33 пікселя, майже така сама, — а глибина промахується лише на 6 сантиметрів. Третина пікселя коштує 6 см на трьох метрах і 49 см на девʼяти — закон Z² видно просто всередині одного заміру.
Діапазон пошуку і те, що він робить зі сценою
Числа тут — ті самі, що в таблиці вище. Повзунок обирає діапазон пошуку; ліворуч видно сцену збоку з істинними й виміряними положеннями смуг, праворуч — скільки кадру лишається придатним.
Хмара точокВід диспаритету до хмари точок
Карта диспаритету — ще не тривимірна сцена, а двовимірна картинка, у якій замість яскравості стоїть число. Щоб дістати справжні координати, кожен піксель переводять у трійку (X, Y, Z) за трьома формулами:
Тут x, y — координати пікселя в кадрі, а cx, cy — координати центра кадру. Набір таких трійок для всіх пікселів і зветься хмарою точок (point cloud).
В OpenCV це робить cv2.reprojectImageTo3D, а всі числа камери
подаються йому однією матрицею 4×4 на імʼя Q — її повертає той самий
cv2.stereoRectify. Перевіримо на знайомих числах: при F = 500 і B = 0.10
диспаритет 25 пікселів дає рівно Z = 2.0 метра — ту саму першу сцену, з якої ми
починали.
Хмара робить видимим те, що в таблиці лишалось абстракцією. Пласка стіна на двох метрах виглядає пласкою. Та сама стіна на девʼяти, виміряна з тією самою точністю в пікселях, розсипається на шар товщиною в пів метра. Це закон Z², побачений збоку.
Хмара точок і як її розмиває відстань
Три пласкі площини на 1, 3 і 9 метрах, перетворені на хмару точок. Ліворуч — вигляд згори, праворуч — під кутом. Повзунок шуму додає похибку саме до диспаритету, як і буває насправді.
Одне окоМонокулярна глибина як вивчений здогад
Повернімось до початку. Ми довели, що з одного знімка глибина не відновлюється. Але монокулярні моделі глибини існують, працюють і виглядають вражаюче. Суперечності тут немає — просто вони роблять не те, що здається.
Модель не міряє — вона згадує: на всіх картинках, які вона бачила під час
навчання, двері були заввишки два метри, а кулі — приблизно такого-то розміру.
Побачивши знайомий предмет знайомого видимого розміру, вона підставляє запамʼятаний
справжній розмір і рахує ту саму формулу Z = F·R/r. Це називають
вивченим пріором — знанням про світ, узятим не з цього знімка.
Готових ваг монокулярної глибини під рукою немає, та вони тут і не потрібні: робимо як у темі 22 з CLIP і в темі 32 із SAM: будуємо крихітну власну модель на власних сценах і пробуємо її зламати.
Сцена — три кулі на стіні. Радіуси беруться з вузького проміжку 0.16-0.24 м, відстані — з проміжку 2-7 м. Мережа — енкодер-декодер на 14 641 вагу, вихід — карта оберненої глибини (величини 1/Z, як роблять усі сучасні монокулярні моделі: обернена глибина рівномірніша й не вибухає на далеких пікселях). AdamW, 24 епохи, 600 сцен, три зерна (навчання — двадцять із чимось секунд на одному потоці):
| зерно | похибка, м | δ < 1.25 | той самий світ ×2.5 | після одного множника | сам множник |
|---|---|---|---|---|---|
| 0 | 0.879 | 0.8480 | 12.658 | 2.168 | 0.390 |
| 1 | 0.654 | 0.8913 | 12.687 | 1.567 | 0.391 |
| 2 | 0.505 | 0.9076 | 12.636 | 1.246 | 0.396 |
Стовпчик δ < 1.25 — стандартна метрика монокулярної глибини: частка пікселів, де відношення передбаченої глибини до справжньої лежить між 0.8 і 1.25. 0.85-0.91 для мережі на чотирнадцять тисяч ваг — цілком пристойно. Здогад працює.
Тепер ламаємо. Беремо ті самі 200 перевірних сцен і множимо і радіуси, і відстані на 2.5: зовсім інший світ. А зображення при цьому ті самі, побітово — бо в r = F·R/Z множник у чисельнику скорочується з множником у знаменнику, і різниця знімків до й після множення дорівнює нулю. Мережа бачить ті самі пікселі й видає ті самі числа, тож похибка підскакує з 0.5-0.9 метра до 12.6 метра на всіх трьох зернах.
Останній стовпчик показує, чого саме бракує. Ми підбираємо одне-єдине число — множник, спільний для всіх пікселів усіх 200 сцен. Похибка падає з 12.6 м до 1.2-2.2 м, тобто приблизно у 2.5 раза більше за похибку на рідному світі, а підібраний множник виходить 0.390, 0.391 і 0.396 — одиниця, поділена на 2.5. Мережа не помилилась у формі сцени; вона не знала одного числа, і цього числа не було в зображенні.
Поза стереоЧим міряють глибину, коли пари немає
Стерео — не єдиний спосіб, і в приладах воно часто йде другим номером.
- Структуроване світло. Проєктор кидає на сцену відомий візерунок, камера дивиться, як він викривився. Те саме стерео, тільки замість другої камери — проєктор, і пошук відповідностей стає тривіальним. Так працював перший Kinect. Слабке місце — сонце: надворі денне світло перебиває проєктор.
- Час прольоту (time of flight). Прилад світить імпульсом і міряє, скільки той ішов туди й назад. Похибка тут не залежить від відстані — це головна відмінність від стерео, де вона росте як Z². Зате роздільність низька, а дзеркальні й прозорі поверхні брешуть.
- Лідар. Той самий час прольоту, але променем, який швидко обмітає сцену. Дає точні відстані на сотні метрів і рідку, нерівномірну хмару точок: рядків мало, і між ними порожньо.
- Рух як база (structure from motion). Два послідовні кадри рухомої камери — майже стереопара з базою, що дорівнює пройденому шляху. Ось чому людина мимоволі похитує головою, оцінюючи відстань. Пастка та сама: якщо шлях невідомий у метрах, сцена відновиться з точністю до масштабу — форма правильна, розміри ні.
Практика ж майже завжди змішує джерела: лідар дає рідкі, але надійні відстані, камера дає густу картинку, модель зшиває їх разом. Лідарні точки грають роль тих самих «відомих розмірів», яких бракувало монокулярній мережі — вони приносять масштаб ззовні.
ПідсумокПідсумок блоку 7
Блок 7 закінчено, і це заразом кінець великої частини курсу. Перші шість блоків питали одне зображення про те, що на ньому намальовано: який це клас, де рамка, якому предмету належить піксель. Блок 7 узявся за інше питання — що з цього зображення можна дізнатися про світ, якого в ньому немає.
| Тема | Який вимір додає | Звідки він береться |
|---|---|---|
| 33 | текст — відповідь, яка не є картинкою | з форми гліфів плюс алфавіт, заданий ззовні |
| 34 | час як сталість предмета | із того, що детекції сусідніх кадрів звʼязали в один трек |
| 35 | час як порядок кадрів | із самого порядку — перемішай кадри, і вимір зникне |
| 36 | глибина в метрах | з другої камери; з одного кадру — нізвідки |
Спільне в цих чотирьох темах не в задачах — задачі різні — а в тому, як саме беруться нові виміри.
Новий вимір ніколи не «витягується» із самого зображення. Його або приносить другий вимір даних (сусідній кадр, друга камера), або доводиться підставляти знання ззовні. Тема 33 показала це на алфавіті: розпізнавач без кирилиці не помиляється «трохи» — він розкладає українські літери на схожі латинські, бо іншого виходу не має. Ця тема показала те саме на масштабі. Різниця лише в тому, що алфавіт моделі можна дати, а масштаб — узяти нізвідки.
Дірка в даних коштує дорожче за неточність моделі. Тема 34 знайшла, що підміна номера народжується не з перетину предметів, а з пропущеної детекції, і що дозвіл треку пережити один кадр без детекції важить більше за модель руху. У стерео та сама історія має інше імʼя: гладка ділянка без текстури — це дірка в даних, і всі три способи з нею впоратись (більший блок, штраф за розрив, зізнатись і не відповісти) — це способи жити з діркою, а не закрити її.
Чесна перевірка коштує один рядок. Тема 35 перемішала кадри й довела, що модель справді користується часом. Ця тема помножила світ на 2.5 й довела, що мережа не користується масштабом, бо його немає. Обидві перевірки ставлять те саме питання: «чи справді модель бере відповідь звідти, звідки я думаю?»
Метрика мусить говорити мовою задачі. Блок увів три виміри похибки, яких у курсі не було: посимвольну похибку в темі 33, підміну номера в темі 34 і похибку глибини в метрах тут. У всіх попередніх блоках метрики були безрозмірні — частки, IoU, mAP. Тут число має одиниці, і саме через одиниці стало видно, що та сама похибка «третина пікселя» означає 6 сантиметрів на трьох метрах і майже пів метра на девʼяти.
І головне, що варто забрати з теми окремо. Формула Z = F·B/d має рівно
три числа, і кожне хтось мусить знати: F — з калібрування камери, B — з
конструкції приладу, d — з пошуку відповідностей. Забери будь-яке — і метри
перетворяться на «щось ближче, щось далі». Кожне з них має ціну: база платить полем
зору, диспаритет — часом і дірками на гладких ділянках, а фокусна відстань —
калібруванням, без якого півградуса перекосу знищують 99 % правильних відповідей.
Далі курс іде від «що зображено» до «що з цим робити»: як зібрати з окремих моделей працюючу систему й що ламається, коли вона виходить із лабораторії у світ. Набір вимірів для цього тепер повний — простір, час, текст і глибина.