Реконструкция 3D-объекта по фото в программе Meshroom

О программе

Программа написана на Python. Позволяет из группы фотографий объекта с различных ракурсов получить 3D-модель этого объекта с текстурами. Внешний вид как модели, так и UV-развёртки, кажется, не отличается от результата 3D-сканирования, однако если нормальный (да и ненормальный) 3D-сканер позволить себе сможет не каждый, то фотоаппарат точно есть у всех.

Программа свободная, на сайте есть сборки под Windows и GNU/Linux. Исходники открыты, желающий может попробовать собрать и под другую ОС.

Для работы потребуется видеокарта с поддержкой CUDA.

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

Недостаток: Meshroom не позволяет выбрать области для сборки, из фоток он генерирует не только главный объект, но и окружающее пространство, что увеличивает время обработки.

Преимущество фотограмметрии перед 3D-сканером - можно реконструировать реально большие объекты, вроде зданий (правда, тут, видимо, понадобится ещё и квадракоптер).

Съёмка фото

Это не съёмка панорамы, здесь нет нужды возиться со штативом. Снимать можно с рук. Каких-либо требований к камере тоже нет – можно и на телефон (если камера на нём что-то из себя представляет, конечно). Нет необходимость соблюдать и какой-то конкретный порядок съёмки — требуется большое количество фото с разных углов, сделанных в любом порядке.

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

При съёмке необходимо перевести камеру в ручной режим: случайные изменения экспозиции в процессе съёмки полезными точно не окажутся.

Основное требование к снимкам – чёткость, ничего не должно быть смазано.

Рекомендуемое количество снимков – не менее 30. Вообще чем больше — тем лучше (правда, время обработки, очевидно, тоже будет увеличиваться). Если снимков будет слишком мало, программе может быть труднее реконструировать по ним трёхмерный объект.

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

Обработка

Перетаскиваем снимки в Meshroom из файлового менеджера. Из метаданных считывается инфа о сенсоре и о камере. Зелёный кружок рядом с фоткой говорит о том, что всё считалось нормально. Жёлтый — значит, не все данные получены. Красный — с фотками совсем что-то не так, лучше их удалить.

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

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

Цвета прогрессбара:

0. Зелёный - то, что обработано;

1. оранжевый - то, что обрабатывается;

2. синий - подготовлено для обработки;

3. красный – ошибка. Возможные причины — нехватка ОЗУ, недостаточное количество фотографий.

оранжевый - то, что обрабатывается;

Если в какой-то момент процесс остановится (обычно на прогрессбаре появляется красная полоса), можно попробовать нажать кнопку Start повторно – в некоторых случаях работа после этого может продолжиться (с того же места, где встала). Но только в некоторых — чаще остановка означает проблему, которая сама собой не решится.

Когда прогрессбар будет заполнен, появится кнопка Load Model – она загрузит во вьюпорт уже текстурированную модель (до нажатия там будет лишь облако точек). Чтобы лучше разглядеть — можно уменьшить до нуля размер точек и камер:

Этапы работы программы

Каждый этап можно запускать отдельно. ПКМ по узлу — Compute. Все предыдущие узлы в этом случае будут просчитаны автоматически.

Каждый этап создаёт свою папку. Meshing - тут будет грубая модель. MeshFilter - уже сглаженная модель, но пока без текстур. Её можно использовать для подготовки к печати.

0. CameraInit. Создаёт SFM-файл, в котором содержится инфа о камере, размере матрицы и др. Этап выполняется сразу после загрузки фото, ещё до нажатия кнопки «Start».

1. FeatureExtraction. На этом этапе «извлекаются элементы из изображений» («The next step extracts features from the images»).

2. ImageMatching. Этап предварительной обработки. Здесь Meshroom выясняет, какие изображения имеет смысл сопоставлять друг с другом.

3. FeatureMatching. Поиск соответствий между изображениями.

