全部文章 笔记与思考

SfM 原理详解:从多张照片恢复三维结构

从特征匹配、对极几何、三角化、PnP 到 Bundle Adjustment,系统理解 SfM 如何把无序图像变成相机轨迹和稀疏点云。

SfM 原理详解:从多张照片恢复三维结构

SfM(Structure from Motion,运动恢复结构)解决的问题很朴素:只给一组从不同位置拍摄的照片,能不能同时恢复相机的运动轨迹和场景的三维结构?
答案是可以,但它靠的不是“AI 猜形状”,而是一整套严密的多视图几何。


目录


一、SfM 到底在求什么

把 SfM 拆开看:

  • Structure:场景里的三维点在哪里;
  • Motion:相机拍每张照片时在哪里、朝向哪里。

输入通常是一组有重叠视野的图片,输出则是相机参数和稀疏点云。

项目 SfM 中的含义 典型结果
输入图像 同一场景的多视角照片,可以有序也可以无序 JPG / PNG
相机内参 焦距、主点、畸变等相机自身参数 $K, d$
相机外参 每张图像对应的位姿 $R, t$
三维结构 被多张图共同观测到的空间点 sparse point cloud
观测轨迹 哪些 2D 特征点来自同一个 3D 点 tracks

最核心的一句话是:SfM 通过同名点约束,把“二维像素坐标”反推出“三维点 + 相机位姿”。


二、整体流程

SfM 整体流水线:从图像输入到稀疏重建

一条典型的 SfM 流水线可以拆成 6 步:

  1. 特征提取:在每张图里找稳定的局部特征点,例如角点、纹理块、边缘交汇处。
  2. 特征匹配:在不同图片之间找“看起来像同一个三维点”的 2D 特征。
  3. 两视图几何估计:用匹配点估计基础矩阵 $F$ 或本质矩阵 $E$,过滤错误匹配。
  4. 初始化重建:选择一对质量好的图片,估计相对位姿并三角化出第一批 3D 点。
  5. 增量注册相机:不断把新图片加入已有重建,用 PnP 求位姿,再三角化新点。
  6. Bundle Adjustment:把所有相机和三维点一起优化,最小化重投影误差。

这条流水线有一个重要特点:SfM 先追求几何一致性,而不是追求稠密表面。 因此它输出的点云通常是稀疏的,但相机位姿很有价值。


三、特征与匹配

特征匹配:在不同照片中找同一个三维点的投影

SfM 的第一步不是直接估计三维,而是先回答一个更基础的问题:照片 A 里的这个点,和照片 B 里的哪个点是同一个真实空间点?

这通常靠局部特征完成。一个特征点包含两部分:

  • 关键点位置:它在图像中的 $(u, v)$ 像素坐标;
  • 描述子:一段向量,用来描述它周围局部纹理的样子。

常见特征包括 SIFT、SURF、ORB、AKAZE 等。经典 SfM 系统很喜欢 SIFT,因为它对尺度、旋转、光照变化相对稳定;实时或移动端系统则常用 ORB 这类更快的二进制特征。

匹配时最直观的方法是:对图像 A 的每个描述子,在图像 B 中找距离最近的描述子。但这会产生很多误匹配,所以还需要过滤:

过滤策略 作用
最近邻比值测试 如果第一近和第二近太接近,说明匹配不可靠
双向一致性检查 A 匹配到 B,B 也必须匹配回 A
RANSAC 用几何模型反复抽样,剔除不满足对极约束的离群点

如果匹配阶段错得太多,后面的几何估计会全部崩掉。所以很多 SfM 工程问题,本质上都是“匹配图不够好”的问题。


四、对极几何

对极几何:一个点在另一张图中只能落在对应的对极线上

有了两张图片之间的匹配点后,SfM 会估计它们之间的相对几何关系。这里最核心的是对极约束:

$$ x_2^\top F x_1 = 0 $$

