背景

1.1 经典三维场景表征与神经表征

经典的三维场景表征方法有 体素表示点云表示网格表示,这三种表示是直接的、显而易见的,因此归为 显式的 场景表示类别。这里介绍的 NeRF(Neural Radiance Fields)其实也是一种三维场景表征,但是是一种 隐式的 场景表示(implicit scene representation),因为它不能像点云、网格、体素一样直接看见一个三维模型,需要将神经表征转换到显示的表征或渲染成可见的图像才可以被看到。

显示场景表征的特点是,它表示的 信号是离散的。相反,隐式神经表征 将信号参数化为连续函数,通常来说,普通的函数不可能做到这样一件事,因此用神经网络来逼近这样一个复杂的“自然函数”。

  • 显示 场景表征——离散
  • 隐式 场景表征——连续
三维场景表征

三维场景表征

1.2 经典的 SFM 重建方法

经典 SFM 重建方法

经典 SFM 重建方法

  1. 基于输入图像对相应特征进行提取,并根据特征相似性进行匹配;使用一些几何先验性知识,对匹配结果进行确认。这个过程是特征匹配的过程。经过以上步骤之后可以获得相机的位姿。
  2. 使用相机位姿投影并经过图像配准、三角化测量等步骤反复迭代,可以获得特征点的三维空间坐标。
  3. 再经过 bundle adjustment(BA)和噪声过滤的操作,便可以获得三维重建的最终结果。

1.3 NeRF 方法的思想

NeRF 工作流程

NeRF 工作流程

使用 Nerf 进行重建,也是需要相机姿态的,这一步和 colmap 没有区别。

NeRF 方法的主要想法通过输入稀疏的图像集,来优化底层的连续神经网络,该神经网络将三维场景隐式存储其中,我们只需要通过输入一个相机位姿,就可以获得场景图片,实现了合成复杂场景的全新视图。

输入图像的位姿是已知的,这一位姿既可以通过外部测量的方式获取,也可以、也是最常用的方法是使用 SFM(运动恢复结构)确定每张图像对应相机的外方位元素。

1.4 NeRF 的作用

  • 三维场景内插

左侧是输入 NeRF 中的稀疏采样的图像(大约有五、六张),在 NeRF 迭代优化后,我们可以得到该场景在新视角下的影像。因此,NeRF 解决了三维场景内插的问题。

稀疏采样图像与同一场景下的新视角

  • 生成三维模型
三维模型

三维模型

  • 深度估计
深度估计

深度估计

NeRF 方法

2.1 NeRF——使用连续神经网络表示三维场景

NeRF 是一种三维场景的神经表征,通过输入稀疏图像训练,NeRF 可以内插出同一场景的不同影像。

下面,我们来看一下 NeRF 的具体内容。NeRF 是 Neural Radiance Fields 的缩写,神经是指神经网络,辐射是因为这个神经网络表示了场景中的辐射信息。其中的场是指一个连续的函数映射,也就是这里的 \(F_\Theta\),神经辐射场使用一个神经网络作为这里的函数映射。另外,也需要说明这里使用的不是卷积神经网络,而是一个相对浅层的多层感知机:

NeRF 方法

NeRF 方法

2.2 2D->3D 类比

NeRF 的问题,如果简化到二维,其实就是图像回归问题。给定一个神经网络,它的输入是平面上的坐标 \(x\) 和 \(y\),表示了一个像素,输出是该点处的颜色值 \((R,G,B)\)。为了能够完整地映射出原图像,这个神经网络需要记忆下原图像信息,因此在这里的神经网络是过拟合的。

\[ F_\Theta : \mathbf{x} \rightarrow \mathbf{c} \]
图像回归示例

图像回归示例

这一问题在二维情况下,看起来是没有意义的,但这是对 NeRF 的一个很好的类推。在 NeRF 中,我们也用一个神经网络记忆了不同视角下图像信息,从而能够内插出新视角下的新图像。在 NeRF 中,我们需要神经网络是过拟合的,要求它能较好地学习到图像中的高频信息。

真实图片与不使用位置编码的图像

不过,我们看到在这个二维情况下,图像信息虽然好像恢复了,但没有完全恢复,图像仍然很模糊。这个问题在后面会提到如何解决(位置编码)。

2.3 立体渲染

NeRF 如何生成特定视角下的图像?——立体渲染(volume rendering)

  • 在光线上采样一系列点
  • 通过神经网络输出颜色值和密度
  • 将颜色值和密度累加生成图像
NeRF 输入与输出

NeRF 输入与输出

从这张图我们可以看到 NeRF 的输入和输出对应的具体含义。对于从左边相机拍摄的图像,以光线 1 为例,我们在上面均匀采样一系列点,这每一个点对应神经网络的输入,通过神经网络的映射,我们得到了右边对应的输出。

在得到了这一条射线上采样点的颜色值和透明度后,我们希望能得到该光线在图像上成像后的颜色值。这就需要用到 渲染

渲染就是用计算机模拟拍照这一过程,模拟“拍照”的对象是已存在的某种三维场景表示。

NeRF 将场景表示为空间中任何点的密度 \(\sigma\) 和颜色值 \(\mathbf{c}\)。 有了以 NeRF 形式存在的场景表示后,可以对该场景进行渲染,模拟生成新视角的图片。论文使用经典 立体渲染(volume rendering) 的原理,对经过相机的光线进行均匀采样,然后积分求和得到该光线的颜色。通过求解穿过场景的任何光线的颜色,就可以渲染合成新的图像。

