文章目录
引言:什么是新视角合成任务
定义
新视角合成(novel view synthesis),属于计算机视觉领域,该任务要求:
- 输入源图像(source)
- 输入源姿态(source pose)
- 输入目标姿态(target pose)
最终获得:
- 目标姿态对应的的图片(target)
无论是2020eccv的best paper,nerf,还是2023年爆火的3dgs,都是为了完成nvs任务。
一般步骤
-
三维重建: 从已有视角的图像中推断出场景的三维几何信息,包括物体的形状和位置。
-
渲染: 利用三维重建的信息,通过渲染技术生成新视角下的图像,考虑光照和纹理等因素。
这两个步骤是新视角合成的基本框架,涵盖了几何重建和图像合成的关键概念。在实践中,可以根据具体应用的需求进一步细化这些步骤,例如加入光照模型、深度合成等处理,以提高合成图像的质量和真实感。
nerf的做法
让我们来以nerf为例子,更加深刻地了解一个新视角合成任务的步骤。当然,笔者不会写的特别详细,否则这篇文章就变成nerf的介绍了。如果对nerf特别感兴趣,可以阅读。

nerf的三维重建
nerf成功最大因素就在于它借用了深度学习的东西去进行三维重建。简单地说,nerf利用多层感知机(mlp)创建了一个函数。

这个函数接受一个向量 ( x , y , z , θ , ϕ ) (x,y,z,\theta,\phi ) (x,y,z,θ,ϕ)作为输入,其中, ( x , y , z ) (x,y,z) (x,y,z)表示这个点在空间中的坐标, ( θ , ϕ ) (\theta,\phi ) (θ,ϕ)表示观察角度(俯仰角pitch和偏航角yaw)。它的输出是 ( r g b , σ ) (rgb,\sigma ) (rgb,σ)。rgb很好理解,就是这个点的颜色。而 σ \sigma σ,是一个被称为体素密度的计算量。这两个输出的量是为了后面的体渲染做准备。
有了这个函数之后,对于三维空间中指定坐标的任何一点,都可以知道它的 ( r g b , σ ) (rgb,\sigma ) (rgb,σ)。而且,由于使用的是mlp来表示这个函数,那么这个函数就是连续的、可微分的,也就可以用反向传播去优化。
nerf的渲染

nerf的渲染方式采用经典的体渲染。具体的算法本文不再赘述。总而言之,体渲染需要三个参数作为输入:
- 目标位姿
- 空间中每个位置的体素密度
- 空间中每个位置的rgb颜色值
然后输出:
- 目标位姿对应的图片
当然,这种方法也是可微的。
这种体渲染的方式需要以像素为单位生成光线,然后在光线上对空间内的点进行采样,因此,每个像素点在渲染时都需要计算对应的光线,成本相当高昂,在渲染高分辨率图像时帧率非常低下,无法做到实时渲染。
同样基于这个原因,nerf优化参数时,在源图像与生成图像上只会选择一些像素点,去计算rgb颜色值的损失,进行反向传播,优化mlp的参数,而不是将所有像素点都拿来计算损失。
3dgs的三维重建
从一组图片估计点云
3dgs使用sfm(structure from motion)方法完成了从一组图片估计点云的步骤,甚至不需要给出相机的位姿就可以获得点云。这是一种非常成熟的方法,由schönberger和frahm等人于2016年提出,已经封装在colmap库中,在3dgs开源的代码中可以直接调用。


此方法的具体内容不是本文要探讨的,可阅读原文献。
高斯点云模型
3dgs从获得的稀疏点云开始,创建并且优化高斯点云。每个高斯点包含以下几个用来渲染的重要属性:
- 点的坐标,position,即3d高斯函数的均值(mean)
- 协方差矩阵,covariance matrix,决定这个高斯点的形状
- 不透明度,opacity α \alpha α,在渲染时用到
- 球谐函数,spherical harmonics,在3dgs中表示这个高斯点在任意视角下的颜色

球谐函数
球谐函数(spherical harmonics, sh)是一组定义在球面上的特殊函数,通常用来表示球面上的函数。球谐函数在图形学、计算机图形学和计算机图像等领域中广泛应用。在3dgs中,球谐函数用于近似光照和颜色分布。
虽然球谐函数是定义在球面上,但是这个函数的输入并不是坐标 ( x , y , z ) (x,y,z) (x,y,z),而是视角 ( θ , ϕ ) (\theta,\phi ) (θ,ϕ),它的输出是rgb颜色值。

