让相机自己决定拍哪儿!——NeRF 三维重建的主动探索之路

我在 NeRF 中折腾自动探索式三维重建的心得

写在前面:
最近我在研究三维重建方向,深切感受到 NeRF (Neural Radiance Fields) 在学术界和工业界都备受瞩目。以往三维重建通常要依赖繁琐的多视图几何管线(比如特征匹配、深度估计、网格融合等),或者需要依靠激光雷达 / RGB-D 传感器才能得到可观的三维数据。

但 NeRF 出现后,给三维重建带来了革命性的思路:它直接用一个多层感知机(MLP)来隐式建模场景位置和方向与颜色、密度的映射关系,再配合可微分的体渲染公式,就能端到端地重建出精准且逼真的场景。

然而,NeRF 往往默认已经有一批“采集好”的图像,训练时并不考虑如何采集这些图像。一旦缺乏足够且有效的多视图信息,NeRF 也很难重建出理想效果。

所以在本文里,我想分享的核心想法是:如果我们能主动控制相机的运动轨迹,怎样才能高效、全面地探索场景,从而让 NeRF 重建的质量更优?


用 NeRF 做三维重建时,如何自动选择拍摄视角?——我的探索尝试

为什么要关心相机视角?
大家可能都知道,NeRF(Neural Radiance Fields) 这种用神经网络来做三维重建的方法很火,它能在一批图像的驱动下,隐式地学习场景的几何和外观,然后渲染出各种新视角图像。但问题是,如果拍摄视角不够好,或者数据采集做得比较随意,就算再强大的 NeRF 也很难得到完整、清晰的重建。

所以我就想:既然相机可以移动,那能不能自动规划相机的运动,让它去“看”最需要看的地方?这样既能节省拍摄成本,也能让 NeRF 获得更准确的三维模型。于是,就折腾出了下面这套“自动探索式”三维重建方法的思路。


一、总体想法

