Создание 3D-видео из RGB-видео

3D-видео из RGB-видео

Инструкции по созданию последовательных видео с картой глубины и облаком точек из любых видео RGB

Изображение автора (отредактированная версия кадра видео из видеоклипов, предоставленных Videvo, загруженных с www.videvo.net)

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

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

В поисках методов генерации последовательной карты глубины видео я нашел научную статью, которая предложила интересный подход. Этот подход включает обучение двух нейронных сетей вместе, используя весь входной видеоматериал: сверточную нейронную сеть (CNN) для прогнозирования глубины и MLP для прогнозирования движения в сцене, или “потока сцены”. Эта сеть прогноза потока используется специальным образом, когда она применяется повторно в разные периоды времени. Это позволяет ей выявлять как незначительные, так и большие изменения в сцене. Незначительные изменения помогают обеспечить плавность движения от одного момента к другому в 3D, а большие изменения помогают обеспечить согласованность всего видео при просмотре с разных точек зрения. Таким образом, мы можем создавать 3D-видео, которые одновременно являются локально и глобально точными.

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

Вы можете проверить мою версию кода на моей странице GitHub, на которую я буду ссылаться.

Шаг 1: Извлечение кадров из видео

Первое, что мы делаем в процессе, это извлечение кадров из выбранного видео. Я добавил скрипт для этой цели, который вы можете найти в scripts/preprocess/custom/extract_frames_from_video.py. Чтобы запустить код, просто используйте следующую команду в терминале:

python extract_frames_from_video.py ^  -- video_path = 'ВВЕДИТЕ ПУТЬ К ВИДЕО ЗДЕСЬ' ^  -- output_dir = '../../../datafiles/custom/JPEGImages/640p/custom/' ^  -- resize_factor = 0.5

С помощью аргумента resize_factor вы можете уменьшать или увеличивать размеры кадров.

Я выбрал это видео для своих тестов. Изначально оно имело разрешение 1280×720, но для ускорения обработки в последующих шагах я уменьшил его до 640×360 с использованием resize_factor 0.5.

Шаг 2: Сегментация переднего плана в видео

Следующий шаг в нашем процессе требует сегментации или выделения одного из основных объектов переднего плана в видео, что является важным для оценки позиции и угла камеры внутри видео. Почему? Объекты, близкие к камере, существенно влияют на оценку позы больше, чем те, которые находятся дальше. Для иллюстрации представьте себе объект, находящийся на расстоянии одного метра и движущийся на 10 сантиметров – это приведет к значительному изменению изображения, возможно, десятки пикселей. Но если бы этот же объект находился на расстоянии 10 метров и двигался на то же расстояние, изменение изображения было бы намного меньше заметным. Следовательно, мы генерируем “маску” видео, чтобы сфокусироваться на значимых областях для оценки позы, упрощая наши вычисления.

Я предпочел использовать Mask-RCNN для сегментации кадров. Вы также можете использовать другие модели сегментации по своему усмотрению. Для моего видео я решил выделить человека справа, так как он остается в кадре на протяжении всего видео и кажется достаточно близким к камере.

Чтобы создать видео с маской, требуются некоторые ручные настройки, специфичные для вашего видео. Поскольку в моем видео присутствуют два человека, я начал с сегментации масок для обоих. Затем я извлек маску для человека справа через хардкодирование. Ваш подход может отличаться в зависимости от выбранного вами переднего объекта и его положения в видео. Сценарий, отвечающий за создание маски, можно найти в файле ./render_mask_video.py. Секция сценария, в которой я указываю процесс выбора маски, выглядит следующим образом:

    file_names = next(os.walk(IMAGE_DIR))[2]    for index in tqdm(range(0, len(file_names))):        image = skimage.io.imread(os.path.join(IMAGE_DIR, file_names[index]))        # Запуск детекции        results = model.detect([image], verbose=0)        r = results[0]        # В следующем цикле проверяется, больше ли размер извлеченного кадра 16000 пикселей,         # и если он находится не менее чем на 250-м пикселе по горизонтальной оси.        # Если нет, я проверял следующую маску с маской "person".        current_mask_selection = 0        while(True):            if current_mask_selection<10:                if (np.where(r["masks"][:,:,current_mask_selection]*1 == 1)[1].min()<250 or                     np.sum(r["masks"][:,:,current_mask_selection]*1)<16000):                    current_mask_selection = current_mask_selection+1                    continue                elif (np.sum(r["masks"][:,:,current_mask_selection]*1)>16000 and                       np.where(r["masks"][:,:,current_mask_selection]*1 == 1)[1].min()>250):                    break            else:                break        mask = 255*(r["masks"][:,:,current_mask_selection]*1)        mask_img = Image.fromarray(mask)        mask_img = mask_img.convert('RGB')        mask_img.save(os.path.join(SAVE_DIR, f"frame{index:03}.png"))

Оригинальное видео и видео с маской визуализируются рядом в следующей анимации:

(Слева) Стоковый материал, предоставленный Videvo, загружен с www.videvo.net | (Справа) Видео с маской, созданное автором

Шаг 3: Оценка позы камеры и внутренних параметров

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