4. StructureFromMotion. На этом этапе определяются положения камер и характеристики этих камер. Слово «Motion» здесь употреблено как общий термин, этот этап выполняется, даже если ничего в кадрах не движется. На этом этапе создаётся облако точек. Здесь же рядом с фотками появляется значок камеры. Зелёный == всё хорошо, фотка подошла и данные из неё будут использоваться. Красный - ну ты понял.

5. PrepareDenseScene. Вроде как на этом этапе Meshroom делает что-то, направленное на борьбу с искажениями изображения («05_PrepareDenseScene’s primary function is to undistort the images»).

6. CameraConnection. Честно говоря, не понял, что конкретно тут происходит. Знающие приглашаются в комментарии для разъяснения.

7. DepthMap. Генерация карты глубины. Именно на этом этапе Meshroom провисит дольше всего. Для каждого изображения будет создана карта глубины в формате EXR.

8. DepthMapFilter. Карты глубины изначально не очень согласуются друг с другом. Некоторые карты глубины «видят» области, закрытые другими картами («certain depth maps will claim to see areas that are occluded by other depth maps»). Этап DepthMapFilter обеспечивает согласованность.

9. Meshing. Генерация меша.

10. MeshFiltering. Исправляет и дорабатывает сгенерированный меш. Сглаживание, удаление больших треугольников (которые сразу бросаются в глаза и заставляют лезть в аптечку за НИМ), удаление мелких кусков меша (при сохранении крупных).

11. Texturing. Создание UV-развёрток и проецирование на них текстур. Все тени и света сохраняются на своих местах («запекаются» в текстуру).

Настройка параметров

Параметры по умолчанию подходят для большинства случаев. Кроме того, многие параметры имеются лишь для исследовательских целей и разработчиков, а для пользователей бесполезны. Если всё хорошо работает с дефолтными настройками - ничего не трогаем, ничего не меняем.

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

Нод FeatureExtraction: опция DescriberPreset определяет, как много ключевых точек будет извлечено; меняем с Normal'а на High — это заставит Meshroom вытягивать больше деталей из фото. Это помогает, если Meshroom неправильно расставил камеры, но увеличивает время обработки. Рекомендуется делать лишь в том случае, если фотографий у нас менее 300. А если менее 50 - можно попробовать и Ultra.

Ноды FeatureMatching, FeatureExtraction, StructureFromMotion: включаем Guided Matching. В качестве DescriberType включаем AKAZE.

Dense reconstruction

DepthMap. Можно поменять параметр Downscale, влияющий на точность вычислений (и время, конечно же). Если разрешение фоток не слишком высокое, можно установить этот параметр на 1 - это повысит точность, но расчёт может оказаться раза в 4 длиннее. Чем выше число в этом параметре - тем меньше времени нужно для расчёта и тем более грубый результат на выходе.

Уменьшение количества «соседних камер» (neighbour cameras, параметры SGM: Nb Neighbour Cameras, Refine: Nb Neighbour Cameras) уменьшит время обработки. Программе нужно минимум 3 камеры, 4-х вполне достаточно для хорошего результата во многих случаях.

DepthMapFilter. Если исходные фото недостаточно плотные (dense) или смазанные, то на сгенерированной модели будет много дыр. В этом случае может быть полезно уменьшить Min Consistent Cameras и Min Consistent Cameras Bad Similarity до 2 и 3 соответственно (по умолчанию - 3 и 4).

Meshing. Если оперативки меньше 16 гигов - уменьшаем MaxPoints. Для более плотной и точной сетки, напротив, надо увеличить.

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

Texturing. Что такое разрешение (Texture Side) - всем понятно, обратим внимание на параметр Texture Downscale - коэффициент уменьшения текстуры. По умолчанию это 2, то есть разрешение текстуры будет уменьшено вдвое. Если Texture Side == 8192, а Texture Downscale == 2, то разрешение текстуры будет 4096х4096. Во всяком случае, так оно должно быть в теории. На практике у меня сгенерировалось 2 текстуры 4096х4096.

