Компьютерное зрение и магия перспективы: от пикселей к реальным размерам

d45c27aa7b4c6b298393184231037267.jpg

В этой статье я поделюсь опытом решения интересной практической задачки: определения линейных размеров объектов в кадре. Решение такой задачи оказалось полезным для множества приложений в компьютерном зрении и может быть использовано в картографировании, планировании, навигации, распознавании объектов, 3D-реконструкции и редактировании изображений.

Например, мы получаем кадр, в котором стоит коробка. Какого он размера? Причём размер нужно определить не в пикселах, а в сантиметрах. Вы спросите:, а что здесь такого? Кажется, что эта задача давно решена человечеством, и здесь не должно возникать никаких вопросов: бери готовый фреймворк и делай, то есть получай размеры! Я тоже так думал и пошёл по этому пути. Что из этого получилось, читайте ниже.

Забегая вперёд, скажу, что единого фреймворка для получения метрических размеров объектов в кадре не нашлось и пришлось решать задачу, разбив её на несколько подзадач.

Простой путь (как мне казалось)

Итак, первое, что приходит в голову — находим в кадре объект с известными нам геометрическими размерами, считаем количество пикселей, которое составляет, например высота известного объекта, далее делим одно на другое и получаем масштабный коэффициент перевода из пикселей в сантиметры. Потом применяем найденный масштабный коэффициент для получения размеров искомого объекта. Это совершенно рабочий подход. Однако это лишь частное решение, работающее в случае нахождения известного и искомого объектов в одной плоскости (Рис. 1)

Рисунок 1. Бутылка и спичечный коробок расположены в кадре в одной плоскости.

Рисунок 1. Бутылка и спичечный коробок расположены в кадре в одной плоскости.

Если же расположение объектов в кадре в разных плоскостях, тогда мы уже не можем впрямую делать перевод из пикселей в сантиметры пользуясь размерами известного объекта. Наши объекты в кадре подвергнуты законам перспективы [1] и визуально изменяют свои размеры (Рис. 2).

Рисунок 2. The Healing of the Cripple and Raising of Tabitha, Masolino (1426–1427)

Рисунок 2. The Healing of the Cripple and Raising of Tabitha, Masolino (1426–1427)

Получается, чем более объекты удалены от камеры, тем больше они визуально сжимаются или расширяются в случае приближения к объективу камеры. Давайте теперь посмотрим на наши бутылку со спичечным коробком в кадре в случае, когда они находятся в разных плоскостях (Рис. 3).

Рисунок 3. Бутылка и спичечный коробок расположены в кадре в разных плоскостях.

Рисунок 3. Бутылка и спичечный коробок расположены в кадре в разных плоскостях.

Теперь очевидно, что спичечный коробок визуально уменьшился в кадре, однако его фактические размеры остались неизменными. Напомню, что наша задача по-прежнему состоит в нахождении фактических размеров, в метрической системе. Как же учесть закон перспективы? Здесь нам не хватает ещё одного пространственного измерения — глубины сцены. Или проще говоря — карты глубины.

В компьютерном зрении задача нахождения карты глубины или взаимного расстояния между объектами в кадре по третьему измерению (первые два — это ширина и высота кадра) называется Depth estimation. По сути, задача нахождения карты глубины сводится к нахождению соответствия каждого пиксела кадра некоему значению определяющему его положение по глубине в кадре. Существует несколько подходов для получения карты глубины. Давайте разбираться, как это работает.

Известные подходы получения карты глубины

1. Стереопара

Это подход получения карты глубины на основе двух изображений от двух камер (стереопара), смещённых в пространстве, друг относительно друга, обычно смещение камер горизонтальное. Механизм подобный работе человеческого зрения, когда два глаза смотрят на один и тот же объект с разных углов. Разница в положении объектов на двух полученных изображениях и позволяет нам построить карту глубины.

Рисунок 4. Получение карты глубины с помощью стереопары.

Рисунок 4. Получение карты глубины с помощью стереопары.

В этом подходе есть одно важное требование: камеры должны быть хорошо откалиброваны и параметры оптики должны быть известны, что является отдельной непростой задачей.

Для выполнения качественной калибровки требуется калибровочная доска (например, с шахматным узором или кругами), размеры и точность изготовления которой напрямую влияют на результат калибровки. Также, в условиях высоких разрешений камер, требуются доски большого размера и высокого качества. Например, часто используется закалённое стекло, или другие прочные материалы для минимизации деформаций. Однако манипулирование крупной и тяжёлой доской в процессе калибровки становится серьёзной задачей.

Ещё для калибровки важно, чтобы калибровочная доска покрывала всё поле зрения обеих камер. Это необходимо для правильного определения внутренних параметров оптики и устранения дисторсий. В случае камер с широким углом обзора добиться полного покрытия непросто.