只要给定了欲生成图片的目标位姿之后,就可以知道这个点对应的视角 ( θ , ϕ ) (\theta,\phi ) (θ,ϕ),从而根据这个函数计算这个点在图片上应该呈现出的颜色。因此,球谐函数的参数也是优化的目标之一。
参数优化

- 使用所有的高斯点,使用源图像的位姿,渲染出图像
- 根据源图像和渲染图像,计算损失,并反向传播进行优化。优化的对象有:
- 协方差矩阵,covariance matrix
- 不透明度,opacity α \alpha α
- 球谐函数,spherical harmonics
- 对高斯点的数量进行控制,即进行克隆、分裂或者删除
损失函数和参数优化
论文中,损失函数定义如下:
l = ( 1 − λ ) l 1 + λ l d-ssim \mathcal{l}=(1-\lambda) \mathcal{l}_{1}+\lambda \mathcal{l}_{\text {d-ssim }} l=(1−λ)l1+λld-ssim
其中, l 1 \mathcal{l}_{1} l1是实际图片与渲染图片的像素值的l1范数; l d-ssim \mathcal{l}_{\text {d-ssim }} ld-ssim 是depth-aware structural similarity (d-ssim) 损失,是一种基于结构相似性(ssim)的损失函数,但考虑了深度信息。ssim 用于衡量两幅图像在结构、亮度和对比度上的相似性。公式如下:
l d − s s i m = 1 − ( 2 μ i ^ μ i + c 1 ) ( 2 σ i ^ i + c 2 ) ( μ i ^ 2 + μ i 2 + c 1 ) ( σ i ^ 2 + σ i 2 + c 2 ) \mathcal{l}_{d-ssim} = 1 - \frac{(2\mu_{\hat{i}} \mu_i + c_1)(2\sigma_{\hat{i}i} + c_2)}{(\mu_{\hat{i}}^2 + \mu_i^2 + c_1)(\sigma_{\hat{i}}^2 + \sigma_i^2 + c_2)} ld−ssim=1−(μi^2+μi2+c1)(σi^2+σi2+c2)(2μi^μi+c1)(2σi^i+c2)
其中:
- μ i ^ \mu_{\hat{i}} μi^和 μ i \mu_i μi分别是渲染图像和真实图像的平均值。
- σ i ^ \sigma_{\hat{i}} σi^ 和 σ i \sigma_i σi分别是渲染图像和真实图像的方差。
- σ i ^ i \sigma_{\hat{i}i} σi^i 是渲染图像和真实图像之间的协方差。
- c 1 c_1 c1 和 c 2 c_2 c2 是用于稳定计算的常数。
然后,作者使用adam一阶优化器进行优化。
高斯点的数量控制(adaptive density control)
-
删除:在优化预热之后,每一百次迭代,就会删除几乎透明的高斯点,即不透明度 α \alpha α小于阈值 ϵ α \epsilon_\alpha ϵα的高斯。 ϵ α \epsilon_\alpha ϵα是个超参数,经验上设置为0.0002。
-
克隆和分裂

-
对于重建不足的高斯点,克隆一个相同大小的副本,并且沿着位置梯度方向移动。
-
对于过度重建的高斯点,对它进行分裂,分裂时还需要确定比例,经验上以超参数 ϕ = 1.6 \phi=1.6 ϕ=1.6作为这个比例。
新的问题
论文中,作者提出分裂高斯点的方法可能会导致密度的不合理增加。
于是,作者设置了以下策略:
- 每迭代n=3000次,将所有高斯点的透明度
α
\alpha
α修改为接近0的一个值。在优化时,
α
\alpha
α会在需要时增加。同时,先前的
阈值删除策略也可以很好地剔除几乎透明的高斯点。这里的n同样是个超参数。
3dgs的渲染:快速可微光栅化
笔者主要参考了此篇综述。
nerf通过体渲染去生成新的图像,这要求为每个像素都采样很多空间点。这种方法在高分辨率的图像合成中计算成本非常高昂,难以实现实时渲染速度。
与之形成鲜明对比的是,3dgs首先将空间中的3d高斯投影到基于像素的图像平面上,这个过程被称为泼溅(splatting)。随后,3dgs对这些高斯进行排序并计算每个像素的值。

