Press "Enter" to skip to content

从RGB视频创建3D视频

从任何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:分割视频中的前景对象

我们流程中的下一步需要对视频中的主要前景对象进行分割或隔离,这对于估计摄像机在视频中的位置和角度至关重要。为什么呢?离相机较近的物体对姿态估计的影响远大于离相机较远的物体。举个例子,想象一下一个距离相机一米的物体移动了十厘米 —— 这将导致图像发生相当大的变化,可能是几十个像素。但是,如果同样的物体距离相机十米并且移动了相同的距离,图像的变化将不太明显。因此,我们生成一个“掩码”视频,以聚焦于姿态估计的相关区域,简化我们的计算。

我选择了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]        # 在下一个for循环中,我检查提取的帧是否大于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下载 | (右)由作者创建的带有遮罩的视频

第三步:估计相机姿态和内参

在创建遮罩帧之后,我们现在继续计算相机姿态和内参。为此,我们使用一个名为Colmap的工具。它是一个多视图立体视觉工具,可以从多个图像创建网格,并估计相机运动和内参。它有一个图形用户界面和一个命令行界面。您可以从此链接下载该工具。

一旦您启动该工具,您将在顶部工具栏上按下“Reconstruction”(如下图所示),然后选择“Automatic reconstruction”。在弹出窗口中,

  • 将“Workspace folder”设置为./datafiles/custom/triangulation
  • 将“Image folder”设置为./datafiles/custom/JPEGImages/640p/custom
  • 将“Image folder”设置为./datafiles/custom/JPEGImages/640p/custom
  • 将“Mask folder”设置为./datafiles/custom/Annotations/640p/custom
  • 勾选“Shared intrinsics”选项
  • 点击“Run”。

计算的时间取决于您拥有的图像数量和图像的分辨率。计算完成后,点击“File”下的“Export model as text”,并将输出文件保存在./datafiles/custom/triangulation中。它将创建两个文本文件和一个网格(.ply)文件。

Colmap的说明 — 图片由作者提供

这一步还没有完成,我们需要处理Colmap的输出。我已经写了一个脚本来自动化这个过程。只需在终端中运行以下命令:

python scripts/preprocess/custom/process_colmap_output.py

它将创建“custom.intrinsics.txt”、“custom.matrices.txt”和“custom.obj”。

Colmap的输出文件 — 作者提供的图片

现在我们准备好进行用于训练的数据集生成。

第四步:准备训练数据集

训练需要一个数据集,其中包含MiDas对每个帧的深度估计、相应的帧间流估计和深度序列。创建这些数据集的脚本已经在原始代码库中提供,我只修改了它们的输入和输出目录。通过运行以下命令,所有所需的文件将被创建并放置在适当的目录中:

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

在训练之前,请检查datafiles/custom_processed/frames_midas/customdatafiles/custom_processed/flow_pairs/customdatafiles/custom_processed/sequences_select_pairs_midas/custom目录中是否有.npz和.pt文件。验证完成后,我们可以继续进行训练。

第五步:训练

训练部分很简单。要使用自定义数据集训练神经网络,只需在终端中运行以下命令:

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个epochs后,我观察到损失开始饱和,因此决定不再继续训练。下面是我的训练损失曲线图:

损失与epoch曲线 — 作者提供的图片

在整个训练过程中,所有检查点都存储在目录./logdir/nets/中。此外,每个epoch结束后,训练脚本会在目录./logdir/visualize中生成测试可视化结果。这些可视化结果对于识别训练过程中可能出现的任何潜在问题以及监控损失非常有帮助。

第六步:使用训练好的模型创建每个帧的深度图

使用最新的检查点,我们现在使用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。

嗯,深度图和点云很酷,但您可能想知道如何使用它们。与传统的添加效果方法相比,深度感知效果可能更加强大。例如,深度感知处理使得能够实现各种电影效果,否则将很难实现。通过视频的估计深度,您可以无缝地融入合成相机的焦点和虚化,从而产生逼真而一致的背景模糊效果。

此外,深度感知技术还提供了实现动态效果(如“推进镜头”)的可能性。通过操纵虚拟相机的位置和内参,可以应用该效果生成令人惊叹的视觉序列。另外,深度感知的对象插入确保虚拟对象在视频中的位置固定,保持场景中的一致性。

深度图和点云的结合为引人入胜的叙事和富有想象力的视觉效果打开了无限可能,将电影制片人和艺术家的创造潜力推向新的高度。

在发布本文后,我将卷起袖子开始制作这样的效果。

祝您度过愉快的一天!

Leave a Reply

Your email address will not be published. Required fields are marked *