Как только вы запустите инструмент, нажмите «Reconstruction» на верхней панели (см. рисунок ниже), затем «Automatic reconstruction». Во всплывающем окне,

  • введите ./datafiles/custom/triangulation в поле «Workspace folder»
  • введите ./datafiles/custom/JPEGImages/640p/custom в поле «Image folder»
  • введите ./datafiles/custom/JPEGImages/640p/custom в поле «Image folder»
  • введите ./datafiles/custom/Annotations/640p/custom в поле «Mask folder»
  • отметьте пункт «Shared intrinsics»
  • нажмите «Run».

Вычисление может занять некоторое время в зависимости от количества изображений и разрешения изображений. По завершении вычислений нажмите «Export model as text» в меню «File» и сохраните выходные файлы в папке ./datafiles/custom/triangulation. Это создаст два текстовых и один файл меша (.ply).

Инструкции для Colmap — Изображение от автора

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

python scripts/preprocess/custom/process_colmap_output.py

Он создаст файлы “custom.intrinsics.txt”, “custom.matrices.txt” и “custom.obj”.

Выходные файлы Colmap — Изображение автора

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

Шаг 4: Подготовка набора данных для обучения

Для обучения требуется набор данных, состоящий из оценок глубины каждого кадра от MiDas, соответствующих оценок перекадрового потока и последовательностей глубины. Скрипты для создания этих данных были предоставлены в исходном репозитории, я только изменил в них входные и выходные каталоги. Запустив следующую команду, все необходимые файлы будут созданы и размещены в соответствующих каталогах:

python scripts/preprocess/custom/generate_frame_midas.py  &python scripts/preprocess/custom/generate_flows.py  &python scripts/preprocess/custom/generate_sequence_midas.py  

Перед обучением, пожалуйста, проверьте, есть ли у вас файлы .npz и .pt в datafiles/custom_processed/frames_midas/custom, datafiles/custom_processed/flow_pairs/custom и datafiles/custom_processed/sequences_select_pairs_midas/custom. После проверки мы можем приступить к обучению.

Шаг 5: Обучение

Обучение части является простым. Чтобы обучить нейронную сеть с использованием вашего собственного набора данных, просто выполните следующую команду в терминале:

python train.py --net scene_flow_motion_field ^ --dataset custom_sequence --track_id custom ^ --log_time  --epoch_batches 2000 --epoch 10 ^ --lr 1e-6 --html_logger --vali_batches 150  ^ --batch_size 1 --optim adam --vis_batches_vali 1 ^ --vis_every_vali 1 --vis_every_train 1 ^ --vis_batches_train 1 --vis_at_start --gpu 0 ^ --save_net 1 --workers 1 --one_way ^ --loss_type l1 --l1_mul 0 --acc_mul 1 ^ --disp_mul 1 --warm_sf 5 --scene_lr_mul 1000 ^ --repeat 1 --flow_mul 1 --sf_mag_div 100 ^ --time_dependent --gaps 1,2,4,6,8 --midas ^ --use_disp --logdir 'logdir/' ^ --suffix 'track_{track_id}' ^ --force_overwrite

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

Кривая потерь по эпохам — Изображение автора

Во время обучения все контрольные точки хранятся в каталоге ./logdir/nets/. Кроме того, после каждой эпохи скрипт обучения генерирует визуализации тестов в каталоге ./logdir/visualize. Эти визуализации могут быть особенно полезны для выявления возможных проблем, которые могли возникнуть во время обучения, а также для контроля потерь.

Шаг 6: Создание карты глубины каждого кадра с использованием обученной модели

С использованием последней контрольной точки мы теперь генерируем карту глубины каждого кадра с помощью скрипта test.py. Просто выполните следующую команду в терминале:

python test.py --net scene_flow_motion_field ^ --dataset custom_sequence --workers 1 ^ --output_dir .\test_results\custom_sequence ^ --epoch 10 --html_logger --batch_size 1 ^ --gpu 0 --track_id custom --suffix custom ^ --checkpoint_path .\logdir

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

Шаг 7: Создание видео с облаками точек

На последнем шаге мы загружаем файлы .npz по кадрам и создаем цветные облака точек, используя информацию о глубине и RGB. Я использую библиотеку open3d для создания и визуализации облак точек на языке Python. Это мощный инструмент, с помощью которого вы можете создавать виртуальные камеры в трехмерном пространстве и делать снимки облак точек с их помощью. Вы также можете редактировать/изменять свои облака точек; я применял встроенные функции удаления выбросов open3d для удаления мигающих и шумных точек.

Хотя я не буду углубляться в конкретные детали использования open3d, чтобы сделать этот блог-пост лаконичным, я включил скрипт render_pointcloud_video.py, который должен быть понятен сам по себе. Если у вас возникнут вопросы или потребуется дополнительное пояснение, не стесняйтесь спрашивать.

Вот как выглядят видео с облаками точек и картами глубины для обработанного мной видео.

(Слева) Архивное видео, предоставленное Videvo, загружено с www.videvo.net | (Справа) Видео карты глубины, созданное автором | (Внизу) Видео цветных облак точек, созданное автором

Более высокое разрешение этой анимации загружено на YouTube.

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

Кроме того, глубинаосознанная техника предлагает возможность реализации динамических эффектов, таких как “долли зум”. Изменяя положение и внутренние параметры виртуальной камеры, этот эффект можно применить для создания потрясающих визуальных последовательностей. Кроме того, вставка объектов с учетом глубины гарантирует, что виртуальные объекты реалистично закреплены в видео и сохраняют постоянные положения на протяжении сцен.

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

Сразу после нажатия кнопки “опубликовать” этой статьи я примусь за создание таких эффектов.

Приятного дня!