- (a)泼溅步骤将 3d 高斯投射到图像空间。
- (b)3d高斯将图像划分为多个不重叠的块(tiles)。
- (c)3dgs复制覆盖多个块的高斯,为每个副本分配一个标识符 id。
- (d)通过渲染有序高斯,我们可以获得所有像素的值。渲染过程相互独立。
3dgs的渲染分为以下几步:
-
视锥剔除:给定指定的相机姿势,此步骤确定哪些高斯点位于相机的视锥体之外。这样做可以确保在后续计算中不涉及给定视图之外的高斯点,从而节省计算资源。对应代码。
-
泼溅(splatting)。在这一步骤中,高斯点被投影到2d图像空间中进行渲染,如图(a)所示。
给定视图变换 w \boldsymbol{w} w和3d协方差矩阵 σ \sigma σ ,那么投影的2d协方差矩阵 σ ′ \sigma^{\prime} σ′的计算公式如下:
σ ′ = j w σ w ⊤ j ⊤ \sigma^{\prime}=\boldsymbol{j} \boldsymbol{w} \sigma \boldsymbol{w}^{\top} \boldsymbol{j}^{\top} σ′=jwσw⊤j⊤
其中, j \boldsymbol{j} j是射影变换的仿射近似的雅可比矩阵。对应代码。 -
以像素为单位进行渲染。在深入讨论使用多种技术来提升并行计算的最终版本的3d gs之前,我们首先阐述其更简单的形式,以提供对其工作机制的洞察。给定像素的位置 x x x,可以通过视图变换 w \boldsymbol{w} w计算出它与所有重叠高斯的距离,即这些高斯的深度,形成一个排序的高斯列表 n \mathcal{n} n(对应代码)。然后,采用alpha合成(对应代码)来计算这个像素的最终颜色,对应公式如下:
c = ∑ i ∈ n c i α i ′ ∏ j = 1 i − 1 ( 1 − α j ′ ) c=\sum_{i\in\mathcal{n}}c_i \alpha_i^{\prime}\prod_{j=1}^{i-1}\left(1-\alpha_j^{\prime}\right) c=i∈n∑ciαi′j=1∏i−1(1−αj′)
其中, c i c_i ci是球谐函数输出的颜色,最终的不透明度 α i ′ \alpha_i^{\prime} αi′是学习到的不透明度 α i \alpha_i αi和高斯分布的乘积结果(对应代码),对应计算公式如下:
α i ′ = α i × exp ( − 1 2 ( x ′ − μ i ′ ) ⊤ σ i ′ − 1 ( x ′ − μ i ′ ) ) \alpha_i^{\prime}=\alpha_i\times\exp\left(-\frac12(x^{\prime}-\boldsymbol{\mu}_i^{\prime})^{\top}\boldsymbol{\sigma}_i^{\prime{-1}}(\boldsymbol{x}^{\prime}-\boldsymbol{\mu}_i^{\prime})\right) αi′=αi×exp(−21(x′−μi′)⊤σi′−1(x′−μi′))
其中, x ′ x^{\prime} x′和 μ i ′ \boldsymbol{\mu}_i^{\prime} μi′是投影空间中的坐标。
值得担忧的是,与nerfs相比,上述的渲染过程可能更慢,因为生成所需的有序列表难以并行化。实际上,这种担忧是合理的;当使用这种简单的逐像素方法时,渲染速度可能会受到显著影响。为了实现实时渲染,3dgs做出了几个妥协,以适应并行计算。 -
tiles(图像块)。为了避免为每个像素计算有序列表的计算成本,3dgs将精度从像素级别转移到块级别细节,如(b)所示。3dgs最初将图像划分为多个不重叠的图像块,这些图像块在原始论文中被称为tiles。每个块包含16x16像素。3dgs进一步确定哪些图像块与这些投影的高斯(椭圆)相交。考虑到一个投影的高斯可能覆盖多个块,一种合理的方法是复制高斯,为每个副本分配一个标识符(即块id),如(c)所示。 -
并行化渲染。复制后,3dgs会将各自的块id与每个高斯视图变换得到的深度值结合起来。这样就得到了一个未排序的字节列表,其中高位代表块id,低位表示深度。这样,排序后的列表就可以直接用于渲染。(c)(d)提供了该概念的直观演示。值得强调的是,每个块和像素的渲染都是独立进行的,因此这一过程非常适合并行计算。另外一个好处是,每个块的像素都可以访问一个公共的共享内存,并保持一个统一的读取序列,从而提高渲染的并行执行效率。在原论文的官方实现中,该框架将块和像素的处理分别视为类似于cuda编程架构中的block和thread。
3dgs的限制
一般来说,一个复杂场景需要由数百万个高斯点表示。因此,3dgs的每个场景都需要gb级别的存储空间。相比之下,nerf的一个场景只需要mb级别的空间。
发表评论