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

对极几何:本质矩阵与基础矩阵

只有两张图、没有任何三维模型时,图 1 里的一个像素能告诉你它在图 2 里的位置吗?能:对应点一定落在一条直线(极线)上。这条约束写成矩阵就是本质矩阵 E 与基础矩阵 F,是视觉里程计、运动恢复结构、双目校正和 SLAM 初始化共同的起点。本节从几何画面推出 x₂ᵀEx₁ = 0,在带噪声的匹配上运行真正的 8 点算法,把 E 分解成四组 (R, t) 并用手性(cheirality)检验选出唯一正确的一组,同时看清为什么单目永远不知道尺度、哪些场景会让算法失效。

约 40 分钟 前置:1.6 秩与零空间 · 1.8 叉积 · 1.12 SVD · 5.3 SE(3) · 10.1 针孔相机 · 10.2 齐次坐标 · 10.3 内参外参 5 个交互

    1为什么机器人需要它

    一台只有一个摄像头的机器人在走。第 \(t\) 帧和第 \(t+1\) 帧是两张图,它想知道自己在两帧之间怎样运动了(旋转多少、朝哪个方向平移),可是手里没有环境的三维地图,连场景里的东西多远都不知道。能做什么?

    两张图之间有一件事完全不依赖场景长什么样:图 1 的一个像素,只能对应图 2 里的一条直线(极线),而不是整个平面。这是纯几何事实,只要两个相机的相对位姿和内参确定,它就成立。反过来,如果能找到足够多的对应点,让它们都满足这条直线约束,就能解出相对位姿。这就是对极几何,它支撑了:

    • 视觉里程计与 SLAM 的初始化:单目系统用两帧的匹配估计初始运动,再三角化出第一批地图点(11.3 节)。
    • 运动恢复结构 (SfM):COLMAP 一类的系统,每对图像先做一次两视图几何验证,再拼成整个场景(11.6 节)。
    • 双目与校正:左右图像的对应点在同一行上,是极线平行时的特例(11.2 节);搜索匹配点从二维变成一维。
    • 鲁棒匹配:极线约束是剔除错误匹配(外点)的主要依据,RANSAC 用 5 点或 8 点的最小求解器(11.5 节)。

    本节只用两张图的 2D–2D 对应点。已知 3D 点时用 PnP(11.4 节)更直接;两视图对应点先给出 \((R,t)\),再三角化(11.3 节)和整体优化(束调整,11.6 节)把它精化。

    2直觉:一条光线,在另一张图里是一条线

    图 1 里的一个像素 \(\mathbf x_1\),对应相机 1 光心发出的一条光线:光线上所有的三维点都投影到这个像素(10.1 节)。三维点到底在光线的哪里,一张图说不出来,深度丢了。现在让相机 2 看这条光线:光线上不同深度的点,在图 2 里投影成一条直线,这就是极线。因此 \(\mathbf x_1\) 的匹配点必在这条线上,一维的搜索代替了二维。

    几何上的关键对象有四个,都在 FIG 1 里:基线(两个光心的连线);对极平面(过两个光心和三维点 \(X\) 的平面);极线(对极平面和图像平面的交线,每张图一条);极点 \(\mathbf e_1,\mathbf e_2\)(基线与两个图像平面的交点,也就是另一个相机的光心在这张图里的像)。所有极线都经过极点,因为所有对极平面都含有基线。

    FIG 1 里,左下是相机 1 的图像,右下是相机 2 的图像,上面是三维视图。在图 1 里点击或拖动琥珀色的点:三维里出现经过它的光线、对极平面,图 2 里出现对应的极线。用"深度"滑块沿光线移动 \(X\),图 2 里的像点 \(\mathbf x_2\) 沿极线滑动,并始终在线上。极线的一端是极点 \(\mathbf e_2\)(深度 0,也就是相机 1 的光心),另一端是方框标出的"深度 ∞"点(光线的无穷远端),匹配点必在这两个端点之间。

    FIG 1两个视图与一条光线
    三维视图:拖动旋转
    预设位姿
    相机 1(青)固定,相机 2(紫)的位姿由滑块给出,量取在相机 1 的坐标系里(x 右,y 下,z 前)。琥珀色:像素 \(\mathbf x_1\)、它的光线、点 \(X\) 与极线。青色半透明平行四边形是对极平面;绿色圆环是极点(在相机后方时标签注明"在相机后",在画面外时画成指向它的箭头,并标出坐标)。图像坐标 \((u,v)\),\(v\) 向下,画面里用 \(y=-v\) 绘制,左上角的小箭头标出方向。图 1 里的虚线是对极平面与图 1 的交线:它经过 \(\mathbf e_1\) 和 \(\mathbf x_1\)。读数里的距离是 \(\mathbf x_2\) 到 \(\mathbf l_2=F\tilde{\mathbf x}_1\) 的距离,应为 \(10^{-13}\) 量级。
    试一试
    • 拖动"深度 Z"滑块,让深度改变 1.5 m 以上。图 2 里的 \(\mathbf x_2\) 沿着极线滑动,端点分别是什么?为什么单张图看不出深度?
    • 点"平行并排"预设:基线平行于两个像平面,极点跑到无穷远,所有极线平行(水平线)。这就是校正后双目(11.2 节)的构型:匹配点在同一行上。
    • 点"向前走"预设(或令 \(t_z>0.5\) m、\(t_x\) 很小):极点 \(\mathbf e_1\) 落进图 1 里,极线从它向四周辐射。这是机器人向前行驶时看到的"光流扩张点"(focus of expansion)。
    • 把三个平移滑块都拖到 0。极线消失了,读数提示 \(E=0\)。没有基线就没有对极几何:纯旋转的相机只改变视线方向,不提供任何深度信息(见后面的退化情形)。
    约定(本节全部遵守)

    以相机 1 的坐标系为参考。同一个三维点在两个相机坐标系里的坐标满足 \(\mathbf X_2=R\,\mathbf X_1+\mathbf t\),也就是 \((R,\mathbf t)\) 是从相机 1 系到相机 2 系的变换 \({}^{2}T_{1}\)(5.3 节,OpenCV 的 recoverPose 同此约定)。相机 2 的光心在相机 1 系里是 \(\mathbf C_2=-R^{\top}\mathbf t\),相机 2 的位姿是 \({}^{1}T_{2}=(R^{\top},\,-R^{\top}\mathbf t)\)。注意 \(\mathbf t\) 不是相机 2 的位置,而是相机 1 光心在相机 2 坐标系里的坐标。两个相机坐标系都是 OpenCV 光学系(x 右,y 下,z 前)。

    3动手玩:推出本质矩阵 E

    极线怎么算?把 FIG 1 里的几何翻译成代数。在相机 2 的坐标系里看(FIG 2):相机 2 的光心 \(O\) 在原点,相机 1 的光心在 \(\mathbf t\),三维点 \(X\) 的位置有两种写法。从相机 2 直接看:\(\mathbf X_2=\lambda_2\hat{\mathbf x}_2\),\(\hat{\mathbf x}_2\) 是像素的归一化坐标(\(\hat{\mathbf x}=K^{-1}\tilde{\mathbf x}=(x,y,1)\),10.3 节),\(\lambda_2\) 是深度;从相机 1 走过去:先到 \(\mathbf t\),再沿相机 1 的光线走 \(\lambda_1 R\hat{\mathbf x}_1\)(光线方向 \(\hat{\mathbf x}_1\) 要用 \(R\) 转到相机 2 的坐标轴上)。两种走法到同一点,三个向量形成一个闭合三角形:

    $$ \hl{ray2}{\lambda_2\hat{\mathbf x}_2}\;=\;\hl{ray1}{\lambda_1 R\hat{\mathbf x}_1}\;+\;\hl{base}{\mathbf t}. $$

    三个向量首尾相接,所以它们在同一个平面里(对极平面)。三个向量共面等价于混合积为零:\(\hat{\mathbf x}_2\cdot(\mathbf t\times R\hat{\mathbf x}_1)=0\)。叉积是线性的,可以写成矩阵(1.8 节):\(\mathbf t\times\mathbf v=[\mathbf t]_\times\mathbf v\)。于是

    $$ \hat{\mathbf x}_2^{\top}\,\hl{E}{E}\,\hat{\mathbf x}_1=0,\qquad \hl{E}{E}=[\mathbf t]_\times R,\qquad [\mathbf t]_\times=\begin{bmatrix}0&-t_z&t_y\\ t_z&0&-t_x\\ -t_y&t_x&0\end{bmatrix}. $$

    \(E\) 叫本质矩阵 (essential matrix),只含相对位姿 \((R,\mathbf t)\),不含内参。把 \(\hat{\mathbf x}=K^{-1}\tilde{\mathbf x}\) 代回去,对像素坐标就是 \(\tilde{\mathbf x}_2^{\top}F\tilde{\mathbf x}_1=0\),\(F=K_2^{-\top}EK_1^{-1}\),基础矩阵 (fundamental matrix)。\(F\tilde{\mathbf x}_1\) 就是图 2 里那条极线的系数 \((a,b,c)\):\(au+bv+c=0\)。FIG 2 把上面五步依次演示出来,数值检验是真实计算:同一个匹配的 \(\hat{\mathbf x}_2^{\top}E\hat{\mathbf x}_1\) 在 \(10^{-16}\) 量级。

    FIG 2推导 E:从共面到矩阵
    相机 2 坐标系 · 拖动旋转
    按钮 1–5 逐步推进。画面是以相机 2 为参考的三维视图(相机 2 的坐标轴在原点,相机 1 的坐标轴在 \(\mathbf t\),朝向由 \(R\) 的各列给出)。琥珀箭头 \(\mathbf t\),蓝箭头 \(\lambda_1R\hat{\mathbf x}_1\),紫箭头 \(\lambda_2\hat{\mathbf x}_2\) 构成闭合三角形;第 3 步起显示对极平面和它的法向 \(\mathbf n=\mathbf t\times R\hat{\mathbf x}_1\),\(\hat{\mathbf x}_2\perp\mathbf n\) 就是混合积为零。右侧读数全部由当前位姿和匹配点真实算出;E 的奇异值是 \((\|\mathbf t\|,\|\mathbf t\|,0)\),F 的秩为 2。悬停公式里带底色的向量,对应的箭头加粗。
    试一试
    • 依次点到第 5 步。换几个匹配点和随机位姿:\(\hat{\mathbf x}_2^{\top}E\hat{\mathbf x}_1\) 每次都是 \(10^{-16}\) 量级,E 的前两个奇异值总是相等,且等于 \(\|\mathbf t\|\)。
    核心洞见

    对每一对匹配,\(\tilde{\mathbf x}_2^{\top}F\tilde{\mathbf x}_1=0\) 是关于 \(F\) 的 9 个元素的一个线性方程。\(F\) 里藏着相对位姿和内参,却不需要知道任何三维点:方程里没有深度 \(\lambda\)。线性意味着可以直接用 SVD 求解(1.12 节),这就是 8 点算法。

    E 与 F 有多少自由度?

    E:5 个。旋转 \(R\) 3 个,平移 \(\mathbf t\) 只剩方向 2 个:对极方程两边乘任何常数仍成立,所以 \(\|\mathbf t\|\) 不可观(尺度模糊,见 FIG 4)。从矩阵角度数:9 个元素减 1(整体尺度),减 1(\(\det E=0\),秩 2),再减 2(两个非零奇异值相等),\(9-1-1-2=5\)。F:7 个。\(F\) 只有"整体尺度"和"秩 2"两个限制,\(9-1-1=7\),它不要求奇异值相等,因为内参 \(K_1,K_2\) 把这条性质破坏了。所以 \(E\) 比 \(F\) 少 2 个自由度,等于已知内参带来的信息。

    4第二、第三视角:估计 F,再恢复运动

    从带噪声的匹配估计 F:8 点算法

    真实系统拿到的不是 \(E\) 或 \(F\),而是一堆带噪声的匹配点(特征检测与匹配,11.5 节)。每对匹配给出一个线性方程 \(\mathbf a_i^{\top}\mathbf f=0\),其中 \(\mathbf f\) 是 \(F\) 的 9 个元素排成的向量。叠起 \(N\ge8\) 个方程得到 \(A\mathbf f=0\),要在 \(\|\mathbf f\|=1\) 下最小化 \(\|A\mathbf f\|\):解是 \(A\) 的最小右奇异向量(1.6 节的零空间,1.12 节的 SVD)。最后还要把 \(F\) 投影到秩 2:令最小奇异值为 0。

    FIG 3 运行的就是这个算法,用的是真实代码,不是动画。场景是固定的(相机 2 向前并稍向右移动),匹配点加上高斯像素噪声。紫线是估计的极线,绿线是真值极线,琥珀圆点是真实的匹配点。度量"估计得好不好"有两种数:用来拟合的点上的 Sampson 误差(小不代表好),以及留出的、没参与拟合的 80 个点上的对极距离(这才是泛化误差)。试着体会:N 很小时拟合误差接近零,留出误差却很大——算法在"背"噪声。

    FIG 38 点算法实验室
    左:图 2。青色小点是用于拟合的匹配点(带噪声),8 条绿线与 8 个琥珀点是留出点的真值极线与真匹配,紫线是估计的 F̂ 给出的极线;绿圈是真极点,紫圈是估计的极点。强制秩 2 时,紫线严格共点于紫圈;关掉后它们不再严格共点(匹配少、噪声大时最明显)。右:留出误差随噪声变化,红线不归一化,绿线 Hartley 归一化(各取 10 次噪声重抽的中位数,粗线是当前设置)。读数里的 σ₇ σ₈ σ₉ 是(归一化后)矩阵 A 最小的三个奇异值:一般场景只有 σ₉ 很小,退化场景有三个很小。虚拟相机 1280×960 像素,焦距 1040 px,场景深度 4.5–8 m。
    试一试
    • 把 N 拉到 8–10,噪声 \(\sigma\ge0.5\) px:拟合误差只和噪声同量级,留出误差却是它的两倍以上。8 个方程恰好解出 8 个自由度,噪声没有被平均掉。再把 N 加到 100,留出误差降下来。
    • 取 \(\sigma\ge1.5\)、\(N\ge15\),把"归一化"关掉:误差明显更大,至少是归一化的 1.5 倍,换几次噪声常常是好几倍(读数给出同一份数据归一化后的结果,右图红线远高于绿线)。像素坐标的量级差太大(\(uu'\sim10^6\),常数项 1),SVD 的最小二乘被大数淹没。
    • 把"强制秩 2"关掉:紫线不再严格共点(N 小、噪声大时最明显),读数里 \(\hat F\) 的 σ₃/σ₁ 从 \(10^{-17}\) 变成非零。误差数值变化不大,但没有严格的极点,E 的分解(FIG 4)就缺了依据。
    • 切到"平面场景"(取 \(N\ge20\)):σ₇ σ₈ σ₉ 三个同样小,σ₈/σ₉ 约为 1,F 在一个三维族里随噪声乱跳,留出误差变得很大,极点位置也不稳定。再试"纯旋转":同样的症状,因为没有基线。

    从 E 恢复运动:四个解与手性检验

    有了 \(E\)(已知内参时,用归一化坐标直接估计,或 \(E=K_2^{\top}FK_1\)),就可以拆出 \((R,\mathbf t)\)。对 \(E\) 做 SVD,\(E=U\,\mathrm{diag}(\sigma,\sigma,0)\,V^{\top}\),\(\mathbf t\) 是 \(E\) 的左零向量 \(\mathbf u_3\),只确定到正负号和尺度;旋转有两个解 \(UWV^{\top}\) 与 \(UW^{\top}V^{\top}\)(\(W\) 是绕 z 轴转 90° 的矩阵)。符号 × 两个旋转共 4 个候选。其中两个旋转差了一个绕基线的 180° 转动,称为"孪生对"(twisted pair)。

    数据本身不分辨它们:对极方程对 \(\pm\mathbf t\)、对两种旋转都成立。真正区分的是物理常识:被拍到的点必须在两个相机的前面。对每个候选,把匹配三角化得到深度 \((\lambda_1,\lambda_2)\),只有一个候选让两个深度都为正。这叫手性检验 (cheirality)。FIG 4 里相机 1(灰)在原点,四种颜色是四个候选的相机 2,每个候选各自"重建"了所有匹配点(小点),选定的一对匹配画成大点,边缘绿色表示在两个相机前面,红色表示不在。灰色的淡相机是真值。

    FIG 4分解 E:四个候选与手性检验
    以 ‖t‖ = 1 为单位 · 拖动旋转
    E 由 \(N\) 个带噪声的匹配用 8 点算法估计(归一化坐标,奇异值强制为 \((\sigma,\sigma,0)\)),再用 SVD 分解出四个候选。右侧表格第三列是"同时在两个相机前方的点数 / N",唯一满 N 的就是正确候选(粗体加 ✓ 是投票选中的)。读数里的百分比是 100 次独立噪声重抽中选对的比例;噪声大、匹配少时它会下降。最后一个滑块把整个世界(场景和基线)一起放大 s 倍:所有像素坐标不变(最大变化约 \(10^{-13}\) px),估计出的 \(\|\hat{\mathbf t}\|\) 永远是 1。
    试一试
    • 点"候选 1…4"逐个聚焦(其余变淡),找到那个被投票选中且就是真值的候选:它的大点在两个相机前面,边缘是绿色;另外三个,点要么在相机 1 后面,要么在相机 2 后面。
    • 把尺度 s 拉到 3 以上(或 0.33 以下):真实基线变成 \(s\) 倍,场景大了又大,像素读数一点不变,重建的三维图形也没动。单目只能恢复到相似变换,没有米。
    同一个约束的三种说法

    几何:\(\mathbf x_1\)、\(\mathbf x_2\) 与两个光心构成的对极平面含基线,等价于两条光线共面。代数:\(\tilde{\mathbf x}_2^{\top}F\tilde{\mathbf x}_1=0\),对 \(F\) 线性,\(F\tilde{\mathbf x}_1\) 就是极线。射影:\(F=[\mathbf e_2]_\times H_\infty\),其中 \(H_\infty=K_2RK_1^{-1}\) 把图 1 的点按"深度无穷远"搬到图 2(FIG 1 里的方框)。极线是连接 \(\mathbf e_2\)(深度 0)与 \(H_\infty\tilde{\mathbf x}_1\)(深度 ∞)的直线:\(\mathbf l_2=\mathbf e_2\times H_\infty\tilde{\mathbf x}_1\)。把 \(H_\infty\) 换成由任何一个平面诱导的单应 \(H_\pi\),公式依然成立(10.5 节)。

    5再看数学

    提示:把鼠标悬停在公式中带底色的符号上,FIG 1 或 FIG 2 中对应的元素会被高亮。

    对极约束、E 与 F

    设 \(\mathbf X_2=R\mathbf X_1+\mathbf t\),像素 \(\tilde{\mathbf x}_i=K_i\hat{\mathbf x}_i\)。把第 3 节(FIG 2)的推导再写一遍,并用 \(\mathbf t\times\mathbf v=[\mathbf t]_\times\mathbf v\):

    $$ \begin{aligned}\lambda_2\hat{\mathbf x}_2&=\lambda_1R\hat{\mathbf x}_1+\mathbf t \ \xrightarrow{\ \times\mathbf t\ }\ \lambda_2[\mathbf t]_\times\hat{\mathbf x}_2=\lambda_1[\mathbf t]_\times R\hat{\mathbf x}_1 \\ &\xrightarrow{\ \hat{\mathbf x}_2^{\top}\cdot\ }\ \boxed{\hat{\mathbf x}_2^{\top}\hl{E}{E}\,\hat{\mathbf x}_1=0,\ \ E=[\mathbf t]_\times R}\\[4pt] &\text{pixels: }\ \boxed{\tilde{\mathbf x}_2^{\top}F\tilde{\mathbf x}_1=0,\ \ F=K_2^{-\top}EK_1^{-1}}\end{aligned} $$

    (第二步用了 \(\hat{\mathbf x}_2^{\top}[\mathbf t]_\times\hat{\mathbf x}_2=0\):向量与自己的叉积垂直于自己。)极线、极点与它们的性质:

    $$ \begin{aligned}\hl{line}{\mathbf l_2}&=F\tilde{\mathbf x}_1,\quad \mathbf l_1=F^{\top}\tilde{\mathbf x}_2\\ \hl{epi}{\mathbf e_2}&=K_2\,\hl{base}{\mathbf t},\quad \mathbf e_1=-K_1R^{\top}\mathbf t=K_1\mathbf C_2\\ F\mathbf e_1&=\mathbf 0,\quad F^{\top}\mathbf e_2=\mathbf 0\end{aligned} $$

    \(F\mathbf e_1=K_2^{-\top}[\mathbf t]_\times R\,K_1^{-1}K_1(-R^{\top}\mathbf t)=-K_2^{-\top}[\mathbf t]_\times\mathbf t=\mathbf 0\),因此 \(F\) 一定有零空间,秩 ≤ 2,极点就是它的左、右零向量,\(\det F=0\)。线 \(\mathbf l\) 与点 \(\mathbf x\) 的关系是 \(\mathbf l^{\top}\mathbf x=0\)(10.2 节的点线对偶)。下面把 \(E\) 与 \(F\) 并排:

    本质矩阵 \(E\)基础矩阵 \(F\)
    作用的坐标归一化坐标 \(\hat{\mathbf x}=K^{-1}\tilde{\mathbf x}\)(需要内参)像素坐标(不需要内参)
    自由度57
    约束秩 2,且两个非零奇异值相等 (Huang–Faugeras)只有秩 2:\(\det F=0\)
    能给出\((R,\mathbf t/\|\mathbf t\|)\),4 个候选极线、极点;射影重建,没有度量
    最小求解器5 点 (Nistér),最多 10 个解7 点,最多 3 个解;线性 8 点

    8 点算法

    把 \(\tilde{\mathbf x}_2^{\top}F\tilde{\mathbf x}_1=\sum_{ij}\tilde x_{2,i}F_{ij}\tilde x_{1,j}\) 按行展开成内积,第 \(i\) 对匹配 \((u_i,v_i)\to(u_i',v_i')\) 给出一个方程:

    $$ \begin{aligned}\mathbf a_i^{\top}\mathbf f&=0,\quad \mathbf a_i=\tilde{\mathbf x}_{2,i}\otimes\tilde{\mathbf x}_{1,i}=(u'u,\ u'v,\ u',\ v'u,\ v'v,\ v',\ u,\ v,\ 1)\\ \mathbf f&=(F_{11},F_{12},\dots,F_{33}),\\ A&=\begin{bmatrix}\mathbf a_1^{\top}\\ \vdots\\ \mathbf a_N^{\top}\end{bmatrix},\qquad \hat{\mathbf f}=\arg\min_{\|\mathbf f\|=1}\|A\mathbf f\|=\mathbf v_9\end{aligned} $$

    \(\mathbf v_9\) 是 \(A=U\Sigma V^{\top}\) 的最后一列右奇异向量(1.12、1.13 节)。步骤:①Hartley 归一化:对每张图的点做平移和缩放,使质心在原点、到原点的平均距离是 \(\sqrt2\),即 \(\mathbf x\mapsto T\mathbf x\);②在归一化点上建 \(A\),取 \(\mathbf v_9\) 排成 \(\hat F\);③强制秩 2:\(\hat F=U\,\mathrm{diag}(s_1,s_2,s_3)\,V^{\top}\to U\,\mathrm{diag}(s_1,s_2,0)\,V^{\top}\)(Frobenius 范数下最近的秩 2 矩阵,Eckart–Young);④去归一化:\(F=T_2^{\top}\hat FT_1\)。第①步看似是小技巧,实则关键:像素坐标下 \(A\) 的列有 \(10^6\)、\(10^3\)、\(1\) 三种量级,条件数极大;归一化后各列同量级。Hartley(1997)的结论是,这样的 8 点算法与迭代算法精度相当,而且简单得多(FIG 3 的红绿线)。若直接估计 \(E\),把第③步换成"最近的本质矩阵":奇异值替换为 \((\tfrac{s_1+s_2}2,\tfrac{s_1+s_2}2,0)\)。

    从 E 到 (R, t),以及手性检验

    令 \(E=U\,\mathrm{diag}(\sigma,\sigma,0)\,V^{\top}\),必要时把 \(U,V\) 的第三列变号使 \(\det U=\det V=+1\)。取 \(W=\begin{bmatrix}0&-1&0\\1&0&0\\0&0&1\end{bmatrix}\):

    $$ \begin{aligned}R&\in\{\,UWV^{\top},\ UW^{\top}V^{\top}\,\},\qquad \mathbf t=\pm\mathbf u_3\ \ (\|\mathbf t\|=1)\\ \text{cheirality:}&\ \ \lambda_1>0,\ \lambda_2>0,\ \ \text{where }\ \lambda_2\hat{\mathbf x}_2=\lambda_1R\hat{\mathbf x}_1+\mathbf t\end{aligned} $$

    验证:\(\mathbf t\) 必须满足 \(E^{\top}\mathbf t=R^{\top}[\mathbf t]_\times^{\top}\mathbf t=\mathbf 0\),所以 \(\mathbf t\) 在 \(E\) 的左零空间里,即 \(\mathbf u_3\)。深度 \((\lambda_1,\lambda_2)\) 由上面三维向量方程的最小二乘解得到(FIG 4 用的就是这个;11.3 节会讲更精确的三角化)。有噪声时用投票:数一数有多少匹配点在两个相机前面,取最多的候选。注意:当基线很小、点很远时,孪生对的深度符号差别也很小,投票可能出错,这正是 FIG 5 里小视差时的失败原因之一。

    Sampson 误差与"金标准"

    \(\tilde{\mathbf x}_2^{\top}F\tilde{\mathbf x}_1\) 本身没有像素单位的意义。点到极线的距离 \(|\mathbf l^{\top}\mathbf x|/\sqrt{l_1^2+l_2^2}\) 只度量一张图。对两张图的一阶(Sampson)近似给出对匹配点在两张图上同时移动最少的像素量:

    $$ d_{\text{Sampson}}^2=\frac{(\tilde{\mathbf x}_2^{\top}F\tilde{\mathbf x}_1)^2}{(F\tilde{\mathbf x}_1)_1^2+(F\tilde{\mathbf x}_1)_2^2+(F^{\top}\tilde{\mathbf x}_2)_1^2+(F^{\top}\tilde{\mathbf x}_2)_2^2}. $$

    它是真正的几何(重投影)误差的一阶近似,常用作 RANSAC 内点判据和非线性精化的目标。线性的 8 点算法最小化的是代数误差 \(\|A\mathbf f\|\),不是几何误差;最优的"金标准"是把 \((R,\mathbf t)\) 与所有三维点一起,最小化重投影误差:这就是束调整(11.6 节),而 8 点或 5 点的结果是它的初值。

    退化情形

    • 平面场景:所有点在一个平面上时,匹配之间是单应 \(\tilde{\mathbf x}_2\sim H\tilde{\mathbf x}_1\),于是对任何向量 \(\mathbf e\),\([\mathbf e]_\times H\) 都满足约束,\(A\) 的零空间至少三维,\(F\) 不唯一(FIG 3:σ₇ σ₈ σ₉ 同样小)。对策:同时估计单应,让模型选择决定用哪一个(10.5 节)。
    • 纯旋转(基线 0):\(\mathbf t=\mathbf 0\),\(E=0\),匹配由 \(H_\infty=KRK^{-1}\) 联系,与场景深度无关。同样 \(A\) 零空间三维,且根本没有深度信息可恢复。
    • 小基线、远场景:不是严格退化,但接近纯旋转,平移方向的噪声极大(FIG 5)。
    • 临界曲面:所有点恰好在一个过两个光心的直纹二次曲面上时,也有多解(Hartley & Zisserman 第 22 章)。实际场景里很少碰到,但"近似平面"很常见。

    最小求解器

    要估计 5 个自由度的 \(E\),最少 5 对匹配:Nistér(2004)的 5 点算法,解一个 10 次多项式,最多 10 个实解,已知内参时用它,因为样本少,RANSAC(11.5 节)迭代次数少得多:5 个点全是内点的概率是 \(w^5\),8 个点是 \(w^8\),\(w=0.5\) 时相差 8 倍。7 点算法利用 \(\det F=0\) 解三次方程,最多 3 个解。8 点算法是线性的,用于点多且干净的情形,或者作为 RANSAC 的内点上的最终精化。OpenCV 里 findEssentialMat 用 5 点加 RANSAC,findFundamentalMat 提供 7 点和 8 点。

    6机器人中的它:单目初始化为什么要等视差

    单目 SLAM / 视觉里程计启动时没有地图。典型做法(ORB-SLAM 等):取第一帧作参考,等相机移动到足够"远",再用这对帧估计 \(F\) 或 \(H\),恢复 \((R,\mathbf t)\) 并三角化初始地图。为什么要等?FIG 5 用蒙特卡洛给出答案:同样的噪声,横向基线与场景深度之比 \(\rho\)(视差)越小,平移方向的误差越大。\(\rho\) 很小时,两张图几乎只差一个旋转,数据里的"平移信号"被噪声淹没,E 接近纯旋转的退化。旋转本身仍估计得不错,所以 VO 在小位移时可以靠别的传感器(IMU)保持姿态,却无法得到好的平移方向。

    FIG 5 中,每个点是 20 次独立噪声重抽后的中位数,每次都完整运行 8 点估计 E、四个候选分解和手性投票。顶部是对应的俯视图:两个相机(楔形是视场)、场景深度带,以及参考点处的视差角 \(\alpha\)(前向运动时,视差角在运动方向上为零,随偏离方向的角度增大)。切换到"向前移动":前向运动同样的 \(\rho\) 下平移方向通常更准,因为极点落在图内,所有极线在图内辐射。但前向运动有它自己的问题:视差集中在图像边缘,光轴附近几乎没有视差。

    FIG 5视差决定能恢复多准
    俯视图(x 右,z 前)
    右图的两条曲线是平移方向误差(琥珀)与旋转误差(蓝),纵轴为对数;大圆点是当前滑块位置。基线 \(=6\rho\) m,横向时相机 2 稍向内转以注视场景中心。每个点用 N 个匹配、\(\sigma\) 像素噪声的 20 次独立实验。读数里的"投票选对候选"是手性检验选中真值候选的比例;视差角太小时,孪生对的深度符号几乎相同,投票就不再可靠。
    试一试
    • 保持"横向移动",把 \(\rho\) 拉到 0.04 以下:平移方向误差超过 20°,而旋转误差仍只有一两度。增大 N 或减小 \(\sigma\) 能把曲线整体压低,但"小基线很难"这条规律不变。
    真实系统里

    SLAM 初始化:ORB-SLAM(Mur-Artal 等,2015)并行估计单应 \(H\)(平面或低视差场景)与基础矩阵 \(F\)(一般场景),用一个基于打分的启发式选其一,再恢复运动并三角化;视差不够时拒绝初始化继续等。SfM:COLMAP(Schönberger & Frahm,2016)对每对图像估计 \(E\)、\(F\)、\(H\),据内点情况把这对图像分类(例如一般、纯旋转/全景、平面),再进入增量式重建与束调整。OpenCV:findEssentialMat(5 点 + RANSAC)、recoverPose(分解 E 并做手性检验)、findFundamentalMat、stereoRectify(11.2 节)。学习式方法:SuperGlue、LoFTR 等学习的匹配器给出更多更可靠的对应点,之后仍然要用对极几何做几何验证(11.5 节);DUSt3R(Wang 等,2024)一类的方法直接从图像对回归出点图,不需要显式的 \(E\)。其他:极线约束把立体匹配和多视图注意力从二维搜索降为沿线的一维,一些多视图 Transformer 与 NeRF/3DGS 的前馈重建方法就沿极线采样特征(12.4 节指路)。

    7常见误区

    误区 1:以为 \(\|\mathbf t\|=1\) 就是 1 米

    对极方程对 \(\mathbf t\) 的任意缩放不变,所以只能恢复平移的方向,分解给出的单位向量只是约定。在 FIG 4 里放大整个世界,所有像素原封不动。后果在系统层面:单目 VO 的轨迹只有相似变换意义下的形状;把两对相邻帧的结果串起来时,每一对的尺度都是任意的,需要用共同观测的三维点把尺度对齐,而对齐误差会累积成尺度漂移。度量尺度必须从外部引入:双目基线、IMU、轮速计、已知大小的物体(如 AprilTag)、深度传感器。

    误区 2:平面场景和纯旋转看起来"很好估计"

    平面墙、地面、桌面上有大量好匹配,残差也很小,可 8 点算法返回的 \(F\) 在一个三维族里随噪声乱跳(FIG 3 的"平面场景":拟合很好,留出误差很大,极点漂移)。机器人偏偏常常对着地面看(移动机器人、无人机的下视相机)。检查办法:看 \(A\) 的奇异值有没有出现三个同样小的,或者同时估计单应、比较内点数(ORB-SLAM、COLMAP 都这样做)。纯旋转同理,而且根本没有深度可言:全景拼接可以靠 \(H_\infty\),但三角化不出任何点。

    误区 3:无噪声的单元测试通过了,所以代码是对的

    没有噪声时,带不带归一化、带不带秩 2 约束都能把残差压到 \(10^{-13}\),测试全绿。真实数据里差别立刻出现:FIG 3 中不归一化的误差通常是归一化的两倍以上。再加上极线约束只是必要条件:落在极线上的任何一点都通过检验,重复纹理会沿线匹配错;一个运动的物体,只要它在对极平面里移动(例如与相机平行行驶的汽车),也满足约束;一个明显错的匹配会把最小二乘拖偏。所以真实流程里总是 RANSAC + 归一化 8 点 / 5 点(11.5 节),再用 Sampson 误差挑内点。

    误区 4:E 与 F 混用,或对 F 加"奇异值相等"

    \(E\) 只对归一化坐标成立,把像素直接放进 8 点算法再去做 SVD 分解,得到的"\(R\)"不是旋转。\(F\) 的奇异值通常相差一个数量级以上(FIG 3 的真值 \(F\):第二奇异值约为第一个的 0.04 倍),它只要求秩 2,强行把 \(F\) 的前两个奇异值设成相等会毁掉它。\(E=K_2^{\top}FK_1\) 要用正确的 \(K\):内参不准或没去畸变(10.3 节)时,得到的 \(E\) 的前两个奇异值就不再相等,这本身是检验标定质量的一个指标。

    误区 5:位姿方向与符号约定搞反

    \(\mathbf X_2=R\mathbf X_1+\mathbf t\):\((R,\mathbf t)\) 把相机 1 系的坐标变到相机 2 系("外参"方向),\(\mathbf t\) 是相机 1 光心在相机 2 系中的坐标,不是相机 2 的位置,相机 2 在相机 1 系的位置是 \(-R^{\top}\mathbf t\)。把 \(E\) 拿来用之前,要确认第一个点集属于哪张图:交换两张图得到 \(E^{\top}\),对应的位姿是 \((R^{\top},-R^{\top}\mathbf t)\)。另外 \(\pm\mathbf t\) 的符号只有手性检验能定,千万不要凭"相机应该往前走"硬选。把解算结果串进 SLAM 的位姿图时,要把它换成 \({}^{w}T_{c}\) 的形式,别直接拿去乘。

    8小练习

    1. 相机 2 相对相机 1 沿 x 方向平移,没有旋转:\(R=I\),\(\mathbf t=(2,0,0)^{\top}\)。归一化点 \(\hat{\mathbf x}_1=(0.3,\,0.5,\,1)^{\top}\) 在图 2 里的极线是什么?(手算 \(E=[\mathbf t]_\times\) 再算 \(E\hat{\mathbf x}_1\)。)
    \([\mathbf t]_\times=\begin{bmatrix}0&0&0\\0&0&-2\\0&2&0\end{bmatrix}\),\(E=[\mathbf t]_\times\),\(E\hat{\mathbf x}_1=(0,\,-2,\,1)^{\top}\),即 \(-2y+1=0\),\(y=0.5\)。左右并排、方向一致的两个相机,极线就是同一行:这是校正后双目的构型,视差只沿 x 方向(11.2 节)。
    2. 本质矩阵 \(E\) 与基础矩阵 \(F\)(都只确定到整体尺度)各有多少个自由度?
    E:旋转 3 + 平移方向 2 = 5(平移的长度不可观)。F:9 − 1(尺度)− 1(\(\det F=0\))= 7。E 还额外要求两个奇异值相等,这是 F 没有的约束,多出的 2 个约束就是内参带来的信息。
    3. 对一对真实匹配,在 \(E\) 分解出的四个候选下三角化,深度符号 \((\lambda_1,\lambda_2)\) 分别是 \((+,+)\)、\((-,-)\)、\((+,-)\)、\((-,+)\)。哪一个候选是真实运动?
    四个候选对对极方程同样成立,数据本身分辨不了,只有"点必须在相机前面"这条物理事实能挑出 \((+,+)\)。\((R,-\mathbf t)\) 给出 \((-,-)\);孪生对(绕基线转 180°的另一个旋转)给出异号的 \((+,-)\) 或 \((-,+)\)。实际中对所有匹配投票(FIG 4)。
    4. 有人把整个世界(场景和相机运动)都放大 2 倍,然后重新拍摄这两张图。下面哪个结论对?
    针孔投影是 \(\tilde{\mathbf x}\sim K[R|\mathbf t]\tilde{\mathbf X}\),\(\mathbf X\) 与 \(\mathbf t\) 同乘 2,像素不变;\(E=[\mathbf t]_\times R\) 变成 \(2E\),而对极方程 \(\hat{\mathbf x}_2^{\top}E\hat{\mathbf x}_1=0\) 对整体比例不敏感。所以单目只能恢复到相似变换,旋转不受影响(FIG 4 的尺度滑块)。
    5. 手持相机原地转动(\(\mathbf t=\mathbf 0\),只有 \(R\)),拍两张图,匹配 200 对,运行 8 点算法。会发生什么?
    纯旋转时所有匹配满足 \(\tilde{\mathbf x}_2\sim H\tilde{\mathbf x}_1\),于是任何 \([\mathbf e]_\times H\) 都满足对极方程,\(E=0\) 不含信息。增加匹配数没有用(FIG 3 的"纯旋转":σ₇ σ₈ σ₉ 同样小,极点乱跳)。应当估计单应;只有单应解释不了数据时,才继续估计 \(F\)。

    9延伸阅读

    • R. Hartley & A. Zisserman, Multiple View Geometry in Computer Vision, 2nd ed. (Cambridge University Press, 2004), Ch. 9–11 — 对极几何与基础矩阵、相机与结构的三维重建、基础矩阵的估计(含 8 点、7 点与归一化)
    • H. C. Longuet-Higgins, A computer algorithm for reconstructing a scene from two projections, Nature 293, 133–135, 1981 — 本质矩阵与 8 点算法的出处
    • R. Hartley, In defense of the eight-point algorithm, IEEE Trans. PAMI 19(6):580–593, 1997 — 说明坐标归一化让 8 点算法变得可用
    • D. Nistér, An efficient solution to the five-point relative pose problem, IEEE Trans. PAMI 26(6):756–770, 2004 — 已知内参时 5 点估计 E(最多 10 个解)
    • Y. Ma, S. Soatto, J. Košecká & S. S. Sastry, An Invitation to 3-D Vision (Springer, 2004), Ch. 5 — 两个标定视图的重建:本质矩阵、4 个解与手性约束
    • T. S. Huang & O. D. Faugeras, Some properties of the E matrix in two-view motion estimation, IEEE Trans. PAMI 11(12):1310–1312, 1989 — 本质矩阵的充要条件(秩 2 且两个非零奇异值相等)
    • R. Mur-Artal, J. M. M. Montiel & J. D. Tardós, ORB-SLAM: A versatile and accurate monocular SLAM system, IEEE T-RO 31(5):1147–1163, 2015 — 单目初始化中 \(H\) 与 \(F\) 的模型选择
    • J. L. Schönberger & J.-M. Frahm, Structure-from-Motion Revisited, CVPR 2016 — COLMAP:两视图几何验证与增量式 SfM