Также в промышленных системах неизбежно возникает необходимость периодической перекалибровки стереопары. Системы со временем могут терять точность из-за смещений камер (например, из-за вибраций или механических нагрузок). В идеале процедура калибровки должна быть простой и выполняться эксплуатирующим персоналом, однако зачастую это требует привлечения команды разработчиков системы.

2. Получение карты глубины по видеопотоку

Получения карты глубины из видеопотока базируется на использовании временной и пространственной информации, содержащейся в последовательности кадров. Это сложнее, чем глубина по двум изображениям (стереопара), так как видео с одной камеры не предоставляет явного смещения между двумя изображениями (как в стереопаре).

Важно, чтобы видео содержало движения камеры, или объектов, чтобы различия между кадрами давали информацию о расстоянии до объектов. Это чем-то похоже на подход со стереопарой, только в случае со стереопарой разнесение камер пространственное, а в случае с видеопотоком мы как бы имитируем вторую камеру перемещением во времени первой камеры. Однако здесь есть очевидное существенное ограничение подхода в случае неподвижности камеры и статичности объектов сцены.

Рисунок 5. Получение карты глубины по видео с взаимным движением камеры относительно объектов

Рисунок 5. Получение карты глубины по видео с взаимным движением камеры относительно объектов

3. Получение карты глубины по одному изображению

Для такого подхода применяются нейронные сети, которые по особенностям сцены в кадре (тени предметов, падение света, формы и паттерны предметов) могут получить карту глубины. В этом подходе ключевым этапом является обучение модели. В качестве разметки выступает матрица со значениями глубины для каждого пиксела входного изображения. Разметка осуществляется с использованием ToF-камер (Time-of-flight), лидаров или стереопары. Задача получение карты глубины по одному изображению получила название monocular depth estimation [2].

Подытожим сравнение подходов получения карты глубины различными подходами:

Подход

Сложность реализации

Точность карты глубины

Стереопара

Высокая

Высокая (особенно на близких объектах)

Глубина по видео

Высокая

Средняя / Высокая

Монокулярное изображение

Низкая

Средняя / Высокая

Выводы по подходам получения карты глубины:

  1. Стереопара даёт наиболее высокую точность, но требует наличия двух камер и калибровки, что увеличивает сложность реализации.

  2. Карта глубины по видео имеет высокую точность, но требуется относительное движение в кадре, что не всегда возможно, также реализация осложняется необходимостью учитывать движение камеры и объектов.

  3. Монокулярный метод самый простой в реализации, но имеет ограничения по точности, в сложных сценах, для которых необходима специализированная разметка и fine-tuning модели глубокого обучения.

Выбор подхода зависит от используемого оборудования, доступных данных (одиночные изображения, стереопара или видео) и требований к точности в конкретной задаче.

Решая задачу

Для решения нашей задачи мы остановимся на подходе получения карты глубины по одному изображению (monocular depth estimation) с помощью моделей глубокого обучения. Этот подход в настоящее время широко применяется, потому как является наиболее простым. При этом нейронные сети для получения карты глубины получили значительный прогресс в развитии, как в архитектурном плане, так и в подходах к обучению и, в настоящее время обладают достаточно высокой точностью [3, 4]. Разница между ранними и современными depth estimation моделями (Рис. 6).

Рисунок 6. Эволюция depth estimation моделей

Рисунок 6. Эволюция depth estimation моделей

На картах глубины цветовой градиент как раз и определяет степень удалённости того или иного объекта в кадре относительно наблюдателя. Причём, как правило получаемые моделью карты глубины имеют обратную зависимость: чем более далёкий объект, тем меньше значение глубины. Теперь от общей теории к нашей задаче. Для эксперимента я выбрал простую сцену со стаканом Латте и Кубиком Рубика на столе (Рис. 7).

Рисунок 7. Экспериментальная сцена со стаканом и кубиком

Рисунок 7. Экспериментальная сцена со стаканом и кубиком

На кадре слева стакан с кубиком находятся на одном расстоянии от камеры. На кадре справа кубик перемещается относительно камеры вглубь сцены на некоторое расстояние. Всё, что нам известно на данном этапе это физическая высота стакана — 120 мм. Наша задача состоит в том, чтобы понять какую физически высоту имеет кубик.

Наша задача определения размеров объектов будет состоять из нескольких подзадач:

a)       Детекция известного и искомого объектов.

b)      Получение карты глубины.

c)       Нормировка карты глубины.

d)      Компенсация перспективы.

e)      Перевод размеров в метрическую систему.

Шаг 1. Детекция объектов.

