В прошлом году смартфон Huawei P30 Pro потряс мир потрясающей камерой Leica с 50-кратным зумом, но это достижение скрыло еще одну особенность этого устройства, которая может быть не менее впечатляющей: заднюю камеру с функцией времени полета (TOF). Фактически, эта TOF-камера, первоначально использованная на машине XBox Kinect, может быть использована для разработки сканера глубины в реальном времени для реконструкции моделей в реальном времени! Поскольку мне было трудно понять математику оригинальной статьи KinectFusion (ссылка в конце), в которой предлагался такой метод, я хотел поделиться обзором всего конвейера и метода этого алгоритма трехмерной реконструкции. Наслаждаться!

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

Обзор

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

KinectFusion - один из старых традиционных методов, разработанных в 2011 году, который пытается использовать изображения глубины - изображения, в которых значение глубины задается вместо значений RGB для каждого пикселя - в качестве единственных входных данных для создания всей 3D-модели.

Предварительные требования

Это будет моя попытка объяснить методы KinectFusion наиболее простым и упрощенным способом. Тем не менее, небольшой опыт в матричной алгебре, такой как сложение и умножение матриц, пригодится для более быстрого и лучшего понимания. Вот два необходимых основных понятия линейной алгебры:

1. Преобразование матрицы

Представьте себе двухмерную плоскость с осью x- и осью y-, точка может быть представлена ​​в декартовой форме (x, y). Любой перенос может быть представлен вектором (cx, cy), и точка после переноса будет иметь новую координату (x + cx, y + cy). Поэтому мы можем использовать матричное вычисление для представления перевода. Точно так же поворот также может быть представлен через матрицы, также может быть представлен через матрицу вращения.

Комбинируя матрицу вращения с матрицей перевода, мы сможем вывести матричное уравнение, которое преобразует любую точку в ее новую координату после преобразования. Например, мы можем представить любую точку (x₀, y₀), вычисленную посредством преобразования (x, y), следующим образом:

где θ - угол поворота против часовой стрелки, а cx, cy - переводы в x и y - ось соответственно. Следует отметить, что это уравнение сначала выполняет вращение, а затем перемещение.

Та же идея может быть применена к трехмерному пространству; матрицы будут более сложными, но концепция очень похожа.

2. Матричная проекция

Проекцию реального объекта на изображение камеры можно просмотреть следующим образом:

Пиксель на плоскости изображения с координатой (u, v) соответствует точке (x, y, z) на 3D-объекте, и его можно найти через проекцию. вот так, используя концепцию похожих форм:

Следовательно, мы также можем представить такое вычисление в терминах матрицы, которая широко известна как внутренняя матрица камеры K:

где tx и ty - смещения, чтобы поместить камеру в центр плоскости изображения.

Затем координату проецируемого пикселя (u, v) можно рассчитать следующим образом:

где z - глубина (длина по оси z) точки P (x, y, z).

Имея в виду эти две концепции, мы можем погрузиться в 4 процедуры трехмерной реконструкции в реальном времени.

Процедура 1 - Измерение поверхности

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

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

Также важно знать, что карты глубины, полученные датчиками, обычно подвержены шумам, и поэтому в оригинальной статье KinectFusion применен двусторонний фильтр к каждой точке пикселя и использовалось отфильтрованное изображение глубины для вычисления карты вершин и нормалей. Короче говоря, этот фильтр подавляет шумы, но также предотвращает размытие краев, которое часто происходит с другими фильтрами.

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

Реализация

После получения изображения глубины обработайте положение пикселя как (u, v), а значение глубины как z. Получите K на основе спецификации, предоставленные устройством с камерой TOF, и вычислить трехмерные точки по уравнению 2. Для машины XBox Kinect, f = 525.0, tx = 319,5, и ty = 239,5. Мы можем создать класс с именем Points и просто сохранить их вектор для представления облаков точек.

Процедура 2 - Картирование и реконструкция поверхности

Чтобы объяснить эту процедуру, мы сначала представим функцию под названием TSDF (Trucated Signed Distance Function). Чтобы объяснить эту функцию, давайте взглянем на следующую иллюстрацию 2D TSDF:

Красная кривая посередине представляет поверхность объекта, и в этом случае камера будет справа от сеток / пикселей выше. SDF - это функция, в которой значение каждого пикселя определяется расстоянием от него от поверхности объекта и до камеры - чем ближе к поверхности, тем ближе значение к 0, а все значения «перед» пиксель (ближе к камере) будет положительным, а все значения «сзади» будут отрицательными. TSDF аналогичен, за исключением того, что мы устанавливаем порог, при котором, если пиксель находится слишком далеко от поверхности, он автоматически принимает значение 1 или -1. Это сократит фактическое время вычислений для реконструкции в реальном времени, поскольку мы можем пропустить единицы.

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

Но зачем нам TSDF? Потому что TSDF очень легко сплавлять. Если теперь у нас есть две функции TSDF в одних и тех же вокселях, все, что нам нужно сделать, это усреднить значение каждого вокселя, и мы получим объединенный TSDF.

Реализация

Чтобы реализовать TSDF, мы должны представить, что перед камерой есть воображаемые воксели. Например, мы можем использовать первый захваченный кадр и представить, что перед ним находятся вокселы 256x256x256, представляющие пространство 2x2x2 м³. Воксели могут быть представлены классом Voxel с его значением TSDF в программе. Теперь мы можем вычислить, какому пикселю на плоскости изображения соответствует воксель, если бы мы его проецировали. Затем мы можем получить значение глубины этого пикселя, вычислить разницу в длине и получить функцию TSDF.

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

