Part III · 第 11 章 多视图几何 · 11.6

光束法平差 (Bundle Adjustment)

三角化在相机已知时求点,PnP 在点已知时求相机,可现实里两者都不知道。光束法平差把所有相机位姿和所有三维点放在一起,最小化全部观测的重投影误差:这是多视图几何的“金标准”,也是每个 SfM 和视觉 SLAM 系统精度的来源。它就是 6.9 节非线性最小二乘最大的一个应用:真正有意思的是它的稀疏结构、7 维规范自由度和对外点的处理。

约 35 分钟 前置:6.9 非线性最小二乘 · 6.10 流形优化 · 11.3 三角化 · 11.4 PnP · 11.5 RANSAC 与鲁棒损失 5 个交互

    1为什么机器人需要它

    用一台相机在房间里走一圈,再用 11.5 节的特征匹配找出各帧之间的对应点。现在你想同时知道两件事:相机每一帧在哪里(位姿),以及这些特征点在三维里的哪里(结构)。已有的工具各解决一半:三角化在相机位姿已知时算出点,PnP在点已知时算出相机。真实的建图两者都未知,只能自举:先用对极几何(11.1)和三角化得到一点粗糙的结构,再用 PnP 把新的一帧接进来,再三角化新的点……每一步都带着一点误差,误差会一层层叠上去,地图越走越歪。

    光束法平差(Bundle Adjustment,BA)的想法是:别再“固定一边、求另一边”。把所有相机位姿和所有三维点都当未知数,让每个三维点投影到每个看到它的相机上的像素,同时尽量贴近实际测得的像素,即最小化总的重投影误差。名字来自“光束”:从每个三维点射向各相机中心的光线束,要一起调整到同时穿过各自观测到的像素。在高斯像素噪声下(4.6 节),它就是最大似然估计,所以被称为多视图几何的“金标准”。

    COLMAP 和 ORB-SLAM 的地图之所以准,靠的就是它;NeRF 与 3D 高斯泼溅训练前需要的相机位姿,也几乎都来自它(12.4 节)。从算法上看,BA 没有新东西:它就是 6.9 节的非线性最小二乘,残差是重投影误差,用 Levenberg-Marquardt 求解。本节不重讲那套理论,只讲 BA 特有的几件事:残差与雅可比具体长什么样,为什么有 7 个多余的自由度,怎样利用稀疏结构(Schur 补)把规模推到百万个点,怎样抵御误匹配,以及解有多可靠。

    2直觉:每条观测是一根橡皮筋

    想象下面的场景:5 台相机排成一道弧,看着 30 个空间点。每台相机看到的点会在它的图像上形成一个像素,这是观测(紫色)。如果你对相机位姿和点位置的猜测是错的,把猜测的点投影回这台相机,就落在另一个像素上,这是重投影(琥珀色)。两者之间的向量就是残差\(\hl{res}{\mathbf r_{ij}}\)(红线),可以想成一根橡皮筋;总代价 \(F\) 是所有橡皮筋的弹性势能。

    未知数是 5 台相机的位姿(每台 6 个自由度)和 30 个点(每个 3 个坐标),共 120 个;观测有 111 条,每条给出两个方程(\(u\) 和 \(v\)),共 222 个。方程比未知数多,所以通常不存在一组解让所有橡皮筋同时松弛,但存在一组最好的折中:BA 就是去找它。下图让你自己把猜测弄坏,看橡皮筋怎样绷紧。

    FIG 1代价:把猜测弄坏,橡皮筋就绷紧
    上:三维视图(z 向上),紫色是真值(相机锥体和点),琥珀色是当前猜测,青线连接同一个点的猜测与真值。下:相机 1、3、5 的图像(像素坐标,v 本来向下,这里画成 −v 使图像是正的):紫点为观测,琥珀点为重投影,红线是残差。最右是代价 \(\log F\) 沿“真值 → 猜测”这条直线的切片,橙点是当前位置,紫点是真值(噪声使它的代价不为零)。滑块越右,猜测越差;真值附近的代价曲线像一个碗,远处很快变陡。观测带 σ = 0.5 px 的噪声。
    试一试
    • 把扰动水平拉到 1 以上:残差是几十个像素,\(F\) 比真值处大几个数量级。
    • 分别选“只扰动相机”和“只扰动点”(水平 ≥ 0.5):只动相机时,同一台相机里所有残差朝着相近方向;只动点时,残差各指各的。
    核心洞见

    BA 的残差只是“预测像素减观测像素”。一个未知数(比如某个点)只出现在看到它的那几条橡皮筋里,一台相机只出现在它自己看到的点的橡皮筋里。这个“谁牵着谁”的结构,决定了 BA 的一切:矩阵为什么是稀疏的、能被 Schur 补加速、规范自由度为什么存在。

    3动手:真的跑一遍 LM

    下面的图运行的就是真正的算法,没有预先算好的动画。每一步:(1) 在当前估计处线性化所有残差,得到每条观测的 \(2\times6\) 相机雅可比块和 \(2\times3\) 点雅可比块(解析公式见第 5 节,页面里还用有限差分验证过);(2) 解阻尼正规方程 \((J^\top J+\lambda D)\boldsymbol\delta=-J^\top\mathbf r\);(3) 相机位姿用 \(T\leftarrow\Exp(\boldsymbol\delta_i)T\) 更新(6.10 节:在 \(\SE\) 上用指数映射而不是加法),点直接相加;(4) 代价下降就接受并把 \(\lambda\) 缩小为三分之一,否则拒绝并把 \(\lambda\) 乘 4(6.6、6.9 节的 LM)。

    有两处新东西。第一,规范:只有图像像素没有绝对坐标,把整个场景刚体移动、再整体放大缩小,所有重投影都不变,所以有 \(6+1=7\) 个方向代价不变。要得到唯一解必须“固定规范”:这里冻结相机 1 的位姿(6 个量),并固定相机 1、2 之间的基线长度(1 个量:实现上是冻结基线方向上的一个平移分量,每步后再把基线长度归一化,这是对代价严格不变的相似变换)。切到“不固定”看会发生什么,并打开 \(J^\top J\) 的谱。第二,线性求解器:“稠密”把全部 \(6c+3p\) 个未知数一起解,“Schur 补”先消去点(第 4 节),两者给出同一个步长。

    FIG 2光束法平差:LM 逐步收敛
    左:琥珀色是当前估计,紫色是真值。因为规范不唯一,估计要先做最佳相似变换(Umeyama 对齐)才能和真值叠在一起比较;“结构误差”也是对齐之后的点位置均方根误差(单位 m,场景约 3 m 宽)。右:相机 3 的图像与残差,下面是代价的对数曲线(绿虚线是噪声水平 \(\tfrac12\sigma^2(2m-n)\),\(n\) 为扣除 7 个规范方向后的未知数个数)或 \(J^\top J\) 的特征值。读数里“规范漂移”给出相机 1 相对初始位置移动了多少、基线长度变了几倍;“稠密 / Schur”给出两种求解器的乘加次数、耗时和两者步长的最大差。
    • 保持默认设置按“运行”:不到 10 步收敛,RMS 降到噪声水平(约 0.5 px)。
    • 选“Gauss-Newton (λ = 0)”,规范固定,运行:几步(5 到 7 步)就收敛,因为初值已在盆地里(有噪声时是快速的线性收敛,只有噪声为 0 时才是二次收敛)。
    • 把规范改成“不固定”,仍用 Gauss-Newton,按“单步”:\(J^\top J\) 奇异,Cholesky 直接失败。
    • 规范“不固定”并用 LM 运行到收敛:代价照样降到最低,但相机 1 跑掉了,基线长度也变了:解沿 7 维“平坦谷”随便落在了哪里。
    • 规范“不固定”,图选“JᵀJ 的谱”:恰有 7 个特征值是数值零(图里红色);切到“固定 7 维”,它们消失。
    • 线性求解选“Schur 补”并按“单步”:读数里 max|δ稠密 − δSchur| 在 1e-9 以下,Schur 的乘加次数少了约一个数量级。
    有意思的细节

    (1) 有噪声时,收敛处的代价(约 14)低于真值处的代价(约 26):优化器拟合了噪声,最优解并不等于真值,这是“估计”而不是“还原”。 (2) 噪声调为 0 时,代价在 7 步内降到 \(10^{-13}\) 以下(程序在此停下),结构误差只有 \(10^{-10}\) m 量级,说明解析雅可比和更新规则确实是对的。 (3) “固定”规范只是在 7 维平坦谷里钉一个点,所以它对尺度的选择完全是任意的:对真值的尺度读数偏离 1 多少,就是你初始基线定得多不准。

    4另外两个视角:稀疏结构与外点

    稀疏:箭头形的 H 与 Schur 补

    FIG 2 的 120 个未知数还好,真实的 SfM 有几千台相机、几百万个点,未知数上千万,稠密矩阵连存都存不下。但 BA 的雅可比极其稀疏:每个观测(\(J\) 的一个 \(2\times n\) 行块)只牵涉一台相机的 6 列和一个点的 3 列,其余全是零。于是正规方程矩阵 \(H=J^\top J\) 有固定的“箭头”形状:

    $$ H=\begin{bmatrix} B & E\\ E^\top & C\end{bmatrix},\quad B=\operatorname{blkdiag}_i(B_i)\ (6\times6),\quad C=\operatorname{blkdiag}_j(C_j)\ (3\times3),\quad E_{ij}\neq 0\iff \text{camera } i \text{ sees point } j $$

    注意 \(C\) 是块对角的:两个不同的点从不出现在同一条观测里,彼此不直接耦合。所以消去全部点只需要对 \(p\) 个 \(3\times3\) 的小矩阵求逆(每个约 30 次运算),再解一个只含相机的 \(6c\times6c\) 小方程组:这就是 Schur 补(第 5 节推导)。下面把它的规模摆出来比较。矩阵按“相机在前、点在后”排列,虚线框是 Schur 补 \(\hl{schur}{S}\) 所在的相机块;相机很多时,一个点被多台相机共同看到,才会让这些相机之间的块 \(S_{ik}\) 非零,轨迹越长,\(S\) 越接近带状。

    FIG 3稀疏结构:J 的非零图案、箭头形 H 与 Schur 补的代价
    左:雅可比 \(J\) 的非零图案,行是观测(每个代表 2 行像素),列先是 \(c\) 个 6 列的相机块,再是 \(p\) 个 3 列的点块。每一行恰好 1 + 1 个块非零。右:\(H=J^\top J\) 的块图案,蓝是相机块 \(B\)(不同相机因共同看到某个点而相连),琥珀是 \(E\) 和 \(E^\top\),绿是点的对角块 \(C\)。每个点被相邻的 \(m\) 台相机看到(沿轨迹的带状可见性,和真实的视觉里程计一样)。运算量按“稠密 Cholesky \(n^3/3\)”对“消点 + 解 \(6c\) 维约化系统”计;按钮会在你的浏览器里实际各解一次(随机雅可比块,只有结构真实),并比较两个解。
    • 把相机数拉到 20 以上、点数拉到 200 以上:Schur 比稠密求解省一百倍以上的运算,J 里非零的比例只有 1% 左右。

    外点与鲁棒损失

    特征匹配(11.5 节)总会混进错误对应。BA 里一个错误观测意味着一根拉向错误方向的橡皮筋,平方损失里它的“拉力”与偏离成正比,几个这样的观测就能把整张地图拽歪。解决办法是把 \(\tfrac12e^2\) 换成增长更慢的 \(\hl{rho}{\rho(e)}\),并用 IRLS 求解:每条观测按当前残差得到权重 \(w=\rho'(e)/e\),外点的残差大,权重就小(6.9、11.5 节)。下图在 111 条观测里随机替换若干条为错误像素(偏离 35 到 90 px),同样的初值、同样的算法,只换损失函数。

    FIG 4外点:平方损失被拽歪,鲁棒核把它们降权
    每次改动都从同一个初值重新运行 LM 到收敛(用 Schur 求解)。左上:估计(琥珀)对齐到真值(紫)后的样子。中:相机 3 的图像,点的大小和颜色是 IRLS 权重(大而绿 = 权重 1,小而红 = 权重 < 0.5),✕ 标出真正的外点,灰线是残差。右:三种损失 \(\rho(e)\):平方增长到画面之外,Huber 线性增长,Cauchy 几乎不再增长;底部的短竖线是当前每条观测的残差(红色是外点)。尺度 \(c\) 以像素计。
    • 先选“平方损失”,把外点加到 6 个以上,记下结构误差;再换成 Cauchy(c = 2):误差降到原来的四分之一以下,被降权的几乎都是真外点。
    一个想法,几种看法

    优化:一个有 \(6c+3p\) 个变量的稀疏非线性最小二乘(6.9 节)。 概率:高斯像素噪声下的最大似然估计,逆 Hessian 给出协方差(4.6 节;FIG 5)。 因子图:变量是相机和点,每条观测是连接一个相机和一个点的因子;Schur 补就是按“先消点”的顺序做消元(6.9 节的 FIG 2)。 交替:它同时包含“已知相机求点”(三角化)和“已知点求相机”(PnP),只是同时、且彼此纠正。

    5再看数学

    提示:把鼠标悬停在公式中带底色的符号上,图中对应的元素会被高亮(残差、相机、点、Schur 补、损失曲线)。

    代价与参数化

    相机 \(i\) 的外参是 \({}^{c_i}T_w=(R_i,\mathbf t_i)\in\SE\),把世界点变到相机系:\(\mathbf x_c=R_i X_j+\mathbf t_i\)(注意这是相机位姿 \({}^{w}T_{c}\) 的逆;画图时我们再取逆得到相机在世界里的位置 \(C_i=-R_i^\top\mathbf t_i\))。内参 \(f_x,f_y,c_x,c_y\) 已知并共享。点 \(X_j\in\R^3\),观测 \(\mathbf x_{ij}\in\R^2\)(像素),\(\mathcal O\) 是所有观测的集合。重投影残差与总代价是

    $$ \hl{res}{\mathbf r_{ij}}=\pi(R_iX_j+\mathbf t_i)-\mathbf x_{ij},\quad \pi(x,y,z)=\begin{bmatrix} f_x\,x/z+c_x\\ f_y\,y/z+c_y\end{bmatrix},\qquad F=\sum_{(i,j)\in\mathcal O}\hl{rho}{\rho}\big(\|\mathbf r_{ij}\|_{\Sigma}\big) $$

    \(\|\mathbf r\|_\Sigma=\sqrt{\mathbf r^\top\Sigma^{-1}\mathbf r}\) 是按像素噪声协方差“白化”后的长度(本页取 \(\Sigma=I\),即 1 px 为单位);\(\rho(e)=\tfrac12e^2\) 就是高斯噪声的最大似然(4.6 节),换成 Huber 或 Cauchy 就是鲁棒版。未知数共 \(6c+3p\) 个,方程 \(2|\mathcal O|\) 个;要有解需要 \(2|\mathcal O|\ge 6c+3p-7\),其中 7 是下面的规范自由度。

    雅可比:两块,各自很小

    相机用左扰动 \(T\leftarrow\Exp(\boldsymbol\delta)T\),\(\boldsymbol\delta=(\boldsymbol\omega,\mathbf v)\)(角速度在前,和全课程一致)。5.7 节告诉我们小扰动下 \(\Exp(\boldsymbol\delta)\mathbf x_c\approx\mathbf x_c+\boldsymbol\omega\times\mathbf x_c+\mathbf v=\mathbf x_c-[\mathbf x_c]_\times\boldsymbol\omega+\mathbf v\),所以相机坐标系下的点对扰动的导数是 \([-[\mathbf x_c]_\times\ \ I]\)(\(3\times6\))。点的扰动直接加在 \(X_j\) 上,\(\mathbf x_c\) 对它的导数是 \(R_i\)。再乘上投影的导数(令 \(\mathbf x_c=(x,y,z)\)):

    $$ \hl{cam}{J_c}=\frac{\partial\mathbf r_{ij}}{\partial\boldsymbol\delta_i}=\underbrace{\begin{bmatrix} f_x/z & 0 & -f_xx/z^2\\ 0 & f_y/z & -f_yy/z^2\end{bmatrix}}_{\partial\pi/\partial\mathbf x_c}\begin{bmatrix}-[\mathbf x_c]_\times & I\end{bmatrix}\in\R^{2\times6},\qquad \hl{pt}{J_p}=\frac{\partial\mathbf r_{ij}}{\partial X_j}=\frac{\partial\pi}{\partial\mathbf x_c}\,R_i\in\R^{2\times3} $$

    上面这一行是页面加载时现算的:把 \(J_c\)、\(J_p\) 和中心有限差分逐元素比较。注意 \(1/z\) 和 \(1/z^2\):深度 \(z\) 越大,同样的移动引起的像素变化越小,这就是远处的点、小视差的点不好约束的根源。

    正规方程、Schur 补

    把所有观测堆起来(IRLS 权重 \(w_k\) 放进对角矩阵 \(W\)),LM 的一步解 \((J^\top WJ+\lambda D)\boldsymbol\delta=-J^\top W\mathbf r\)。把未知数分成相机部分 \(\boldsymbol\delta_c\) 和点部分 \(\boldsymbol\delta_p\),方程变成分块形式(\(\mathbf g=J^\top W\mathbf r\) 是梯度,阻尼已并入 \(B\) 和 \(C\) 的对角):

    $$ \begin{bmatrix}B&E\\E^\top&C\end{bmatrix}\begin{bmatrix}\boldsymbol\delta_c\\\boldsymbol\delta_p\end{bmatrix}=-\begin{bmatrix}\mathbf g_c\\\mathbf g_p\end{bmatrix}\ \Longrightarrow\ \underbrace{(B-EC^{-1}E^\top)}_{\hl{schur}{S}}\boldsymbol\delta_c=-\mathbf g_c+EC^{-1}\mathbf g_p $$ $$ \boldsymbol\delta_{p,j}=-C_j^{-1}\big(\mathbf g_{p,j}+E_j^\top\boldsymbol\delta_c\big)\quad\text{(back-substitution, one }3\times3\text{ solve per point)} $$

    推导就是对第二块行做高斯消元:由 \(E^\top\boldsymbol\delta_c+C\boldsymbol\delta_p=-\mathbf g_p\) 得 \(\boldsymbol\delta_p=-C^{-1}(\mathbf g_p+E^\top\boldsymbol\delta_c)\),代入第一块行 \(B\boldsymbol\delta_c+E\boldsymbol\delta_p=-\mathbf g_c\) 即得关于 \(\boldsymbol\delta_c\) 的方程。\(S\) 叫约化相机系统(reduced camera system),大小 \(6c\times6c\),与点数无关;它正是把所有点“边缘化”掉之后相机的信息矩阵。FIG 2 里“稠密”与“Schur”两条路给出同一步长(差 \(10^{-13}\) 量级),因为它们只是同一个线性方程的两种消元顺序。

    规范自由度与可观测性

    取任意相似变换:旋转 \(R_g\)、平移 \(\mathbf t_g\)、尺度 \(s>0\),令 \(X_j'=sR_gX_j+\mathbf t_g\),\(R_i'=R_iR_g^\top\),\(\mathbf t_i'=s\mathbf t_i-R_iR_g^\top\mathbf t_g\)。则 \(R_i'X_j'+\mathbf t_i'=s(R_iX_j+\mathbf t_i)\),相机坐标整体放大 \(s\) 倍,而 \(\pi\) 对这样的缩放不变(\(x/z\) 不变),所以每一个重投影残差都不变,\(F\) 也不变。这个 7 参数族 \((R_g,\mathbf t_g,s)\) 是代价函数的一条 7 维“平坦谷”,\(H\) 因此有 7 维零空间,FIG 2 的谱画的就是这个。固定规范的常见做法:冻结第一台相机的位姿(6 维),再冻结一个量定尺度(这里是基线长度,也可以固定某一点的深度,或者把第二台相机平移的某一分量固定)。如果有别的信息,就能多固定几维:双目或带已知基线的系统自带尺度,只剩 6 维;加 IMU(重力方向)、GPS 或已知尺寸的物体,也能固定其中一部分。

    单目 BA 无法恢复绝对尺度,这是物理上的限制,不是算法的缺陷:把整个世界放大两倍,照片一模一样。能否恢复结构还取决于几何:每个点至少要被两台相机看到,并且视线有足够的夹角(视差);纯旋转的相机对所有点都没有视差,深度完全不可观测,\(C_j\) 奇异。

    不确定度:逆 Hessian

    在最优点附近,参数估计的协方差近似是 \(\operatorname{Cov}(\hat{\boldsymbol\theta})\approx\sigma^2(J^\top J)^{-1}\)(4.4、4.6 节;它也是 Cramér-Rao 下界)。只有固定了规范 \(J^\top J\) 才可逆,所以协方差的数值依赖于你选了哪种规范:“点相对于相机 1 的不确定度”和“点云去掉整体相似变换之后的不确定度”是不同的量。FIG 5 用后者:先取固定规范下的逆,再把点云的 7 个相似方向投影掉(最小迹规范)。我们用 1500 次蒙特卡洛重复核对了它:预测的点位误差方差与实测之比为 0.99。

    与位姿图的关系:消去所有点之后只剩相机,约化系统 \(S\) 就是相机位姿的信息矩阵,它在共视的相机之间有非零块。位姿图(Part IV 的 SLAM 后端)进一步用相机之间的相对位姿测量代替这些块,相当于把结构信息“边缘化后近似”掉:代价小得多,但丢掉了结构的细节,所以回环后常常再跑一次完整的 BA。

    BA 是局部方法

    LM 只保证找到离初值最近的局部极小。初值必须来自几何方法:11.1 的对极几何与 11.3 的三角化给出两视图的初始结构,11.4 的 PnP 把新相机接进来,11.5 的 RANSAC 先把外点挡在门外,BA 才能在“正确的盆地”里把误差压到噪声水平。

    6机器人中的它:要多宽的基线?

    BA 给出的不只是一个解,还有这个解的可信程度。一台机器人沿墙走,每隔一段时间选一帧“关键帧”加入地图。关键帧选得太密,相邻帧之间几乎没有视差,新三角化的点深度很不准;选得稀一点,视差大了,但特征匹配会变难。下图用上面的 BA 反过来问这个问题:给定相机弧的宽度、相机数和像素噪声,每个点的位置不确定度(琥珀色椭球,3σ,已去掉整体相似变换)有多大?椭球是从 \(\sigma^2(J^\top J)^{-1}\) 里取出来的,没有跑任何随机试验。

    FIG 5不确定度来自 Hessian:视差决定深度精度
    24 个点,所有相机都看到所有点。椭球是每个点位置的 3σ 协方差椭球(最小迹规范),为了看得见,画出时放大了 10 倍(读数是真实大小)。相机弧很窄时椭球沿视线方向被拉得很长:深度比横向差几倍;弧变宽或相机变多,椭球收缩并趋于球形。深度 / 横向读数是各点沿“平均相机到该点”方向的标准差与垂直方向标准差之比。
    • 先把弧半角压到 12° 以下:深度不确定度是横向的 2.5 倍以上;再把弧半角拉到 50° 以上:深度误差降到 4 mm 以下,椭球几乎变成球。
    真实系统里

    SfM:COLMAP、Theia、OpenMVG 增量式地注册图像(PnP)、三角化新点,并周期性运行局部与全局 BA;COLMAP 的 BA 基于 Ceres Solver,用 Schur 型求解器。 视觉 SLAM:ORB-SLAM 系列在建图线程里对共视关键帧和它们的地图点做局部 BA(g2o,LM),回环后再做全局 BA;ORB-SLAM3 加入了 IMU。三角化的点要求两条视线之间有足够的夹角,正是 FIG 5 的道理。 滑动窗口:机器人要实时,就不能让问题越来越大,所以只对最近的若干关键帧做 BA,旧状态边缘化(Schur 补)成一个先验,VINS-Mono 就是这样做的视觉惯性滑窗优化(用 Ceres 求解),OpenVINS 则走滤波(MSCKF)路线。 标定也是 BA:OpenCV 的 calibrateCamera 在标定板上最小化重投影误差,未知数是内参、畸变和每张图的板位姿(10.4 节),Kalibr 对多相机加 IMU 做同样的事。 NeRF / 3DGS:训练前的相机位姿通常来自 COLMAP(Nerfstudio 的数据处理流程调用它),BARF(Lin 等,ICCV 2021)进一步把位姿和神经辐射场一起优化。 库:g2o、Ceres Solver、GTSAM、SymForce(自动生成雅可比);Agarwal 等的 “Bundle Adjustment in the Large” 在数千台相机、百万级点上用预条件共轭梯度解 Schur 约化系统,Ceres 里对应 ITERATIVE_SCHUR。

    7常见误区

    误区 1:没固定规范,或固定得不对

    FIG 2 已经演示:不固定时 \(J^\top J\) 有 7 维零空间,Gauss-Newton 的 Cholesky 直接失败;LM 的阻尼能让它“跑得通”,但解落在 7 维平坦谷里任意一点,每次运行世界坐标系和尺度都不同,没法与别的地图拼接。还有一种常见错法:只固定了相机位姿,忘了尺度,或者把位置先验(GPS、已知的标定板尺寸)写成残差却又同时冻结了相机,使得问题过约束且互相矛盾。固定几维就是几维,不要多也不要少。

    误区 2:初值太差,或以为 BA 能自己找到初值

    BA 是局部优化。本页的初值是“真值加扰动”,所以连扰动水平 3 也能收敛;真实流程里初值来自对极几何、三角化、PnP,质量参差不齐,一个相机被错误地注册到镜像或错误的位置,就可能陷入离正解很远的局部极小。用鲁棒的几何方法初始化,增量式地加相机并频繁做局部 BA,是 SfM 稳健的关键。

    误区 3:不用鲁棒核,或把鲁棒核当万能药

    FIG 4:6 个外点就让平方损失的结构误差放大十几倍。但鲁棒核也有代价:Huber 的影响函数有界却不为零,外点多时仍会偏;Cauchy 这类“回落”核几乎能消除外点,但代价非凸,对初值更挑剔;尺度 \(c\) 取小了会把正常的大噪声也降权。更好的顺序是:先用几何验证(RANSAC、11.5 节)筛一遍,再用鲁棒 BA 兜底,最后可以去掉被降权的观测再跑一次普通 BA。

    误区 4:小视差的点和远处的点

    视线夹角越小,点的深度越不确定(FIG 5),\(C_j\) 越接近奇异,\(J^\top J\) 越病态。更糟的是 BA 最小化的是像素误差,一个很远的点深度错了几十米,像素几乎不变,所以代价对它几乎没有约束。要么给每个点设最小视差、最小三角化角度的门槛,要么用逆深度参数化(\(1/z\) 对远点是良态的),要么把这些点只当方向约束使用。别拿“重投影误差很小”当作“这个点可靠”的证据。

    误区 5:阻尼太小、旋转直接加法、以为 BA 能恢复尺度

    三个小坑。(a) \(\lambda\) 太小时,病态的 \(J^\top J\) 让步长爆炸,要靠 LM 的“拒绝再增大 \(\lambda\)”兜底,不要把 \(\lambda\) 写死成 0。 (b) 旋转不能用 \(R\leftarrow R+\Delta R\) 或欧拉角直接相加:用指数映射 \(\Exp\) 更新(6.10 节),否则会出现万向节锁或不再是旋转矩阵。 (c) 单目 BA 的尺度由你固定的基线决定(FIG 2 里“对真值的尺度”读数),要得到公制尺度,需要双目基线、IMU、已知尺寸的物体或 GPS 之类的外部信息。

    8小练习

    1. 单目 BA:4 台相机、10 个点,每个点都被 4 台相机看到。固定规范之后,有多少个独立未知数?方程有多少个?
    未知数 \(6\cdot4+3\cdot10=54\),减去 7 个规范自由度得 47。观测 \(4\times10=40\) 条,每条给出 \(u\) 和 \(v\) 两个方程,共 80 个。冗余度 \(80-47=33\) 是 BA 能把噪声平均掉的原因。如果是带已知基线的双目系统,规范只有 6 维,未知数是 48。
    2. 把一个已收敛的单目重建(所有点和相机中心)整体放大 2 倍,相机朝向不变。重投影代价 \(F\) 会怎样?
    相机坐标系下的点 \((x,y,z)\) 全部变成 \((2x,2y,2z)\),而 \(u=f_xx/z+c_x\)、\(v=f_yy/z+c_y\) 只与比值有关,所以每个像素都不变,\(F\) 不变。这就是尺度规范自由度:单目图像本身不含绝对尺度,必须固定一个。
    3. Schur 补为什么能让 BA 快几个数量级?
    Schur 补是精确的(不是近似),步长和稠密求解完全相同(FIG 2 的读数差 \(10^{-13}\))。省下的是运算量:稠密 \(\sim(6c+3p)^3/3\),而 Schur 约 \(\sim p\cdot O(m^2)+(6c)^3/3\),点数 \(p\) 只以线性出现。
    4. 一台相机只旋转、不平移,拍了两帧。把这两帧加进 BA,点的深度会怎样?
    视差来自相机中心的移动,与旋转无关:纯旋转时所有点的视线都从同一个中心出发,两帧对点的深度没有任何约束(相当于一个单应,10.5 节)。FIG 5 的极限情形(弧宽趋于 0)就是这个现象:深度方向的标准差趋于无穷。
    5. 数据有噪声时,BA 收敛处的代价 \(F\) 与“真值处的代价”相比?
    BA 最小化的是带噪声的观测上的代价,真值只是一个可行点,不是该代价的最小值。有 \(n\) 个自由未知数时,最优处的期望代价约为 \(\tfrac12\sigma^2(2m-n)\),而真值处约为 \(\tfrac12\sigma^2\cdot2m\)(FIG 2 里约 14 对 26)。这个差别就是“过拟合噪声”的量,也说明为什么每条观测的残差 RMS 收敛到 σ 附近,而不是真值处的 \(\sqrt2\,\sigma\)(这里约 0.5 px 对 0.71 px)。

    9延伸阅读

    • B. Triggs, P. McLauchlan, R. Hartley & A. Fitzgibbon, Bundle Adjustment — A Modern Synthesis, Vision Algorithms: Theory and Practice (LNCS 1883), 2000 — 权威综述:参数化、规范自由度、Schur 补、鲁棒核、协方差
    • R. Hartley & A. Zisserman, Multiple View Geometry in Computer Vision, 2nd ed., Cambridge University Press, 2004, Appendix 6 (iterative estimation methods) and Ch. 18 — 稀疏 LM 与 n 视图重建
    • S. Agarwal, N. Snavely, S. Seitz & R. Szeliski, Bundle Adjustment in the Large, ECCV 2010 — 用预条件共轭梯度求解数千相机、百万点的 BA
    • F. Dellaert & M. Kaess, Factor Graphs for Robot Perception, Foundations and Trends in Robotics, 2017 — 把 BA、SLAM 看成因子图与稀疏消元
    • J. L. Schönberger & J.-M. Frahm, Structure-from-Motion Revisited, CVPR 2016 — COLMAP:增量式 SfM 的工程细节
    • C. Campos, R. Elvira, J. J. Gómez Rodríguez, J. M. M. Montiel & J. D. Tardós, ORB-SLAM3, IEEE Transactions on Robotics, 2021 — 视觉与视觉惯性 SLAM 中的局部与全局 BA
    • C.-H. Lin, W.-C. Ma, A. Torralba & S. Lucey, BARF: Bundle-Adjusting Neural Radiance Fields, ICCV 2021 — 把 BA 的思想用于神经辐射场的位姿联合优化