Первое, что необходимо сделать, это детектировать известный (стакан) и искомый (кубик) объекты. Сделать это можно, например при помощи SOTA моделей детекции объектов серии YOLO или Faster R-CNN. В более общем случаем это могут быть модели инстанс сегментации типа Mask R-CNN. Для нашей задачи применим Faster R-CNN. Результат детекции двух объектов (Рис. 7).

Рисунок 7. Детекция известного и искомого объектов

Рисунок 7. Детекция известного и искомого объектов

После детекции объектов из боксов мы получаем высоту наших объектов в пикселах. Вот табличка, с полученными результатами:

Высота стакана, мм

Высота стакана, пикселы

Высота кубика, пикселы

Кадр слева

Hс = 120

hс = 390

hк = 181

Кадр справа

Hс = 120

hс = 390

hк = 121

Очевидно, что на кадре справа наш кубик немного сжался относительного левого кадра. Учитывая известную фактическую высоту стакана и полученную высоту стакана в пикселах после детекции, можно рассчитать коэффициент перевода высоты из пикселей в метрическую систему.

k = \frac{H_c}{h_c} = \frac{121}{390} = 0.31 \text{ мм/пиксел}

Шаг 2. Получение карты глубины

Следующее, что необходимо сделать, получить глубину нашей сцены, чтобы понять, насколько кубик находится глубже чем стакан. Здесь и вступает в работу модель определения глубины. Для решения нашей задачи я использовал модель глубины Depth Anything V2 [5]. Эта модель замечательно работает из «коробки», вот результат её работы для нашей сцены (Рис. 8).

Рисунок 8. Получение карты глубины, модель глубины Depth Anything V2

Рисунок 8. Получение карты глубины, модель глубины Depth Anything V2

На полученной карте глубины градиент как раз и определяет степень удалённости каждого пиксела относительно наблюдателя. Жёлтые пиксели наиболее близкие к камере и соответственно тёмно-синие пиксели наиболее удалённые. Для наглядности взглянем ещё на спектры двух наших кадров (Рис. 9).

Рисунок 9. Спектры карт глубин для двух кадров(сверху - кубик и стакан в одной плоскости; снизу - кубик и стакан в разных плоскостях)

Рисунок 9. Спектры карт глубин для двух кадров
(сверху — кубик и стакан в одной плоскости; снизу — кубик и стакан в разных плоскостях)

По полученным картам глубины очевидно, что модель хорошо отработала удаление кубика вглубь сцены — кубик стал более тёмный. Также это видно по спектрам двух кадров, на которые для наглядности я нанёс объекты нашей сцены. На спектре снизу, который соответствует кадру со смещённым кубиком, хорошо заметно смещение кубика ближе к стенке стола.

Как вы могли заметить, получаемая карта глубины имеет как бы обратный характер, т.е. чем дальше объект от наблюдателя, тем значения глубины на карте меньше. Хотя это и необязательная процедура, но для лучшего понимания проинвертируем полученную карту глубины так, чтобы при удалении объекта его значения возрастали (Рис. 10).

Рисунок 10. Инвертированная карта глубины

Рисунок 10. Инвертированная карта глубины

Рисунок 11. Инвертированный спектр карты глубины

Рисунок 11. Инвертированный спектр карты глубины

Как видим, теперь задний фон имеет максимальное значение в спектре, и напротив стол начинается с минимальных значений спектра.

Шаг 3. Нормировка карты глубины

Теперь самое важное и интересное — изюминка нашего расчёта! Если мы впрямую будем использовать карту глубины для получения коэффициента компенсации перспективы, скорее всего, результат нашей трансформации будет некорректный. Почему? Оказывается, что полученная карта глубины является относительной, т.е. значения глубины не отражают реальных сантиметров или метров, а являются относительными весами пикселей.

Дело в том, что при обучении модели у неё нет информации о физических размерах объектов в кадре, нет информации макро или микросъемка. В обучающей выборке могут быть кадры с дистанциями между объектами равные как нескольким сантиметрам, так и сотням метров. Плюс ко всему картинка в кадре сильно зависит от параметров объектива камеры. Вот пример кадров с одной и той же сценой, сделанных разными объективами (Рис. 12).

Рисунок 12. Одинаковые сцены, снятые разными объективами, выглядят по-разному

Рисунок 12. Одинаковые сцены, снятые разными объективами, выглядят по-разному

Хотя физическое расстояние от нависающей кроны на переднем плане и деревом вдали одинаковое на двух кадрах, при съёмке разными объективами выглядят они по-разному. Поэтому модели сложно точно предсказать реальные расстояния до каждого пиксела. Это приводит нас к необходимости нормировки (приведения к абсолютным значениям) карты глубины под наши параметры камеры и сцены.