Я бы также обратил внимание на параметр Padding — что это такое, знает каждый, кто работал с UV-развёртками, и здесь он, видимо, по умолчанию несколько больше, чем нужно.

Unwrap Method имеет три варианта. Как поясняет всплывающая подсказка: Basic (> 600 тыс. фейсов) самый простой и основной, может сгенерировать несколько текстурных атласов, LSCM и ABF оптимизируют пространство и генерируют только один атлас. Последние 2 варианта подходят только для сцен, включающих не более 600 и не более 300 тысяч фейсов соответственно — если в сцене фейсов больше, на этапе Texturing возникнет ошибка. Уменьшить количество фейсов поможет нод MeshDecimate.

Можно также включить чекбокс Fill Holes.

Экспорт модели в Blender и обработка

Если реконструкция прошла успешно, возникнет вопрос о возможности экспорта модели в Blender (или ещё куда-то). Кнопки экспорта здесь нет, все файлы уже сохранены на диск автоматически.

Результаты расчётов сохраняются в папке MeshroomCache. Местонахождение зависит от того, куда сохранён файл проекта. Если файл сохранён не был — MeshroomCache будет в /tmp (для Linux, с виндовой версией не работал).

В MeshroomCache/Texturing будет obj, mtl и png-текстура.

Уже в Blender рекомендуется сделать Decimate (количество вертексов можно уменьшить в 5-10 раз без видимого вреда качеству), добавить модификатор Smooth (Repeat == около 3, Factor подбираем по своему усмотрению), включить Smooth Shading.

Из текстуры можно сразу сгенерировать (с помощью ColorRamp) roughness-map и bump-map.

Поскольку модель после такого «сканирования» будет зверски тяжёлой, а UV-развёртки — отвратительными, вероятно, имеет смысл сделать ретопологию, заново развернуть модель, а текстуры и рельеф запечь. Поскольку рельеф на сгенерированной модели физический, то карта нормалей должна получиться правильной (а не такой, какую генерируют программы типа CrazyBump).

Модель на выходе будет повёрнута под непотребным углом — надо повернуть.

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

Качественную высокополигональную модель, которая будет хорошо выглядеть без текстур, с помощью Meshroom получить сложно: обычно модель смотрится прилично только с текстурами. Несколько улучшить ситуацию могут модификаторы Smooth (2 шт.) и Displace.

Пример. Исходная модель.

Добавляем модификатор Smooth (количество итераций не стесняемся ставить большим, 50-100). Ненужный рельеф сгладился:

С помощью Displace пробуем вытянуть детали из текстуры:

Добавляем ещё один модификатор Smooth:

Сравниваем оригинальный меш и конечный:

Результат явно заметен, но даже вариант справа далёк от идеала. К сожалению, добиться лучшего качества мне не удалось, так что дальнейшая работа — ручной скульптинг.

Decimate в Meshroom’е

Аппроксимацию можно выполнить и в Meshroom’е, для этого надо добавить (нажав ПКМ) нод MeshDecimate и воткнуть его между MeshFiltering и Texturing:

В свойствах (панель справа) можно задать минимальное и максимальное количество вершин.

Черновой меш

Далее будет объяснено, как сгенерировать быструю грубую сетку для предпросмотра.

Дублируем DepthMap и все ноды, идущие после (Duplicate Nodes from Here)

- Удаляем DepthMap и DelpthMapFilter

- Соединяем PrepareDenseScene.input с Meshing.input (да, тут можно инпут одного нода подключить к инпуту же другого)

- Соединяем PrepareDenseScene.output с Texturing.inputImagesFolders

Расчёт будет производится намного быстрее, но качество будет ниже, кроме того, это сработает только с «высокотекстурированными» (high-textured) объектами.

Полезные ссылки

http://filmicworlds.com/blog/command-line-photogrammetry-with-alicevision/

https://youtu.be/O-WgQ7XcJ4M

https://github.com/alicevision/meshroom/wiki/Reconstruction-parameters

© Denis Skiba aka Mapper720

17.05.2019