让相机自己决定拍哪儿!——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”

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pytest-xdist 进行多进程并发测试

在自动化测试中,运行时间过长往往是令人头疼的问题。你是否遇到过执行 Pytest 测试用例时,整个测试流程缓慢得让人抓狂?别担心,pytest-xdist 正是解决这一问题的利器!它支持多进程并发执行,能够显著加快测试…

广度优先搜索(BFS)算法详解——以走迷宫问题为例

引言:当算法遇见迷宫 想象你置身于一个复杂的迷宫,如何在最短时间内找到出口?这个问题不仅存在于童话故事中,更是计算机科学中经典的路径搜索问题。本文将带你通过走迷宫问题,深入理解广度优先搜索(BFS&am…

kubeadm构建k8s源码阅读环境

目标 前面看了minikube的源码了解到其本质是调用了kubeadm来启动k8s集群,并没有达到最初看代码的目的。 所以继续看看kubeadm的代码,看看能否用来方便地构建源码调试环境。 k8s源码编译 kubeadm源码在k8s源码库中,所以要先克隆k8s源码。之…

BFS算法篇——广度优先搜索,探索未知的旅程(上)

文章目录 前言一、BFS的思路二、BFS的C语言实现1. 图的表示2. BFS的实现 三、代码解析四、输出结果五、总结 前言 广度优先搜索(BFS)是一种广泛应用于图论中的算法,常用于寻找最短路径、图的遍历等问题。与深度优先搜索(DFS&…

baigeiRSA

baigeiRSA 打开附件有两个: 1.import libnumfrom Crypto.Util import numberfrom secret import flag​size 128e 65537p number.getPrime(size)q number.getPrime(size)n p*q​m libnum.s2n(flag)c pow(m, e, n)​print(n %d % n)print(c %d % c)​​2.n…

脚本一键生成管理下游k8s集群的kubeconfig

一、场景 1.1 需要管理下游k8s集群的场景。 1.2 不希望使用默认的cluster-admin权限的config. 二、脚本 **重点参数: 2.1 配置变量。 1、有单独namespace的权限和集群只读权限。 2、自签名的CA证书位置要正确。 2.2 如果配置错误,需要重新…

camera光心检测算法

1.概要 光心检测算法,基于opencv c实现,便于模组厂快速集成到软件工具中,适用于camera模组厂算法评估组装制程镜头与sensor的偏心程度,便于工程师了解制程的问题找出改善方向。 2.技术介绍 下图为camera模组厂抓取的bayer-raw经过…

基于logback+fastjson实现日志脱敏

一、需求背景 日常工作中,必不可免的会将一些敏感信息,如用户名、密码、手机号、身份证号、银行账号等等打印出来,但往往为了安全,这些信息都需要进行脱敏。脱敏实际就是用一些特殊字符来替换部分值。 JSON 和 JSONObject Fastj…

RC5分组加密算法

目录 (1)RC5密钥扩展算法 (2)RC5加密算法 (3)RC5解密算法 RC5分组加密算法 RC5分组密码算法是1994年RSA实验室的RonaldL.Rivest教授发明的。它是参数可变的分组密码算法,三个可变的参数是&a…

GPU — 8 卡 GPU 服务器与 NVLink/NVSwitch 互联技术

目录 文章目录 目录8 卡 GPU 服务器GPU 互联技术分类PCIe 直连PCIe Switch 互联NVLink 互联NVLink 1.0 与 DGX-1 系统NVLink 2.0 与 DGX-1 系统NVSwitch 全互联NVSwitch 1.0 与 DGX-2 系统NVLink 3.0、NVSwitch 2.0 与 DGX A100NVLink 4.0、NVSwitch 3.0 与 DGX H100NVSwitch v…

idea——IDEA2024版本创建Sping项目无法选择Java 8

目录 一、背景二、解决方式(替换创建项目的源地址) 一、背景 IDEA2024创建一个springboot的项目,本地安装的是1.8,但是在使用Spring Initializr创建项目时,发现版本只有17、21、23。 二、解决方式(替换创…

STM32 串口发送与接收

接线图 代码配置 根据上一章发送的代码配置,在GPIO配置的基础上需要再配置PA10引脚做RX接收,引脚模式可以选择浮空输入或者上拉输入,在USART配置串口模式里加上RX模式。 配置中断 //配置中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE…

储能系统-系统架构

已更新系列文章包括104、61850、modbus 、单片机等,欢迎关注 IEC61850实现方案和测试-1-CSDN博客 快速了解104协议-CSDN博客 104调试工具2_104协议调试工具-CSDN博客 1 电池储能系统(BESS) 架构 电池储能系统主要包括、电池、pcs、本地控制…

TOTP实现Google Authenticator认证工具获取6位验证码

登录遇到Google认证怎么办? TOTP是什么?(Google Authenticator) TOTP(Time-based One-Time Password)是一种基于时间的一次性密码算法,主要用于双因素身份验证。其核心原理是通过共享密钥和时间同步生成动态密码,具体步骤如下: 共享密钥:服务端与客户端预先共享一个…

清理服务器/docker容器

清理服务器 服务器或docker容器清理空间。 清理conda环境 删除不用的conda虚拟环境: conda env remove --name python38 conda env remove --name python310清理临时目录:/tmp du -sh /tmp # 查看/tmp目录的大小/tmp 目录下的文件通常是可以直接删除…

Naive UI去掉n-select下拉框边框,去掉n-input输入框边框

<template><div><div style"margin-top:10px;width: 100%;"><dade-descriptions><tr><dade-descriptions-item label"代理名称"><dade-input placeholder"代理名称"></dade-input></dade-de…

【完整版】DeepSeek-R1大模型学习笔记(架构、训练、Infra)

文章目录 0 DeepSeek系列总览1 模型架构设计基本参数专家混合模型&#xff08;MoE&#xff09;[DeepSeek-V2提出, DeepSeek-V3改良]多头潜在注意力&#xff08;MLA&#xff09;[DeepSeek-V2提出]多token预测&#xff08;MTP&#xff09;[DeepSeek-V3提出] 2 DeepSeek-R1-Zero及…

如何使用 Python 和 SQLAlchemy 结合外键映射来获取其他表中的数据

在使用 Python 和 SQLAlchemy 时&#xff0c;结合外键映射可以让你在查询时轻松地获取其他表中的数据。SQLAlchemy 提供了丰富的 ORM&#xff08;对象关系映射&#xff09;功能&#xff0c;可以让你通过定义外键关系来查询并获取关联的数据。下面我会演示如何设置外键关系&…

Python爬虫:1药城店铺爬虫(完整代码)

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ &#x1f434;作者&#xff1a;秋无之地 &#x1f434;简介&#xff1a;CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作&#xff0c;主要擅长领域有&#xff1a;爬虫、后端、大数据…

游戏引擎学习第91天

黑板&#xff1a;澄清线性独立性 首先&#xff0c;提到线性独立时&#xff0c;之前讲解过的“最小”的概念实际上是在表达线性独立。对于二维坐标系来说&#xff0c;两个基向量是最小的&#xff0c;这两个向量是线性独立的。如果超过两个基向量&#xff0c;就会变得冗余&#…