Есть несколько способов как отнормировать полученную карту глубины и тут всё зависит от условий конкретной задачи. В более общем случае рекомендуется сделать fine-tuning претринированной модели под наш набор данных с конкретными параметрами камеры и сцены. Архитектурно модель Depth Anything V2 состоит из мощного Vit-энкодера, формирующего карту глубины, и простой DPT головы, которая, переводит карту глубины из относительных значений в абсолютные.

Например, для используемой нами модели глубины Depth Anything V2 есть два типа претринерованных моделей разной ёмкости для Indoor (в помещении, расстояния десятки метров) и Outdoor (на открытом пространстве, расстояния сотни метров и больше) сцен.

Сам процесс fine-tuning для модели Depth Anything V2 описан здесь [6]. Для решения нашей задачи я брал за основу Depth-Anything-V2-Large модель предобученную на Indoor датасете. После дообучения модели у меня получился следующий результат (Рис. 13).

Рисунок 13. Спектр нормированной карты глубины

Рисунок 13. Спектр нормированной карты глубины

После нормировки карты глубины стакан переместился со значения 450 в район 300, а кубик — со значения 600 на 450. Заранее скажу, что это получились те самые фактические расстояния в миллиметрах, которые я устанавливал при съёмке сцены. Уже похоже на правду! Но давайте продолжим, это ещё не окончательное решение задачи, нам по-прежнему нужно найти фактическую высоту кубика.

Шаг 4. Компенсация перспективы

Чтобы получить коэффициент, компенсирующий перспективу, или коэффициент сжатия кубика при перемещении вглубь сцены — необходимо найти простое отношение глубины кубика к глубине стакана. Для этого необходимо взять «пробы» глубины с поверхности стакана и кубика. Это всегда можно сделать исходя из известных положений в кадре предметов после этапа детекции объектов. На рисунке ниже красными рамками показаны области интересующих нас объектов, по которым мы берём «пробы» глубины (Рис. 14).

Рисунок 14. Взятие проб глубины для стакана и кубика

Рисунок 14. Взятие проб глубины для стакана и кубика

Возьмём среднее по значениям внутри красных рамок на стакане и кубике и обозначим их dс и dк соответственно. Теперь можно рассчитать коэффициент компенсации перспективы.

\epsilon = \frac{d_k}{d_c} = \frac{440}{298} = 1.47

Шаг 5. Перевод размеров в метрическую систему

Итак, на последнем шаге у нас уже есть все нужные данные, осталось только рассчитать фактическую высоту кубика. Выпишем все данные, полученные на предыдущих шагах.

Параметр

Значение

Высота кубика в пикселах

hк = 121

Коэффициент перевода из пикселей в мм

k = 0,31

Коэффициент компенсации перспективы

\epsilon = 1,48

H_k = h_k \cdot \epsilon \cdot k = 55.3 \text{ мм}

Заключение.

Конечный результат получен. По нашему расчёту кубик в высоту составляет 55,3 миллиметра. Насколько хорош это результат? Фактическая высота кубика, если её замерить линейкой, составляет 56 мм, погрешность определения высоты получилась примерно 2%. Много это или мало — зависит от конкретной задачи, где применяется такой подход.

Приведу пример, как могла бы выглядеть реальная практическая задача. Представьте промышленный объект, где требуется анализировать загрузку кузова самосвала, наполненного грудой камней разных размеров, примерно такой как на рисунке 15.

Рисунок 15. Кузов самосвала с грудой камней и его карта глубины

Рисунок 15. Кузов самосвала с грудой камней и его карта глубины

Задача — определить распределение фактических размеров этих камней, чтобы рассчитать массу груза или лучше спланировать этапы дальнейшей обработки камней.

Список используемой литературы:

1.       http://www.essentialvermeer.com/technique/perspective/history.html

2.       Towards Robust Monocular Depth Estimation: Mixing Datasets for Zero-shot Cross-dataset Transfer, Ren´e Ranftl*, Katrin Lasinger*, David Hafner, Konrad Schindler, and Vladlen Koltun

3.       Обзор моделей карты глубины: https://medium.com/@patriciogv/the-state-of-the-art-of-depth-estimation-from-single-images-9e245d51a315

4.       HuggingFace модели глубины: https://huggingface.co/models? pipeline_tag=depth-estimation&sort=trending

5.       https://github.com/DepthAnything/Depth-Anything-V2 (гит на модель глубины)

6.       https://github.com/DepthAnything/Depth-Anything-V2/tree/main/metric_depth#pre-trained-models (гит на тонкую настройку модели глубины для получения метрической глубины)

© Habrahabr.ru