其中 $x_1$ 和 $x_2$ 是同一个三维点在两张图中的齐次像素坐标,$F$ 是基础矩阵。

这条公式表达了一个强约束:
给定图 1 中的点 $x_1$,它在图 2 中的对应点 $x_2$ 不可能出现在任意位置,而必须落在一条对极线上。

如果相机内参 $K$ 已知,可以进一步使用本质矩阵:

$$ E = K_2^\top F K_1 $$

本质矩阵可以分解出两台相机之间的相对旋转 $R$ 和平移方向 $t$。注意这里说的是平移方向,不是绝对距离,因为纯视觉 SfM 天生存在尺度不确定性。

在真实数据里,匹配点必然有噪声和误匹配。因此实际估计 $F$ 或 $E$ 时,通常会配合 RANSAC:

  1. 随机抽一小组匹配点;
  2. 估计一个候选 $F$ 或 $E$;
  3. 统计有多少匹配点满足对极约束;
  4. 重复多次,选择内点最多的模型。

这一步的意义很大:它把“看起来像”的特征匹配,变成了“几何上说得通”的匹配。


五、三角化

三角化:两条视线在空间中交会,恢复三维点

当两台相机的相对位姿已知,并且知道同一个点在两张图中的像素位置,就可以把两条观测射线反投影到三维空间。理想情况下,两条射线会在真实三维点处相交。

但真实世界不理想:

  • 像素定位有误差;
  • 镜头畸变不可能完全校正;
  • 特征匹配可能有轻微偏移;
  • 两条射线往往不会精确相交。

所以三角化通常求的是一个最小二乘意义下的三维点,使它投影回各个相机后的误差尽量小。

用投影矩阵 $P_i$ 表示第 $i$ 个相机,用三维点 $X$ 表示空间点,观测像素为 $x_i$,重投影关系可以写成:

$$ x_i \sim P_i X $$

三角化后还要做几个检查:

  • 正深度检查:点必须在相机前方,不能跑到相机背后;
  • 重投影误差检查:投影回图像后不能偏离观测点太远;
  • 视差检查:两张图视角太接近时,三角化会非常不稳定。

这也是为什么拍摄 SfM 数据时,不能只原地转圈拍。原地旋转能估计相机朝向,但几乎没有平移基线,很难稳定恢复深度。


六、增量式重建

增量式 SfM:初始化一对图像,然后反复注册新相机、三角化新点、BA 优化

工程上最常见的是增量式 SfM。它不是一次性把所有照片全部解出来,而是先找一对靠谱的种子图像,再逐步扩张。

典型循环如下:

阶段 做什么 判断好坏的关键
选择种子对 找匹配多、视差足、内点比例高的两张图 baseline 不能太小
初始化 分解 $E$ 得到相对位姿,三角化第一批点 正深度点足够多
注册新图像 用已知 3D 点和新图 2D 特征做 PnP 2D-3D 对应足够多
三角化新点 新相机加入后,与旧相机共同生成更多 3D 点 视差和误差合格
局部 BA 优化最近加入的相机和相关点 快速修正局部漂移
全局 BA 间隔性优化所有相机和点 抑制累计误差

其中 PnP(Perspective-n-Point)解决的是这个问题:

已知若干个 3D 点 $X_j$,以及它们在当前图片中的 2D 投影 $x_j$,求这张图片对应的相机位姿 $R, t$。

PnP 是增量式 SfM 能“接上新照片”的关键。只要一张新图能和已有点云建立足够多的 2D-3D 对应,就可以估计它的相机位姿,再继续扩展重建。


七、Bundle Adjustment

Bundle Adjustment:同时优化相机位姿和三维点,让重投影误差最小

前面的步骤会不断累积误差:匹配有误差、相机位姿有误差、三角化有误差。Bundle Adjustment(BA)就是 SfM 的全局校准器。

它的目标是最小化所有观测的重投影误差:

$$ \min_{{P_i}, {X_j}} \sum_{i,j} \rho \left(\left|x_{ij} - \pi(P_i, X_j)\right|^2\right) $$

其中:

  • $P_i$:第 $i$ 个相机的参数,包括位姿,也可能包括内参;
  • $X_j$:第 $j$ 个三维点;
  • $x_{ij}$:第 $j$ 个点在第 $i$ 张图中的实际观测;
  • $\pi(P_i, X_j)$:把三维点投影到第 $i$ 张图的预测位置;
  • $\rho$:鲁棒损失函数,用来减小离群点影响。

BA 的直觉很简单:
如果某个三维点和相机位姿是对的,那么这个点投影回所有观测过它的照片时,都应该落回原来的特征点附近。

BA 很耗时,因为变量很多:几百张图、几十万个点、上百万条观测都很常见。但它的稀疏结构非常强:一个观测只连接一个相机和一个三维点。因此实际系统会利用稀疏矩阵和 Schur Complement 来加速求解。

没有 BA 的 SfM 往往会出现“局部看起来对,整体慢慢弯掉”的问题;有 BA 后,整个重建会被全局观测一起拉回更一致的位置。


八、尺度、失败场景与下游任务

SfM 的输出:相机位姿和稀疏点云,通常作为 MVS、NeRF、3DGS 的输入

8.1 尺度不确定性

单目 SfM 最大的限制是没有绝对尺度。如果所有相机平移和所有三维点坐标同时放大 10 倍,投影到图像上的像素位置不会变。

因此 SfM 输出的模型只能确定“相对形状”。要恢复真实尺度,需要额外信息,例如:

  • 已知相机间基线;
  • 标定板或已知尺寸物体;
  • GPS / IMU;
  • 深度传感器;
  • 人工指定两点距离。

8.2 常见失败场景

场景 为什么难 典型表现
纹理少 找不到稳定特征 白墙、玻璃、纯色物体重建失败
重复纹理 匹配容易混淆 楼宇窗格、栅栏、瓷砖产生错误结构
动态物体多 几何假设被破坏 行人、车辆形成漂浮点
视角变化太大 特征外观差异大 匹配数量不足
基线太小 深度三角化不稳定 点云很扁、深度噪声大
纯旋转拍摄 没有平移视差 能拼全景,但难恢复三维

8.3 和 MVS、NeRF、3DGS 的关系

SfM 不是完整的三维重建终点,更像是几何地基:

  • MVS(Multi-View Stereo):用 SfM 的相机位姿进一步估计稠密深度图、网格和纹理;
  • NeRF:通常需要 SfM 提供训练图像对应的相机位姿;
  • 3DGS:常用 SfM 输出的稀疏点云初始化高斯位置;
  • 视觉 SLAM:和 SfM 共享很多几何模块,但更强调实时性和在线定位。

所以当你看到 COLMAP 生成的 sparse reconstruction 时,不要误以为“只重建出这么几个点”。它真正值钱的是:这些点和相机位姿已经形成了一个几何一致的坐标系。


九、总结

SfM 的主线可以压缩成一句话:

先用特征匹配建立跨图像对应关系,再用对极几何估计相机关系,用三角化恢复三维点,最后通过 BA 同时优化所有相机和点。

更工程化地看,它是一套不断回答下面三个问题的系统:

  1. 哪些像素来自同一个三维点?
    靠特征匹配、track 构建和 RANSAC 过滤。

  2. 每张照片拍摄时相机在哪里?
    靠两视图几何初始化,靠 PnP 增量注册新相机。

  3. 三维点到底在哪里最合理?
    靠三角化生成初值,靠 Bundle Adjustment 全局修正。

理解了 SfM,再看 COLMAP、MVS、NeRF、3DGS 这些系统时,很多流程都会突然清晰起来:它们并不是孤立的技术,而是建立在同一套多视图几何地基之上。