1. 大方向

  1. 一开始,用少量随机拍摄到的图像先训练出一个初步的 NeRF;
  2. 然后让相机(例如无人机或者机器人上的摄像头)自动探索
    • 根据当前 NeRF 的“模型不确定性”评估哪些位置、哪个角度拍摄更有价值;
    • 规划相机的运动路径,让它飞过去拍摄;
    • 将新获得的图像再增量更新到 NeRF 中;
  3. 如此循环,直到我们的 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(VF)=rR(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(1p)log(1p) 是二值分布的熵。当 p ≈ 0.5 p \approx 0.5 p0.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(ViF)=i1rR(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

  1. 这里的 d d d 表示沿光线从近端 n e a r near near 到远端 f a r far far深度 (或者距离)。
  2. σ 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=1m1tjtj+1 vjg (p(t)) 2dt+λj=1m(Δ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=1mΔtj=T,p(tj)=vj.

这里, Δ t j = t j + 1 − t j \Delta t_j = t_{j+1} - t_j Δtj=tj+1tj表示第 (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)1rR(Vi)nearfar[1CΩ(r(t))]dt.

数值大的图,说明它拍到了更多不确定区域,也就更值得在训练中多出现。这样可以平衡:已经很熟悉的地方,别再重复占用太多训练迭代;而欠探索区域的图像要多参与训练。
另外,还可以周期性地复位缓存,回到历史所有数据,让模型整体都再刷一遍,防止完全遗忘老地方。


五、实验情况与一些发现

  1. 合成场景:在模拟环境里,我们控制无人机在一个大盒子里乱飞,比较不同策略:

    • 随机飞;
    • 固定速度向前飞;
    • 贪心只看单步“下一视角增益”;
    • 以及我们的“综合时空优化”策略;
      结果显示,我们的方法在渲染质量和覆盖率上都显著更高。在相同的拍摄步数下,能覆盖更多有效区域,也重建得更精细。
  2. 真实场景:在一些公开的三维重建数据集(如 Tanks & Temples, ScanNet)上,也把已有图像视为“可能拍摄到的潜在位置”,再模拟我们的探索算法。我们的自动探索在大规模、复杂环境中更能显出优势,尤其是室内场景遮挡多,需要更聪明地选择角度。另外,我们的增量式训练在资源占用上还算可控,没有比传统离线训练方式高太多。

  3. 采样分布可视化:如果画一张俯视图,会看到随机或者固定路线的拍摄,分布要么太散,要么只在少数地方。而我们的策略在前期先快速扫一遍全局,然后在几何细节多的地方慢下来细拍。最终形成一条既兼顾覆盖,又兼顾细节的曲线。


六、还有哪些不足?

  • 暂时只考虑静态场景:如果场景里有动态人物、非刚体形变等,就需要更复杂的动态 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”

非常期待这个方向能吸引更多研究和应用,也欢迎大家讨论和分享自己的想法!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/894826.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

央行发布《贸易金融分布式账本技术要求》,参考架构包括5部分

《银行科技研究社》(作者 木子剑):2024年12月11日,中国人民银行发布金融行业标准《贸易金融分布式账本技术要求》(JR/T 0308-2024)(以下简称“《要求》”),当日实施。据悉,该文件的起草单位包括6大行和多家股份制银行等。 《要求》规定了分布式账本技术在贸易金融领域…

管理etcd的存储空间配额

如何管理etcd的存储空间配额 - 防止集群存储耗尽指南 本文基于etcd v3.4官方文档编写 为什么需要空间配额? 在分布式系统中,etcd作为可靠的键值存储,很容易成为系统瓶颈。当遇到以下情况时: 应用程序频繁写入大量数据未及时清理…

调用腾讯云批量文本翻译API翻译srt字幕

上一篇文章介绍了调用百度翻译API翻译日文srt字幕的方法。百度翻译API是get方式调用,参数都放在ur中,每次调用翻译文本长度除了接口限制外,还有url长度限制,而日文字符通过ur转码后会占9个字符长度,其实从这个角度来讲…

Python aiortc API

本研究的主要目的是基于Python aiortc api实现抓取本地设备媒体流(摄像机、麦克风)并与Web端实现P2P通话。本文章仅仅描述实现思路,索要源码请私信我。 1 demo-server解耦 1.1 原始代码解析 1.1.1 http服务器端 import argparse import …

记录 | WPF基础学习Style局部和全局调用

目录 前言一、Style1.1 例子1.2 为样式起名字1.3 BasedOn 继承上一个样式 二、外部StyleStep1 创建资源字典BaseButtonStyle.xamlStep2 在资源字典中写入StyleStep3 App.xaml中写引用路径【全局】Step4 调用三、代码提供四、x:Key和x:Name区别 更新时间 前言 参考文章&#xff…

如果$nextTick内部抛出错误,如何处理?

如果 $nextTick 内部抛出错误,可以通过在回调函数中使用 try…catch 语句来捕获和处理这些错误。由于 $nextTick 是异步执行的,因此错误不会直接影响到 Vue 的运行,但捕获错误可以帮助你进行更好的错误处理和调试。 一、使用 try…catch 以下是如何在 $nextTick 中捕获错误…

吴恩达深度学习——卷积神经网络实例分析

内容来自https://www.bilibili.com/video/BV1FT4y1E74V,仅为本人学习所用。 文章目录 LeNet-5AlexNetVGG-16ResNets残差块 1*1卷积 LeNet-5 输入层:输入为一张尺寸是 32 32 1 32321 32321的图像,其中 32 32 3232 3232是图像的长和宽&…

Spring Boot 自动装配原理与优化实践

在 Java 开发领域,Spring Boot 以其 “约定优于配置” 的理念,极大地简化了 Spring 应用的开发和部署过程,成为了众多开发者的首选框架。它通过自动装配机制,让开发者能够快速搭建一个功能完备的应用,而无需进行繁琐的…

【Uniapp-Vue3】z-paging插件组件实现触底和下拉加载数据

一、下载z-paing插件 注意下载下载量最多的这个 进入Hbuilder以后点击“确定” 插件的官方文档地址: https://z-paging.zxlee.cn 二、z-paging插件的使用 在文档中向下滑动,会有使用方法。 使用z-paging标签将所有的内容包起来 配置标签中的属性 在s…

【B站保姆级视频教程:Jetson配置YOLOv11环境(七)Ultralytics YOLOv11配置】

Jetson配置YOLOv11环境(7)Ultralytics YOLOv11环境配置 文章目录 1. 下载YOLOv11 github项目2. 安装ultralytics包3. 验证ultralytics安装3.1 下载yolo11n.pt权重文件3.2 推理 1. 下载YOLOv11 github项目 创建一个目录,用于存放YOLOv11的项目…

第二天:系统从BIOS/UEFI到GRUB/bootloader的启动过程

目录 **一、BIOS/UEFI初始化阶段****二、引导加载程序(GRUB)的启动过程****1. BIOS模式下的GRUB分阶段加载****2. UEFI模式下的GRUB加载** **三、操作系统内核加载与初始化****四、关键组件与配置文件****五、故障排查与恢复****总结**常见问题如何在UEF…

es官方go客户端创建ik索引并进行查询操作

es-go client引入gomod go get github.com/elastic/go-elasticsearch/v8latest连接es服务器(不经过安全校验) cfg : elasticsearch.Config{Addresses: []string{"http://localhost:9200",}, } es, err : elasticsearch.NewClient(cfg) if err ! nil {pa…

【容器技术01】使用 busybox 构建 Mini Linux FS

使用 busybox 构建 Mini Linux FS 构建目标 在 Linux 文件系统下构建一个 Mini 的文件系统,构建目标如下: minilinux ├── bin │ ├── ls │ ├── top │ ├── ps │ ├── sh │ └── … ├── dev ├── etc │ ├── g…

【C语言系列】深入理解指针(5)

深入理解指针(5) 一、sizeof和strlen的对比1.1sizeof1.2strlen1.3sizeof和strlen的对比 二、数组和指针笔试题解析2.1 一维数组2.2 字符数组2.2.1代码1:2.2.2代码2:2.2.3代码3:2.2.4代码4:2.2.5代码5&#…

标志的推理

下面的讨论是我对《对编程实现拟人智能可行性的论证》这篇文章的“赋值与对象的标志”这一节的展开讨论。 标志能够使我们更好的思维(比如用轮廓标记物体对象,用兴奋强度标记回忆情况等等)。有思维标志、信息标志,单纯标志、组合…

【蓝桥杯嵌入式】2_LED

1、电路图 74HC573是八位锁存器,当控制端LE脚为高电平时,芯片“导通”,LE为低电平时芯片“截止”即将输出状态“锁存”,led此时不会改变状态,所以可通过led对应的八个引脚的电平来控制led的状态,原理图分析…

Diskgenius系统迁移之后无法使用USB启动

前言 本文用于记录系统迁移中遇到的问题及解决方法,如有不对请指出,谢谢! 现象 使用DiskGenius进行系统迁移后,使用USB启动失败,反复在品牌logo和黑屏之间切换,期间还会在左上角显示”reset system“报错…

使用 Postman 进行 API 测试:从入门到精通

使用 Postman 进行 API 测试:从入门到精通 使用 Postman 进行 API 测试:从入门到精通一、什么是 API 测试?二、Postman 简介三、环境搭建四、API 测试流程1. 收集 API 文档2. 发送基本请求示例:发送 GET 请求示例代码(…

Android Studio:Application 和 Activity的区别

Application 和 Activity 是 Android 中非常重要的两个组件,它们分别负责不同的生命周期管理和应用的不同层次的操作。 Application 是应用级别的生命周期管理,它在整个应用运行时只有一个实例,负责应用的全局初始化和资源管理。Activity 是…

Mac本地体验LM studio

博主很懒,不爱打字! 1、LM studio官网:LM Studio - Discover, download, and run local LLMs 2、下载DMG文件,安装 3、使用vscode工具,commandshiftH【全局替换功能】,选择目录/Applications/LM\ Studio…