NeRF 立体渲染

NeRF 立体渲染

  • 渲染一条光线:\(\mathbf{r}(t)=\mathbf{o}+t\mathbf{d}\)
\[ C \approx \sum_{i=1}^{N} T_i \alpha_i c_i \]
  • 从 \(t_1\) 起被遮挡的光线量:
\[ T_i = \prod_{j=1}^{i-1}(1 - \alpha_j) \]
  • 第 \(i\) 段贡献的光线量:
\[ \alpha_i = 1 - e^{-\sigma_i \delta t_i} \]

从这里的公式可以看到,渲染一条光线的颜色,就是对光线上个点的颜色值进行加权求和,权由光线的路径和路径上各段的透明度确定

2.4 使用梯度下降优化渲染损失

在渲染出一条光线的颜色后,与该光线的真实颜色对比,就可以计算出渲染的损失值。该光线的真实颜色由输出的图像确定。

\[ \min _{\Theta} \sum_i\left\|\operatorname{render}^{(i)}\left(F_{\Theta}\right)-I_{\mathrm{gt}}^{(i)}\right\|^2 \]
NeRF 渲染损失

NeRF 渲染损失

我们看到立体渲染的公式仅包含了简单的乘加和指数运算,每一步都是可微的,因此可以使用梯度下降的方式进行优化。

训练完成后,就可以得到一个以多层感知机表示的三维场景。

2.5 位置编码

通过前面的介绍,我们已经可以实现一个简单的 NeRF 了,这里可以看到简单实现的结果。不过我们会发现这个图像有点模糊,NeRF 模型没有很好地学习到图像中的高频信息。在论文中,作者使用了 位置编码 的方法,让神经网络能够更好地学习高频信息。

NeRF 原始图像与位置编码

在论文中,使用了 傅里叶基函数,对输入空间坐标坐标 \((x,y,z)\) 和方向 \((\theta,\phi)\) 进行编码。这里以二维为例,左图是之前的神经网络,这里多了一个 \(\gamma (x,y)\) 的环节,也就是对输入 \(x\),\(y\) 进行位置编码。编码的方式可以从右图中看到。\(x\) 和 \(y\) 表示了图像中像素的位置,首先将 \(x\) 和 \(y\) 归一化到 \([-1,1]\) 的区间,然后分别用傅里叶基函数进行编码,最后将两者编码的结果合并在一起。

\[ \gamma(\mathrm{x})=\left(\sin \left(2^0 \pi \mathrm{x}\right), \cos \left(2^0 \pi \mathrm{x}\right), \cdots, \sin \left(2^{L-1} \pi \mathrm{x}\right), \cos \left(2^{L-1} \pi \mathrm{x}\right)\right) \]

NeRF 加入位置编码后的图像回归示例

原来神经网络的输入是只有 \(x\),\(y\) 的一个二维向量,现在的输入变成了一个高维向量。

在上文中已经展示了使用位置编码后神经网络对二维图像的拟合结果,明显可以看到位置编码的结果更加清晰。

2.6 为什么 Fourier 位置编码有效?

这里主要是为了解释为什么傅里叶位置编码会有效?这部分偏向我个人的看法。这里进一步把二维图像回归的问题,简化为一维曲线拟合的问题。

曲线拟合示例

在曲线拟合问题中,如果只输入 \(x\),我们可以拟合一条直线,为了拟合复杂的曲线,我们从用二次曲线或三次曲线等,也就是使用 多项式基函数,将输入 \(x\),变换为 \((x^0,x^1,\ldots,x^N)\) 等。

为了更好地拟合图像中的高频信息,可以使用 高频的基函数,如 傅里叶基函数 作为输入。从右图中可以看到,当 \(L=8\) 时,傅里叶基函数对高频信息有较好的拟合。不过,这里的 \(N\) 也不宜选择过大,会增加图像中的噪声。

实验

Colmap 是一个开源的三维重建框架,提供了通用的运动恢复结构(SFM)和立体几何重建的相关功能。在实验中可用于获取相机的真实位姿。

instant-ngp 是英伟达实验室发布的一个使用 NeRF 快速三维重建的项目,能够在几秒内实现 NeRF 训练的收敛,在实际测试中,通常 2-3 秒可以看到结果,在 2 分钟内基本可以稳定下来。

参考资料

  1. Mildenhall, Ben, Pratul P. Srinivasan, Matthew Tancik, Jonathan T. Barron, Ravi Ramamoorthi and Ren Ng. 2020. “NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis.” In ECCV.
  2. Tancik, Matthew, Pratul Srinivasan, Ben Mildenhall, Sara Fridovich-Keil, Nithin Raghavan, Utkarsh Singhal, Ravi Ramamoorthi, Jonathan Barron, and Ren Ng. 2020. “Fourier Features Let Networks Learn High Frequency Functions in Low Dimensional Domains.” In NIPS.
  3. Mescheder, Lars, Michael Oechsle, Michael Niemeyer, Sebastian Nowozin, and Andreas Geiger. 2019. “Occupancy Networks: Learning 3D Reconstruction in Function Space.” In CVPR.
  4. “NeRF: Neural Radiance Fields.” https://www.youtube.com/watch?v=LRAqeM8EjOo.