我在 NeRF 中折腾自动探索式三维重建的心得
写在前面:
最近我在研究三维重建方向,深切感受到 NeRF (Neural Radiance Fields) 在学术界和工业界都备受瞩目。以往三维重建通常要依赖繁琐的多视图几何管线(比如特征匹配、深度估计、网格融合等),或者需要依靠激光雷达 / RGB-D 传感器才能得到可观的三维数据。但 NeRF 出现后,给三维重建带来了革命性的思路:它直接用一个多层感知机(MLP)来隐式建模场景位置和方向与颜色、密度的映射关系,再配合可微分的体渲染公式,就能端到端地重建出精准且逼真的场景。
然而,NeRF 往往默认已经有一批“采集好”的图像,训练时并不考虑如何采集这些图像。一旦缺乏足够且有效的多视图信息,NeRF 也很难重建出理想效果。
所以在本文里,我想分享的核心想法是:如果我们能主动控制相机的运动轨迹,怎样才能高效、全面地探索场景,从而让 NeRF 重建的质量更优?
用 NeRF 做三维重建时,如何自动选择拍摄视角?——我的探索尝试
为什么要关心相机视角?
大家可能都知道,NeRF(Neural Radiance Fields) 这种用神经网络来做三维重建的方法很火,它能在一批图像的驱动下,隐式地学习场景的几何和外观,然后渲染出各种新视角图像。但问题是,如果拍摄视角不够好,或者数据采集做得比较随意,就算再强大的 NeRF 也很难得到完整、清晰的重建。所以我就想:既然相机可以移动,那能不能自动规划相机的运动,让它去“看”最需要看的地方?这样既能节省拍摄成本,也能让 NeRF 获得更准确的三维模型。于是,就折腾出了下面这套“自动探索式”三维重建方法的思路。
一、总体想法
1. 大方向
- 一开始,用少量随机拍摄到的图像先训练出一个初步的 NeRF;
- 然后让相机(例如无人机或者机器人上的摄像头)自动探索:
- 根据当前 NeRF 的“模型不确定性”评估哪些位置、哪个角度拍摄更有价值;
- 规划相机的运动路径,让它飞过去拍摄;
- 将新获得的图像再增量更新到 NeRF 中;
- 如此循环,直到我们的 NeRF 足够“自信”,或者时间 / 资源耗尽。
2. 为啥要不确定性?
NeRF 其实暗含了一个体密度(也可以理解为“有没有东西”)的分布,某些区域如果模型还没看清,就会有比较大的“熵”(表明不确定度高)。如果在这些区域多来几张照片,模型就能对它更确定,进而让重建更加精准和全面。
二、用“熵”来衡量哪些视角值得拍
1. 信息增益的概念
我们可以把相机的某个视角记为 V V V,然后把这个视角可以“看到”的所有光线统称为 R ( V ) R(V) R(V)。如果 NeRF 在这些光线上不太确定,那就说明这个视角能带来“新知识”。用熵函数 H H H 描述不确定度的话,信息增益可以用下面这个公式来表示:
Gain ( V ∣ F ) = ∑ r ∈ R ( V ) ∫ n e a r f a r H ( σ F ( r ( t ) ) ) d t \text{Gain}(V \mid F) = \sum_{r \in R(V)} \int_{near}^{far} H\bigl(\sigma_F(r(t))\bigr)\, dt Gain(V∣F)=r∈R(V)∑∫nearfarH(σF(r(t)))dt
这里, σ F ( r ( t ) \sigma_F(r(t) σF(r(t) 是 NeRF 对光线上某点密度的估计; H ( p ) = − p log p − ( 1 − p ) log ( 1 − p ) H(p) = -p \log p - (1-p)\log(1-p) H(p)=−plogp−(1−p)log(1−p) 是二值分布的熵。当 p ≈ 0.5 p \approx 0.5 p≈0.5 时熵最大,也就代表不确定性最高。
2. 时间衰减
在实际探索中,我们希望在早期阶段多挖掘信息,因此让早期视角的增益更“值钱”,可以给它加一个时间衰减系数 1 / i 1/i 1/i:
Gain ( V i ∣ F ) = 1 i ∑ r ∈ R ( V i ) ∫ n e a r f a r H ( σ F ( r ( t ) ) ) d t \text{Gain}(V_i \mid F) = \frac{1}{i} \sum_{r \in R(V_i)} \int_{near}^{far} H\bigl(\sigma_F(r(t))\bigr)\, dt Gain(Vi∣F)=i1r∈R(Vi)∑∫nearfarH(σF(r(t)))dt
这样,在最初几次探索时,相机会更加积极地寻找那些不确定性高的区域进行拍摄;后面如果想要精修细节,也可以再继续拍,但贡献权重逐渐变低。
三、让相机别乱走——用“表面趋势场”来规划运动
1. 为什么要表面趋势?
如果一个场景的某些位置变化剧烈(比如物体的边缘或拐角处),就需要多看看;如果一片平坦空旷,可以“快步路过”。为此,我们构造了一个“表面趋势场” g ⃗ ( x ) \vec{g}(x) g(x) ,让它告诉相机:哪些地方表面变化快,值得多花点时间拍。
2. 趋势场怎么定义?
我们想要某个函数 Φ ( x ) \Phi(x) Φ(x) 来表示“距离表面有多远”。在传统 3D 里,这类似“有符号距离场 (SDF)”。NeRF 里可以用“体密度”在光线终止处做一个期望估计,得到一个近似的距离分布:
Φ ( x ) ≈ ∫ n e a r f a r d ⋅ σ F ( r ( d ) ) d d \Phi(x) \approx \int_{near}^{far} d \,\cdot\, \sigma_F(r(d)) \, dd Φ(x)≈∫nearfard⋅σF(r(d))dd
然后对 Φ \Phi Φ 做梯度,就能获得
g ⃗ ( x ) = ∇ Φ ( x ) = ( ∂ Φ ∂ x , ∂ Φ ∂ y , ∂ Φ ∂ z ) . \vec{g}(x) = \nabla \Phi(x) =\left( \frac{\partial\Phi}{\partial x}, \frac{\partial\Phi}{\partial y}, \frac{\partial\Phi}{\partial z} \right). g(x)=∇Φ(x)=(∂x∂Φ,∂y∂Φ,∂z∂Φ).
如果 ∥ g ⃗ ( x ) ∥ \|\vec{g}(x)\| ∥g(x)∥ 很大,就意味着这里的表面变化剧烈,需要重点关注。
如何理解这条公式
Φ ( x ) ≈ ∫ n e a r f a r d ⋅ σ F ( r ( d ) ) d d \Phi(x) \approx \int_{near}^{far} d \,\cdot\, \sigma_F\bigl(r(d)\bigr)\,\mathrm{d}d Φ(x)≈∫nearfard⋅σF(r(d))dd
- 这里的 d d d 表示沿光线从近端 n e a r near near 到远端 f a r far far 的 深度 (或者距离)。
- σ F ( r ( d ) ) \sigma_F\bigl(r(d)\bigr) σF(r(d)) 可以理解为 NeRF 模型对光线 r r r 在深度 d d d 处的“体密度”或“占据概率”预测。
如果我们把 σ F \sigma_F σF 看作对“物体在深度 d d d 附近出现的可能性”进行加权的函数,那么:
- 当 σ F ( r ( d ) ) \sigma_F\bigl(r(d)\bigr) σF(r(d)) 较大时,就意味着在深度 d d d 左右有更高概率遇到场景表面;
- 将深度 d d d 与该处的密度相乘,并在整个可见深度范围内积分,相当于在所有深度上做一个加权平均,得到“光线可能终止(与表面交汇)的期望深度”。
因此, Φ ( x ) \Phi(x) Φ(x) 可以近似表示“场景表面在哪儿”。在此基础上,还可以对其做梯度计算,用来估计表面的趋势或几何结构,并将这些信息应用于相机路径的规划和优化。
3. 在时间上也要优化
现在我们不只选“空间上的拍摄点”,还想决定多久拍一次、运动速度如何。于是把相机轨迹离散成一系列 t j , v j t_j, v_j tj,vj 控制点,目标是让相机尽量垂直于表面趋势运动,同时时间分配要平滑。可以写成一个优化问题:
{ t j , v j } 1 : m = arg min { t j , v j } ∑ j = 1 m − 1 ∫ t j t j + 1 ∥ v j ⋅ g ⃗ ( p ( t ) ) ∥ 2 d t + λ ∑ j = 1 m ( Δ t j ) 2 \{t_j, v_j\}_{1:m} = \arg\min_{\{t_j, v_j\}} \sum_{j=1}^{m-1} \int_{t_j}^{t_{j+1}} \bigl\| v_j \cdot \vec{g}(p(t)) \bigr\|_2 \, dt \;+\; \lambda \sum_{j=1}^{m} (\Delta t_j)^2 {tj,vj}1:m=arg{tj,vj}minj=1∑m−1∫tjtj+1 vj⋅g(p(t)) 2dt+λj=1∑m(Δtj)2
并满足
∑ j = 1 m Δ t j = T , p ( t j ) = v j . \sum_{j=1}^m \Delta t_j = T, \quad p(t_j) = v_j. j=1∑mΔtj=T,p(tj)=vj.
这里, Δ t j = t j + 1 − t j \Delta t_j = t_{j+1} - t_j Δtj=tj+1−tj表示第 (j) 段运动时间, l a m b d a \\lambda lambda 是平滑系数。如果轨迹跟表面走得“太平行”,就会被惩罚;而太频繁地加减速,也会被惩罚。
四、在线更新 NeRF,别让模型忘掉以前的地方
1. 滑动窗口思路
每次拍到新图像,我们都把它放进一个缓存 ( B ) 中。如果缓存超了,就丢掉最老的数据(或者做优先级筛选)。然后每来一张图,就利用它做一点梯度更新:
Θ n + 1 = Θ n − η ∇ Θ L ( I n , V n ; Θ n ) , \Theta_{n+1} =\Theta_n - \eta \nabla_\Theta \mathcal{L}\bigl(I_n, V_n; \Theta_n\bigr), Θn+1=Θn−η∇ΘL(In,Vn;Θn),
这里 Θ \Theta Θ 是 NeRF 参数, η \eta η 是学习率。
2. 避免遗忘
如果相机一直在某个局部区域晃悠,缓存里就全是这个局部的图像。久而久之,模型可能把其他区域的记忆“遗忘”了。
为此,我们引入一个重建置信度 C Ω ( x ) = exp ( − H ( σ F ( x ) ) ) C_\Omega(x) = \exp(-H(\sigma_F(x))) CΩ(x)=exp(−H(σF(x)))。如果熵大,置信度就低,表示当前点的重建不够好。相反,熵小就代表模型在那儿挺确定了。
那对每张图像,衡量一下它覆盖了多少“低置信度”区域,把这个结果当做采样权重:
w ( I i ) = 1 ∣ R ( V i ) ∣ ∑ r ∈ R ( V i ) ∫ n e a r f a r [ 1 − C Ω ( r ( t ) ) ] d t . w(I_i) =\frac{1}{|R(V_i)|} \sum_{r \in R(V_i)} \int_{near}^{far} \bigl[\,1 - C_\Omega(r(t))\bigr] \, dt. w(Ii)=∣R(Vi)∣1r∈R(Vi)∑∫nearfar[1−CΩ(r(t))]dt.
数值大的图,说明它拍到了更多不确定区域,也就更值得在训练中多出现。这样可以平衡:已经很熟悉的地方,别再重复占用太多训练迭代;而欠探索区域的图像要多参与训练。
另外,还可以周期性地复位缓存,回到历史所有数据,让模型整体都再刷一遍,防止完全遗忘老地方。
五、实验情况与一些发现
-
合成场景:在模拟环境里,我们控制无人机在一个大盒子里乱飞,比较不同策略:
- 随机飞;
- 固定速度向前飞;
- 贪心只看单步“下一视角增益”;
- 以及我们的“综合时空优化”策略;
结果显示,我们的方法在渲染质量和覆盖率上都显著更高。在相同的拍摄步数下,能覆盖更多有效区域,也重建得更精细。
-
真实场景:在一些公开的三维重建数据集(如 Tanks & Temples, ScanNet)上,也把已有图像视为“可能拍摄到的潜在位置”,再模拟我们的探索算法。我们的自动探索在大规模、复杂环境中更能显出优势,尤其是室内场景遮挡多,需要更聪明地选择角度。另外,我们的增量式训练在资源占用上还算可控,没有比传统离线训练方式高太多。
-
采样分布可视化:如果画一张俯视图,会看到随机或者固定路线的拍摄,分布要么太散,要么只在少数地方。而我们的策略在前期先快速扫一遍全局,然后在几何细节多的地方慢下来细拍。最终形成一条既兼顾覆盖,又兼顾细节的曲线。
六、还有哪些不足?
- 暂时只考虑静态场景:如果场景里有动态人物、非刚体形变等,就需要更复杂的动态 NeRF,定义不确定性也会更棘手;
- 没和语义任务结合:现在只考虑了几何信息增益,如果还想做目标检测 / 语义分割,就要把语义不确定性也加进来;
- 相机内参等因素:我们主要在优化“相机位姿”,没考虑镜头焦距、曝光等更多可调参数;
- 需要进一步的持续学习方法:虽然用了缓存和加权采样,但在超长时间的探索中,如何让模型一直保持对过去的记忆,还是一个难题。
七、总结
整体而言,让相机主动探索,在 NeRF 等隐式表示下做三维重建,能显著提升建模的速度和精度。这背后其实是一个很有潜力的研究方向:把主动视觉和神经场景表示结合起来,不再被动地“等数据”,而是“主动去找数据”。
如果未来和机器人、无人机技术紧密结合,那么在陌生环境中,机器人就能自己知道去哪儿拍、怎么拍,快速学到一份高保真的 3D 场景模型。对自动驾驶、VR/AR、环境监测等领域都大有帮助。
参考一些前沿成果:
- Mildenhall et al. “NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis”
- Barron et al. “Mip-NeRF”
- Müller et al. “Instant Neural Graphics Primitives”
非常期待这个方向能吸引更多研究和应用,也欢迎大家讨论和分享自己的想法!