乐趣区

关于机器学习:PyTorch3D-立体隐式形状渲染教你构建场景-3D-结构

内容导读

3D 深度学习始终是机器视觉畛域的难点,为了精确高效地建设场景的平面模型,失去绝对实在的渲染成绩,行业内的一些大厂先后开源了本人的研发成绩。

本文首发自微信公众号「PyTorch 开发者社区」

随着计算机视觉畛域相干技术的倒退,针对 2D 图像的解决效率和精度失去了显著地晋升。

然而事实环境中,物体多以 3D 平面构造的模式存在,如何精确地晋升 AI 系统对简单事实环境的感知和理解能力,正确处理 3D 图像,正在成为日趋要害的技术难点。


2019 年 Facebook AI 公布 Mesh R-CNN 模型进行 3D 指标检测与形态预测

2020 年 1 月 23 日,Facebook AI 公布了 PyTorch3D v0.1.0 版本。PyTorch3D 是 PyTorch 中通过优化的、高效、可重用组件库,它具备 3 大突出特点:高效、模块化和可微分,旨在简化在 PyTorch 中进行 3D 深度学习的难度。

PyTorch3D 中提供了 3D 算子和渲染两大组件。

在 3D 算子中,Fit Mesh 能够利用 3D 损失函数,把初始的通用形态变形为指标形态,并借助一些规定让指标形态变得更为晦涩。而 3D 算子中的光束平差法(Bundle Adjustment),则提供了 cameras_、_transforms_、_so3 共计 3 个 API,依据给定相机的视角,造成对照相机视角的映射,从而推断场景的 3D 构造。

渲染则包含纹理网格渲染器(Render Textured Meshes)、DensePose 网格渲染器(Render DensePose Meshed)、黑白点云渲染器(Render Colored Pointclouds)等,借助这些渲染器,能够进一步优化造成的场景 3D 构造。

2020 年 2 月 6 日,PyTorch3D 相干代码在 GitHub 开源。通过 5 个版本的迭代后,2021 年 2 月 9 日,PyTorch3D 公布第 6 个公开版本 v0.4.0,新增隐函数、平面渲染和 NeRF 从新实现等性能,为 3D 深度学习钻研提供了更迅速、更灵便的开源库。


图为 PyTorch3D logo,由 PyTorch3D 的隐式平面渲染器生成的

隐式形态渲染(Implicit Shape Rendering)

隐式形态渲染是指基于输出场景的新视角,生成 3D 场景的实在渲染,其核心思想是利用神经网络与可微分渲染,重建 3D 场景外表的隐式状态,这使得仅依附 2D 视图就能够学习 3D 场景中的几何形态。

进行隐式形态渲染须要几个要害组件,包含数据卷的抽象类(abstraction for volume data)以及可微分的隐式形态渲染器。

为了让行业从业者更容易地针对隐式形态渲染进行尝试,PyTorch3D 曾经为用户提供了一系列罕用的 3D 算子(3D operators)和损失函数,以及一个模块化、可微分的渲染 API。在指出外围可重用组件的同时,也提供了这些组件教训证的、标准化实现办法。

在 PyTorch3D v0.4.0 中,包含 5 个反对隐式形态渲染的新个性:

1、新增数据卷构造(Volumes data structure),反对 3D 卷的批处理和坐标框架之间的转换;

2、新增多个光线纹理实现办法:

GridRaysampler

MonteCarloRaysampler

NDCGridRaysampler

3、新增多个 Raymarcher 实现办法:

AbsorptionOnlyRaymarcher

EmissionAbsorptionRaymarcher

4、新增隐式渲染器(ImplicitRenderer)和体积渲染器(VolumeRenderer)API,形成 Raysampler 和 Raymarcher

5、新增多个效用函数,如点云到体积的可微分转换。


利用 PyTorch3D 生成的甜甜圈 3D 图像

要应用这些新组件,能够借助一个模块化、文档齐备的 NeRF 从新实现。
NeRF 是一个深度学习模型,由 Google Research 团队开发,旨在借助神经辐射场(Neural Radiance Fields)示意场景,从而进行视图合成(View Synthesis)。
NeRF 仅应用非结构化图像汇合,就能合成简单的 3D 场景图。

而改良版的 NeRF 从新实现,性能失去了极大晋升,在保障输入图像品质的同时,比正式版本运行得更快。


应用 PyTorch3D 的 NeRF 从新实现性能,生成了形态和光影简单的 3D 图像示例

教程(Fit Textured Volume)

咱们基于 PyTorch3D GitHub 官网教程 Fit Textured Volume,进行了汉化和整顿,演示如何在 PyTorch3D 中,利用可微分平面渲染,根据给定场景的一组视图,预测场景的平面构造。

用 Raymarching 构建场景 3D 平面构造

本教程将介绍:

  • 如何创立一个可微分的平面渲染器;
  • 如何创立一个平面模型(包含如何应用 Volumes 类);
  • 应用可微分的平面渲染器,依据图像拟合平面构造;
  • 将预测的平面构造可视化。

备注:限于篇幅无限,本文仅展现局部代码,残缺代码请移步:

https://openbayes.com/console…

0. 装置和导入模块

确保已装置  torch  和  torchvision

如果没有装置  pytorch3d,请应用以下代码装置。

1. 生成场景及 mask 的图像

以下代码将生成本次训练数据。它会通过  fit_textured_mesh.ipynb  教程,从多个角度渲染奶牛图像,并返回以下内容:

一系列由奶牛网格渲染器生成的图像及其掠影的张量;与所有摄像机镜头一一对应的渲染器。

备注:在  generate_cow_renders  函数中实现网格渲染的工作原理请参考:
fit_textured_mesh.ipynb

target_cameras, target_images, target_silhouettes = generate_cow_renders(num_views=40)
print(f'Generated {len(target_images)} images/silhouettes/cameras.')

2. 初始化体积渲染器

初始化体积渲染器会从指标图像的每个像素收回一条射线,并沿射线采样一组距离平均的点。与每个射线点绝对应的密度值和色值,可通过查问场景的体积模型中的相应地位取得。
渲染器由一个 _raymarcher_ 和一个 _raysampler_ 形成。

raysampler_ 负责从图像像素中发射射线,并沿着射线对点进行取样。此处应用的是  _NDCGridRaysampler,它符合标准的 PyTorch3D 坐标网格标准。

raymarcher_ 取得射线采样的密度和色彩,并将所有射线渲染成光线源像素的色彩和不透明度值。此处应用的是  _EmissionAbsorptionRaymarcher,它实现了规范的  Emission-Absorption Raymarching  算法。

# render_size 示意渲染图像各个边的像素大小,将其设置为与指标图像尺寸统一
# 也就是说将其渲染成与基准图像一样的尺寸
render_size = target_images.shape[1]

# 渲染场景以(0,0,0)为核心,被限定在一个边长约等于 3.0 (国内单位)的边框内。volume_extent_world = 3.0

# 1) 实例化 raysampler
# 此处 NDCGridRaysampler 会生成一矩形图像网格的射线,其坐标遵循 pytorch3d 坐标规定
# 因为此处设定的体积是 128^3,因而取样 n_pts_per_ray=150
# 大抵相当于每个体素都有一个射线点
# 进一步设置 min_depth=0.1,因为相机立体内的所有外表都超过了 0.1 单位
raysampler = NDCGridRaysampler(
    image_width=render_size,
    image_height=render_size,
    n_pts_per_ray=150,
    min_depth=0.1,
    max_depth=volume_extent_world,
)


# 2) 实例化 raymarcher.
# 此处用的是规范 EmissionAbsorptionRaymarcher 
# 它会沿着每条射线后退
# 将每条射线都渲染成一个繁多的 3D 色彩向量和一个不透明度标量
raymarcher = EmissionAbsorptionRaymarcher()

# 最初,用 raysampler 和 raymarcher 实例化体积渲染器
renderer = VolumeRenderer(raysampler=raysampler, raymarcher=raymarcher,)

3. 初始化体积模型

接下来实例化场景的体积模型。这会使得 3D 空间量化为体积像素,其中每个体素都用体素 RGB 色彩的 3D 向量,和形容体素不透明度的密度标量(范畴在 [0-1] 之间,数字越大不通明越高)来示意。

为了保障密度和色彩的取值范畴在 [0-1] 之间,咱们会在对数空间中示意体积色彩和密度。模型运行  forward  函数时,log-space  值会通过  sigmoid  函数传递,从而使得  log-space  值处于正确的取值范畴。

此外,VolumeModel  还蕴含渲染器对象。这个对象在整个优化过程中放弃不变。

本局部代码还定义了  huber  损失函数,它能够计算出渲染色和 mask 之间的差别。

4. 体积拟合

这一步,咱们用可微分渲染来进行体积拟合。

为了拟合体积,咱们从  target_camera  的视角进行渲染,并将渲染后果与察看到的  target_images  和  target_silhouettes  进行比照。

这种比照是通过评估的  target_images/rendered_images  和  target_silhouettes/rendered_silhouettes  之间的均匀 huber(smooth-l1)误差来实现的。

5. 将优化后的场景体积进行可视化

最初,旋转场景体积的 y 轴,从多个视点进行渲染,将优化后的体积进行可视化。

def generate_rotating_volume(volume_model, n_frames = 50):
    logRs = torch.zeros(n_frames, 3, device=device)
    logRs[:, 1] = torch.linspace(0.0, 2.0 * 3.14, n_frames, device=device)
    Rs = so3_exponential_map(logRs)
    Ts = torch.zeros(n_frames, 3, device=device)
    Ts[:, 2] = 2.7
    frames = []
    print('Generating rotating volume ...')
    for R, T in zip(tqdm(Rs), Ts):
        camera = FoVPerspectiveCameras(R=R[None], 
            T=T[None], 
            znear = target_cameras.znear[0],
            zfar = target_cameras.zfar[0],
            aspect_ratio = target_cameras.aspect_ratio[0],
            fov = target_cameras.fov[0],
            device=device,
        )
        frames.append(volume_model(camera)[..., :3].clamp(0.0, 1.0))
    return torch.cat(frames)
    
with torch.no_grad():
    rotating_volume_frames = generate_rotating_volume(volume_model, n_frames=7*4)

image_grid(rotating_volume_frames.clamp(0., 1.).cpu().numpy(), rows=4, cols=7, rgb=True, fill=True)
plt.show()

6. 论断

本教程中演示了如何优化场景的 3D 平面结构,使已知视点的体积渲染与每个视点的观测图像相匹配。

教程中的渲染是应用  NDCGridRaysampler  和   EmissionAbsorptionRaymarcher  形成的 PyTorch3D 平面渲染器实现的。

为 2D 图像构建有纹理的平面形态

残缺教程请查看:_https://openbayes.com/console…_

参考:

https://ai.facebook.com/blog/…

https://github.com/facebookre…

退出移动版