Теперь для каждого кадра камеры после этого, если у нас есть новая поза камеры, мы можем выполнить обратное преобразование позы камеры для каждого вокселя, чтобы воксели все еще оставались в том же пространстве, в котором мы их сначала создали. Проще говоря, тот же воксель теперь будет проецироваться на другой пиксель, поскольку мы повернули или сместили камеру. Таким образом, мы можем продолжить объединение TSDF вместе, чтобы реконструировать модель! (Если, конечно, у нас есть поза камеры, что является наиболее важным шагом в KinectFusion.)

Процедура 3 - Трансляция лучей

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

В этой процедуре мы сгенерируем воображаемый луч из каждого пикселя, который идет в направлении к трехмерной точке, которая вычисляется посредством обратной проекции по уравнению 2. Луч начинается с минимальной глубины пикселя (как любой TSDF с меньшим depth будет иметь значение 1), марши с размером шага, равным длине вокселя (поэтому воксель не пропускается в середине), и останавливается, когда происходит переход через нуль (изменение с положительного на отрицательное значение TSDF). Марш также останавливается, когда есть изменение от отрицательного к положительному или когда он выходит за границы воксельного пространства, которое мы создали при вычислении TSDF.

Обратите внимание, что с помощью преобразования лучей теперь мы можем получить карту вершин слияния всех предыдущих TSDF. Мы также можем вычислить карту нормалей, вычислив градиент на поверхности, пересекающей ноль, через изменение значений значений TSDF вокселей поблизости. Мы будем называть их глобальной картой вершин и глобальной картой нормалей, поскольку они будут использоваться на заключительном этапе KinectFusion - Pose Estimation - для оценки позы каждого кадра только с помощью новой карты глубины и уже существующих TSDF.

Реализация

Мы можем вычислить единичный вектор для каждого пикселя в направлении TSDFS, который захватывает этот конкретный пиксель. мы излучаем этот воображаемый луч, начиная с глубины 0, перемещая один воксель за раз, и берем значение TSDF воксела, который в настоящее время пересекает луч. Когда мы попадаем в область пересечения нуля (положительное значение TSDF на отрицательное), мы возвращаем трехмерные координаты воксела.

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

Процедура 4 - Оценка позы

Оценка позы - последний и самый важный компонент алгоритма KinectFusion. Если поза камеры известна для каждого нового кадра глубины, мы можем легко объединить новый кадр глубины с TSDF и постепенно сгенерировать 3D-модель по мере захвата большего количества кадров.

KinectFusion использует метод под названием ICP для оценки позы. ICP расшифровывается как Iterative Closest Point, который представляет собой алгоритм, сводящий к минимуму разницу между двумя облаками точек. Математические уравнения, лежащие в основе ICP, могут быть сложными, но идея проста: медленно вращайте и перемещайте одно из двух совпадающих облаков точек так, чтобы два облака в конечном итоге выровнялись с точки зрения векторов и нормалей каждой точки.

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

Реализация

Мы получаем набор вершин и карт нормалей из процедуры 1 для вновь введенного изображения глубины. Затем мы получаем глобальную карту вершин посредством преобразования лучей и глобальную карту нормалей, используя градиенты внутри TSDF. Мы сравниваем карты нормалей и карты вершин с помощью алгоритма ICP (полное математическое объяснение этого сравнения можно найти в разделе 3.5 статьи KinectFusion), чтобы в конечном итоге получить поворот и перемещение камеры, когда она сделала новое изображение глубины.

Рабочий процесс

Таким образом, общий поток программы будет следующим:

  1. Мы получаем первое изображение карты глубины и выполняем процедуру 1 и процедуру 2, чтобы получить карту вершин и нормалей, а также сохранить ее в TSDF. На данный момент было получено только одно изображение, поэтому закрепляющую часть в Процедуре 2 можно игнорировать.
  2. Мы получаем новое изображение глубины и выполняем Процедуру 1 для этого нового изображения, одновременно обрабатывая TSDF с помощью Процедуры 3, чтобы получить карты вершин и нормалей как для TSDF, так и для новой глубины. изображение.
  3. Мы выполняем Процедуру 4, чтобы получить разницу в позе между двумя облаками точек, и объединяем TSDF с помощью Процедуры 2 после преобразования позы облака точек, созданного новой глубиной. изображение.
  4. Мы повторяем шаги 2 и 3, пока все изображения глубины не будут объединены в окончательное объединенное облако точек.

Код

Прилагается мой текущий код. Поскольку эта программа почти полностью построена с нуля, в алгоритме ICP все еще есть незначительные ошибки, которые, надеюсь, когда-нибудь будут исправлены.

Код:

Https://github.com/ttchengab/KinectFusion

Вы также можете протестировать свою собственную программу KinectFusion с наборами данных TUM RGBD-SLAM, которые можно найти здесь:

Https://vision.in.tum.de/data/datasets/rgbd-dataset

Конец примечания

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

KinectFusion Paper:

Https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/ismar2011.pdf

Если вам понравилась эта статья, убедитесь, что вы 👏 , чтобы больше людей тоже смогли ее прочитать!