Part III · 第 10 章 相机与投影 · 10.5

单应性 Homography

同一块平面被两台相机看到(或一台相机看地面、机器人走了一步),两幅图像之间只差一个 3×3 矩阵:单应性。四个点对就能解出它,于是有了地面鸟瞰图、全景拼接、AprilTag 位姿、文档矫正和 10.4 节的平面标定。它只对平面(或纯旋转)成立:平面之外的一切都会出现视差,而这恰好是检测障碍物的线索。

约 35 分钟 前置:1.6 秩与零空间 · 1.12 SVD · 1.13 最小二乘 · 5.3 SE(3) · 10.1 针孔模型 · 10.2 射影几何 · 10.3 内参与外参 5 个交互

    1为什么机器人需要它

    相机把三维世界压成二维图像,深度丢了,一般无法反过来。但有一种特殊情形,反过来完全没有歧义:被看的点都落在同一个平面上。地面、桌面、墙、棋盘格、一页文档、AprilTag 的黑白方块,都是平面。同一个平面被两台相机拍到,两幅图像里对应点之间的关系就是一个 3×3 矩阵 \(H\):\(\lambda\tilde{\mathbf x}'=H\tilde{\mathbf x}\),这个矩阵叫单应性(homography)。

    另一种同样"免费"的情形是相机只转动、不平移(原地环顾、云台转动、手机拍全景)。这时场景有多深都无所谓,两幅图像也只差一个单应性。这个 3×3 矩阵撑起了机器人视觉里一长串应用:

    • 鸟瞰图(逆透视映射):把前视相机的地面像素映成俯视的度量地图,用于车道线、AMR 导航和可通行区域(FIG 5);
    • 障碍物检测:地面上的像素服从 \(H\),不服从的就是"高出地面"的东西(FIG 2);
    • 全景拼接:旋转相机拍的多张图合成一张(FIG 3);
    • 平面标记的位姿:AprilTag / ArUco 的四个角点 → \(H\) → 标记相对相机的位姿;文档与白板的矫正也是同一件事;
    • 平面标定:10.4 节中每张棋盘格照片给出一个 \(H\),Zhang 方法从多个 \(H\) 里解出内参 \(K\);
    • SLAM 初始化:场景接近平面或相机几乎纯旋转时,对极几何(11.1 节)退化,要改用 \(H\)。

    本节先用四个手柄建立直觉(FIG 1),看 DLT 如何从四个点对解出矩阵;再从几何推出 \(H=K'(R+\mathbf t\mathbf n\T/d)K^{-1}\) 并让平面之外的点"露馅"(FIG 2);然后看纯旋转(FIG 3)、噪声与归一化(FIG 4);最后在一个合成的公路场景上做鸟瞰图(FIG 5)。

    2直觉:拖四个角,矩阵自己出来

    想象把一张印好的图平放在桌上,从斜上方拍照:矩形变成了梯形,近大远小,直线仍是直线,平行线却可能汇聚。左图是原图,右图是你"拍到"的样子。拖动右图的四个角,每个角对应原图的一个角。四个点对 \((\mathbf x_i\mapsto\mathbf x_i')\) 恰好够解一个 \(H\):每个点对给两个方程,\(H\) 有 9 个元素,但整体乘一个常数不改变映射,只剩 8 个自由度,\(4\times2=8\)。页面上每一帧都在运行真正的 DLT 算法(见下面的数学部分),再用 \(H^{-1}\) 反向映射每个输出像素到原图并做双线性采样,得到右图。

    注意 \(H\) 的列有几何意义:第 1、2 列是原图 \(x\) 轴、\(y\) 轴方向无穷远点的像,也就是消失点(10.2 节);第 3 列是原点的像。当四边形变成平行四边形,\(H\) 的最后一行变成 \((0,0,1)\),消失点跑到无穷远,映射退化为仿射。

    FIG 1拖四个角:DLT 实时求 \(H\) 并扭曲图像
    原图 (x, y)
    拖动 ①②③④ → 扭曲后 (x′, y′)
    左右两幅图的像素坐标都是 \(v\) 向下的图像坐标。琥珀色手柄是 \(\mathbf x_i'\),DLT 用 \(\mathbf x_i=\) 原图四个角、\(\mathbf x_i'=\) 手柄位置解出 \(H\);青色虚线把原图上下边、左右边延长到消失点。手柄靠近"三点共线"或"平行四边形"位置时会轻微吸附。
    试一试
    • 把上边两个角往中间收,做出"梯形"(像远处的墙)。读出 \(w\) 比值和消失点,棋盘格的横线怎样汇聚?
    • 把四边形拖成平行四边形(吸附会帮你)。\(h_{31},h_{32}\) 变成什么?平行线现在还平行吗?
    • 把三个角拖到一条直线上(会吸附)。\(H\) 的奇异值比 \(\sigma_3/\sigma_1\) 发生了什么?图像为什么消失了?
    核心洞见

    单应性是一个8 自由度的射影变换:直线保持为直线,但长度、角度、平行都不保持。四个点对(任意三点不共线)刚好定出它。若目标点里有三点共线而源点不共线,就不存在可逆的 \(H\)(DLT 给出的矩阵是奇异的,整幅图被压成一条线);若三点在两幅图里都共线,方程只剩 7 个独立的,\(H\) 不再唯一。

    3实验:平面诱导的单应性与视差

    FIG 1 里的 \(H\) 是"拟合"出来的。真实的相机对里,它由几何完全决定。设相机 1 坐标系中有平面 \(\mathbf n\T\mathbf X_1=d\)(\(\mathbf n\) 单位法向,\(d\) 是相机 1 光心到平面的距离),相机 2 与相机 1 的关系为 \(\mathbf X_2=R\mathbf X_1+\mathbf t\)。则(见下面的数学部分) $$H=K'\Big(R+\frac{\hl{t}{\mathbf t}\,\hl{n}{\mathbf n}\T}{\hl{d}{d}}\Big)K^{-1}.$$ 下面的实验里,相机 1、2 看着一块平面(可以倾斜),平面中心立着一根杆。你可以移动相机 2、倾斜平面、改变杆高,页面做三件事:用上面的公式由几何算出 \(H\);用平面上 25 个点的投影,用 DLT 独立解出 \(H\);然后用 \(H\) 把相机 1 的点搬到相机 2。平面上的点严丝合缝(误差 \(10^{-12}\) 像素量级);杆顶不在平面上,被 \(H\) 搬到的位置是错的,这个误差就是视差。

    几何解释在 3D 视图里:\(H\) 把相机 1 的射线"压"到平面上,再从相机 2 看这个平面点。杆顶的射线先落在平面的 \(\mathbf Q\)(紫色),\(H\) 预测相机 2 在 \(\mathbf Q\) 的位置看到杆顶,而真正的杆顶在别处。这就是"地面单应性残差"检测障碍物的原理:地面像素残差为零,高出地面的物体残差正比于高度和基线。

    FIG 2平面诱导的单应性:公式 vs DLT,以及杆顶的视差
    图像 1
    图像 2:实线 = 真实,紫色 = H 的预测
    蓝色锥体 = 相机 1,绿色锥体 = 相机 2(光心、像平面)。青色网格是平面,琥珀色是杆。紫色点 \(\mathbf Q\) 是相机 1 经过杆顶的射线与平面的交点。图像 2 中紫色虚线网格是用 \(H\) 搬运图像 1 平面点的结果,与青色实线重合;紫色圆圈是 \(H\) 对杆顶的预测,红线是视差残差。图像坐标 \(v\) 向下。
    试一试
    • 移动相机 2 的方位角、再把平面倾斜 25° 以上。\(\mathbf n,d\) 和 \(H\) 都变了,"公式 − DLT"误差仍是 \(10^{-12}\) 量级吗?
    • 把杆升高到 0.6 m 以上,杆顶残差超过 3 px,被标成"不在平面上"。再把杆高降到 0,残差消失。
    • 把相机 2 的方位角调到 −25°、高度调到 2.8 m(与相机 1 重合),杆保持高度。基线 \(\|\mathbf t\|\to0\),视差为什么也消失了?
    同一个想法的三个视角

    几何:\(H\) 是"先把射线落到平面上,再从另一台相机看"。代数:\(R+\mathbf t\mathbf n\T/d\) 在平面上等于 \(R\mathbf X+\mathbf t\),平面外多出 \(\mathbf t(1-d'/d)\)。信息:\(H\) 里的深度信息被平面方程"吃掉"了,所以只要深度不起作用——平面,或 \(\mathbf t=0\)——一个 3×3 矩阵就够。这正是 FIG 3 的纯旋转。

    4另外两个视角:纯旋转与噪声

    纯旋转:对任何场景都成立

    让 \(\mathbf t=\mathbf 0\),公式里的 \(\mathbf t\mathbf n\T/d\) 整项消失:\(H=K'RK^{-1}\),\(\mathbf n\) 和 \(d\) 都不出现,场景可以是任意的三维结构。直观地说,绕光心旋转时每条射线只是转了个方向,物体多远都沿同一条射线成像。下面的场景里有 60 个深度从 3 m 到 25 m 的点。滑块让相机绕竖直轴转 \(\theta\),并(或不)向右平移 \(t_x\)。紫色圆圈是用 DLT 在所有点上拟合的最优单应性的预测;纯旋转时它与真实点重合,哪怕深度差了 8 倍;一旦平移,近处的点移动得更多(\(\approx f\,t_x/Z\)),任何一个 \(H\) 都解释不了。

    反过来,由 \(H\) 还能读出旋转:\(R=K^{-1}HK\)(先把 \(H\) 乘上 \(\det^{-1/3}\) 使 \(\det=1\)),再用 \(\theta=\arccos\frac{\operatorname{tr}R-1}2\) 或 5.6 节的 \(\Log\)。全景拼接就是这样估计相邻图像的相对旋转的(Brown–Lowe,2007)。

    FIG 3纯旋转 vs 平移:谁能被单应性解释
    图像 1(颜色 = 深度)
    图像 2:实心 = 真实,圆圈 = 最优 H
    琥珀色 = 近(\(Z\lt6\) m),紫色 = 中,青色 = 远(\(Z\ge12\) m)。红线从圆圈连到真实点,长度就是该点的残差。只统计同时出现在两幅图内的点。读数里"最优 \(H\) 残差"是 DLT 拟合后的最大值;"已知 \(R\) 的 \(K R K^{-1}\)"则完全不拟合,直接用真实旋转算。
    试一试
    • 选"纯旋转 15°"。残差是否是 \(10^{-10}\) 量级?读数里恢复出的角度对吗?再换一个角度试。
    • 选"纯平移 0.6 m"。谁的残差大,近点还是远点?此时从 \(H\) 里"恢复"的旋转还是旋转矩阵吗(看正交性误差)?

    带噪声的 DLT:归一化、点数与分布

    真实数据有噪声,点数多于 4,还有错配。下面把图像 2 中的点加上高斯噪声 \(\sigma\),分别用Hartley 归一化的 DLT(青色)和直接用像素坐标的 DLT(红色)估计 \(H\),用整幅 640×480 图像上一个 9×7 测试网格上的均方根误差(灰色是真值)评价。有三个旋钮:点数、点占图像的比例("分布")、噪声。要看到的现象是:点铺满图像时两者差不多;点挤在一个小区域且离坐标原点很远时,未归一化的 DLT 条件数 \(\kappa(A)\) 暴涨,误差大一个数量级;而不论哪个,外推到没有点的区域都是危险的。"加外点"按钮把个别点偏移 50 像素量级,最小二乘立刻被拖偏;"RANSAC"用 4 点采样、重复拟合找出内点(11.5 节详细讲)。

    FIG 4带噪声的 DLT:归一化 vs 未归一化
    图像 2(640×480)
    测试网格误差 vs 分布
    灰色 = 真实 \(H\) 搬运的网格,青色 = 归一化 DLT,红色 = 未归一化 DLT。琥珀色点是带噪声的 \(\mathbf x_i'\),红色圆环是外点,空心圆环外加绿色勾边表示 RANSAC 保留的内点。右图是当前点数和噪声下 15 次随机试验的中位数误差,竖线是当前分布。
    试一试
    • 把"分布"拉到 25% 以下。两种 DLT 的误差差几倍?\(\kappa(A)\) 差几个数量级?再多加点数,误差能救回来吗?
    • 点"加外点"三次,看最小二乘的网格被拖偏;切到 RANSAC,误差降到最小二乘误差的五分之一以下,回到读数里"去掉外点"的量级。

    5数学

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

    单应性是什么:8 个自由度

    用 10.2 节的齐次坐标 \(\tilde{\mathbf x}=(x,y,1)\T\),单应性是一个可逆的 3×3 矩阵作用在 \(\mathbb P^2\) 上:

    $$ \lambda\,\tilde{\mathbf x}'=H\tilde{\mathbf x},\qquad x'=\frac{h_{11}x+h_{12}y+h_{13}}{h_{31}x+h_{32}y+h_{33}},\quad y'=\frac{h_{21}x+h_{22}y+h_{23}}{h_{31}x+h_{32}y+h_{33}} $$

    \(cH\)(\(c\neq0\))给出同一个映射,所以 9 个元素只有 8 个自由度,每个点对提供 2 个方程,至少 4 个点对。分母 \(w=h_{31}x+h_{32}y+h_{33}\) 就是 FIG 1 里的"\(w\) 比值",除以 \(w\) 这一步让映射成为非线性的。\(H\) 的最后一行为 \((0,0,1)\) 时是仿射(6 个自由度,3 个点对,平行线保持平行);再要求左上 2×2 是旋转乘缩放时是相似变换(4 个自由度,2 个点对)。复合就是矩阵乘法:\(H_{13}=H_{23}H_{12}\),反向是 \(H^{-1}\)。

    直接线性变换(DLT)

    \(\lambda\) 未知,所以不写 \(\tilde{\mathbf x}'=H\tilde{\mathbf x}\),而写"两个向量平行":\(\tilde{\mathbf x}'\times H\tilde{\mathbf x}=\mathbf 0\)(叉积 1.8 节)。记 \(\tilde{\mathbf x}'=(u',v',1)\T\),\(H\) 的三行为 \(\mathbf h_1\T,\mathbf h_2\T,\mathbf h_3\T\),展开:

    $$ \tilde{\mathbf x}'\times H\tilde{\mathbf x}=\begin{bmatrix} v'\,\mathbf h_3\T\tilde{\mathbf x}-\mathbf h_2\T\tilde{\mathbf x}\\ \mathbf h_1\T\tilde{\mathbf x}-u'\,\mathbf h_3\T\tilde{\mathbf x}\\ u'\,\mathbf h_2\T\tilde{\mathbf x}-v'\,\mathbf h_1\T\tilde{\mathbf x}\end{bmatrix}=\mathbf 0 \;\Longrightarrow\; \underbrace{\begin{bmatrix}-\tilde{\mathbf x}\T&\mathbf 0\T&u'\tilde{\mathbf x}\T\\ \mathbf 0\T&-\tilde{\mathbf x}\T&v'\tilde{\mathbf x}\T\end{bmatrix}}_{A_i\ \in\ \R^{2\times9}}\underbrace{\begin{bmatrix}\mathbf h_1\\\mathbf h_2\\\mathbf h_3\end{bmatrix}}_{\mathbf h\ \in\ \R^9}=\mathbf 0 $$

    第三行等于前两行的线性组合(\(u'\)×第一行 + \(v'\)×第二行 \(=-\)第三行),所以每个点对只有 2 个独立方程,这就是"8 = 4×2"。把 \(n\) 个点对的 \(A_i\) 叠成 \(A\in\R^{2n\times9}\):\(A\mathbf h=\mathbf 0\)。恰好 4 个点(任意三点不共线)时 \(A\) 秩为 8,零空间(1.6 节)是一维的,\(\mathbf h\) 唯一(相差一个常数);\(n>4\) 时方程无精确解,取

    $$ \hat{\mathbf h}=\arg\min_{\|\mathbf h\|=1}\|A\mathbf h\|^2=\ \text{the right singular vector of }A\text{ for the smallest }\sigma. $$

    (1.12 节的 SVD。)若三点在两幅图里都共线,\(A\) 的秩降到 7,\(\sigma_8\approx0\),零空间多出一维,\(H\) 不唯一;只在一幅图里共线时 \(A\) 仍满秩,但解出的 \(H\) 是奇异的(FIG 1 读数里的 \(\sigma_3(H)/\sigma_1(H)\))。\(\|A\mathbf h\|\) 叫代数误差,它没有几何含义,只是方便;本节末尾会回到几何误差。

    Hartley 归一化:为什么先挪动坐标

    像素坐标在百的量级,\(A\) 的一行里同时出现 \(1\)、\(x\sim10^2\)、\(u'x\sim10^4\) 三种尺度,\(\kappa(A)\) 高达 \(10^6\) 以上,SVD 的最小奇异向量对噪声极其敏感(FIG 4 读数)。办法:对两幅图各做一次相似变换 \(T,T'\)——平移使质心在原点,缩放使到原点的平均距离是 \(\sqrt2\)——在归一化坐标里解出 \(\hat H\),再换回来:

    $$ T=\begin{bmatrix}s&0&-s\,c_x\\0&s&-s\,c_y\\0&0&1\end{bmatrix},\quad s=\frac{\sqrt2}{\bar d},\qquad \tilde{\mathbf x}\to T\tilde{\mathbf x},\ \ \tilde{\mathbf x}'\to T'\tilde{\mathbf x}',\qquad H=T'^{-1}\hat H\,T. $$

    它不增加点数,也不改变理想数据的解(4 个无噪声点时两种 DLT 一样准),只改善条件数,代价是几行代码。Hartley(1997)为八点算法提出,同一思想适用于所有 DLT。

    平面诱导的单应性的推导

    相机 2 的坐标 \(\mathbf X_2=R\mathbf X_1+\mathbf t\)(与 5.3 节一致:\(R,\mathbf t\) 是相机 1 → 相机 2 的相对位姿),平面 \(\mathbf n\T\mathbf X_1=d\),\(\mathbf n\) 是相机 1 坐标系里的单位法向,\(d>0\)。平面上的点满足 \(\mathbf n\T\mathbf X_1/d=1\),所以可以把 \(\mathbf t\) 乘上这个"1":

    $$ \mathbf X_2=R\mathbf X_1+\mathbf t\,\frac{\mathbf n\T\mathbf X_1}{d}=\Big(R+\frac{\mathbf t\,\mathbf n\T}{d}\Big)\mathbf X_1,\qquad \tilde{\mathbf x}_i\sim K_i\mathbf X_i $$ $$ \Longrightarrow\quad \boxed{H=K'\Big(R+\frac{\mathbf t\,\mathbf n\T}{d}\Big)K^{-1}} $$

    用的是 \(\mathbf X_1=\lambda K^{-1}\tilde{\mathbf x}_1\),\(\lambda\) 被"\(\sim\)"吞掉了。几点说明。

    • 符号:这里平面写成 \(\mathbf n\T\mathbf X=d\),所以是加号。Hartley–Zisserman 把平面写成 \(\mathbf n\T\mathbf X+d=0\),得到 \(R-\mathbf t\mathbf n\T/d\)。FIG 2 对加号做了数值验证;换号会差几百像素。
    • 只出现 \(\mathbf t/d\):把整个场景和基线同时放大 2 倍,\(H\) 不变,这就是单目的尺度不确定。
    • 欧氏单应性:\(K'^{-1}HK=R+\mathbf t\mathbf n\T/d\) 只含运动与平面。分解它可得 \((R,\mathbf t/d,\mathbf n)\),一般有至多 4 组数学解,要求点在两个相机前方后通常剩 2 组,第三个视角或已知法向再消歧(Malis–Vargas 2007;OpenCV 的 decomposeHomographyMat)。
    • 平面外的点:若 \(\mathbf n\T\mathbf X_1=d'\neq d\),则 \(\mathbf X_2=(R+\mathbf t\mathbf n\T/d)\mathbf X_1+\mathbf t\,(1-d'/d)\)。多出来的 \(\mathbf t(1-d'/d)\) 就是视差:正比于基线 \(\mathbf t\) 和"离平面有多远",方向沿着极线(指向极点,11.1 节)。\(\mathbf t=\mathbf 0\) 时为零。

    三个特例:纯旋转、地面 \(z=0\)、平面目标的位姿

    $$ \underbrace{H_\infty=K'RK^{-1}}_{\mathbf t=\mathbf 0\ (\text{or } d\to\infty)},\qquad \underbrace{\lambda\tilde{\mathbf x}=K\,[\,\mathbf r_1\ \ \mathbf r_2\ \ \mathbf t\,]\,(X,Y,1)\T}_{\text{the world plane }Z=0,\ \ \tilde{\mathbf x}\sim H_g\,(X,Y,1)\T},\qquad H_g=K[\mathbf r_1\ \mathbf r_2\ \mathbf t]. $$

    纯旋转:\(d\to\infty\)(平面在无穷远)与 \(\mathbf t=\mathbf 0\) 效果相同,\(H_\infty=K'RK^{-1}\)。相机绕光心转 \(\theta\),\(K\) 相同时,图像中心移动约 \(f\tan\theta\) 像素(小角时 \(\approx f\theta\)),与深度无关。地面:世界平面 \(Z=0\) 上的点 \(\mathbf X=(X,Y,0)\),\(\mathbf x_c=R\mathbf X+\mathbf t=\mathbf r_1X+\mathbf r_2Y+\mathbf t\),\(R\) 的第三列 \(\mathbf r_3\) 乘 0 消失,所以 \(H_g=K[\mathbf r_1\ \mathbf r_2\ \mathbf t]\),这里 \((R,\mathbf t)\) 是世界 → 相机的外参 \({}^cT_w\)(10.3 节)。对高 \(h\)、俯仰角 \(\alpha\) 向前看的相机(世界 \(X\) 向右、\(Y\) 向前、\(Z\) 向上):

    $$ H_g=K\begin{bmatrix}1&0&0\\0&-\sin\alpha&h\cos\alpha\\0&\cos\alpha&h\sin\alpha\end{bmatrix} $$ $$ u=c_x+\frac{f\,X}{Y\cos\alpha+h\sin\alpha},\qquad v=c_y+\frac{f\,(h\cos\alpha-Y\sin\alpha)}{Y\cos\alpha+h\sin\alpha}. $$

    \(Y\to\infty\) 得到地平线 \(v=c_y-f\tan\alpha\)。反过来,从 \(H\) 求相机位姿(平面目标的位姿,AprilTag 与 10.4 节标定的第一步):\(K^{-1}H_g\propto[\mathbf r_1\ \mathbf r_2\ \mathbf t]\),取 \(\lambda=1/\|K^{-1}\mathbf h_1\|\) 使 \(\mathbf r_1\) 为单位向量,\(\mathbf r_3=\mathbf r_1\times\mathbf r_2\),再用 SVD 把 \([\mathbf r_1\ \mathbf r_2\ \mathbf r_3]\) 投影到最近的旋转矩阵(\(R=UV\T\),1.12 节),选符号使 \(t_z>0\)(目标在相机前方)。FIG 5 的读数用 4 个点的 DLT 恢复出相机的高度和俯仰角,就是这一段。有噪声时更好的做法是 PnP(11.4 节)或迭代优化。

    误差:代数、几何与最大似然

    DLT 最小化的 \(\|A\mathbf h\|\) 是代数量。真正想要的是像素误差。转移误差 \(\sum_i\|\mathbf x_i'-\pi(H\tilde{\mathbf x}_i)\|^2\)(\(\pi\) 是除以 \(w\))只算图像 2 的误差;对称转移误差再加上 \(\|\mathbf x_i-\pi(H^{-1}\tilde{\mathbf x}_i')\|^2\);若两幅图的点都有噪声,最大似然是重投影误差:同时估计 \(H\) 和精确点 \(\hat{\mathbf x}_i,\hat{\mathbf x}_i'\)(Sampson 距离是它的一阶近似)。后两种是非线性最小二乘,用 6.6、6.9 节的高斯–牛顿 / LM,初值取 DLT 结果。OpenCV 的 findHomography 在 RANSAC 之后也会在内点上做 LM 精化。

    6在机器人里:鸟瞰图(逆透视映射)

    前视相机在路上看到的车道线汇聚到消失点,这对"在地图上走多远、车道多宽"毫无帮助。如果假设地面是平面,则 \(H_g\) 把地面坐标 \((X,Y)\)(米)映到像素,它的逆 \(H_g^{-1}\) 把每个像素映回地面米制坐标。对鸟瞰图的每个输出像素 \((X,Y)\),用 \(H_g\) 找到它在相机图像中的位置采样,就得到一张俯视的度量图:车道线平行、宽度恒为 3.5 m、距离刻度均匀。这就是反向映射(输出 → 输入),不会留下空洞。下面是一个合成的两车道公路(所有像素由射线与地面求交渲染),相机高 \(h\)、俯仰 \(\alpha\) 可调。\(H_g\) 有两种来源:公式 \(K[\mathbf r_1\ \mathbf r_2\ \mathbf t]\)(已知安装高度和俯仰),或者四个手柄:在图中点出地面已知矩形(车道线与两条横向标线的交点,3.5 m × 10 m)的四个角,用 DLT 求 \(H\),这是没有标定数据时的做法。

    但这只对地面上的东西成立。高出地面的物体(琥珀色箱子)违反了平面假设:射线穿过它的顶部,落在地面上更远的位置,于是箱子被沿着视线方向拖长。侧视图里的相似三角形给出顶端落点 \(d'=d\,\dfrac{h}{h-z_b}\)(\(d\) 是水平距离,\(z_b\) 是高度)。

    FIG 5鸟瞰图:由地面单应性做逆透视映射
    前视相机图像 (u, v)
    侧视图(竖直方向拉伸):为什么箱子被拖长
    鸟瞰图(米制,0.1 m/像素)
    "4 点"模式下,把相机图里的四个琥珀色手柄点在矩形角上(对应地面坐标 \((\pm1.75,5)\)、\((\pm1.75,15)\) m);初始位置是取整到像素的真实投影,拖离它就像点错了。拖动相机高度或俯仰会让手柄重新回到真实位置。鸟瞰图里的虚线框是箱子的真实占地,被拖长的琥珀色区域就是违反平面假设的后果。
    试一试
    • 把箱子高度升到 0.8 m 以上。侧视图里顶端射线落在哪里?读数里的 \(d'\) 与鸟瞰图里的拖长对得上吗?
    • 切到"4 点",把一个手柄拖离 15 像素以上。车道线还平行吗?读数里的车道宽度、恢复出的高度和俯仰变成多少?
    真实系统里

    OpenCV:getPerspectiveTransform(4 点 → \(H\))、findHomography(DLT + RANSAC / LMEDS / RHO,并做 LM 精化)、warpPerspective(反向映射 + 插值)、decomposeHomographyMat。AprilTag / ArUco:从标签的四个角点估计 \(H\),再恢复标签位姿(AprilTag 的参考实现里就有"由单应性求位姿"的步骤,OpenCV 的 ArUco 则常用平面 PnP,11.4 节)。车道线与可通行区域:车载和 AMR 的经典做法是 IPM 鸟瞰图;端到端的自动驾驶栈如今多用学习的 BEV 表示(如 Lift-Splat-Shoot、BEVFormer),部分原因正是 IPM 的"地面是平面"假设在坡道和车辆上失效。全景拼接:OpenCV Stitcher 按 Brown–Lowe 的流程估计旋转并做光束法平差。ORB-SLAM:初始化时同时估计 \(H\) 和 \(F\),按得分选择模型,平面或低视差场景选 \(H\)。视觉伺服:Malis 等的 2½D 视觉伺服直接分解当前图与期望图之间的单应性得到旋转与归一化平移(第 IV 部分)。10.4 节:Zhang 标定的每张棋盘图先估计一个 \(H\)。

    7常见误区

    误区 1:平面假设不成立,却以为 \(H\) 在说真话

    杆顶、箱子顶、车辆、路沿、坡道都不在"地面"上:FIG 2 里杆顶残差随高度和基线增长,FIG 5 里箱子被拖到数米之外。"近似平面"的场景(远处的建筑、航拍的农田)可以用 \(H\),但误差随视差增大;只有纯旋转时,任何场景都可以。在拼接时若相机还在平移,要么用深度,要么靠重叠区域的融合掩盖。

    误区 2:退化与病态的点分布

    三点共线(FIG 1)要么使 \(H\) 奇异(只在一幅图里共线),要么使 \(A\) 秩亏、\(H\) 不唯一(两幅图里都共线);接近共线或全部挤在一个小角落(FIG 4 分布 10%)则"几乎"秩亏,解对噪声极度敏感,外推到别处误差成百倍放大。选点要铺开:AprilTag 的四个角天然是满秩的矩形,但一个很小、很远的标签在像素噪声下姿态仍然不稳;标定板要摆满视野。

    误区 3:不归一化,或不处理外点

    没有归一化的 DLT 在点铺满图像时看上去"也能用",一旦点聚在一处就严重变差(FIG 4 红色曲线),而修复只要几行。最小二乘对一个外点没有免疫:一个 50 px 的错配就能把整个网格拖偏几十像素。特征匹配总有错配,所以实际流程是"匹配 → RANSAC 找内点 → 在内点上 DLT + LM 精化"(11.5 节)。

    误区 4:方向、除以 \(w\)、前向映射

    三个小错误。①方向:\(H\) 把图像 1 的点搬到图像 2;做图像 2 → 图像 1 要用 \(H^{-1}\),反过来用就是整幅图的镜像或错位。②忘了除以 \(w\):\(H\tilde{\mathbf x}\) 的前两个分量不是像素坐标;在 FIG 5 的地平线附近 \(w\to0\),坐标飞向无穷。③前向映射:把输入的每个像素搬到输出会留下空洞和重叠,应该对每个输出像素用逆映射去输入里采样(FIG 1、FIG 5 的做法,warpPerspective 也是这样)。还有一个相关的坑:warpPerspective 的 \(H\) 默认是 src → dst,加了 WARP_INVERSE_MAP 才是反过来。

    误区 5:用仿射代替射影

    getAffineTransform 用 3 个点对解 6 个参数,平行线永远保持平行。对近距离斜看的平面,这会产生系统性的畸变:FIG 1 的梯形用仿射拟合,四个角中至多三个对得上。仿射只适合弱透视(物体的深度起伏远小于距离,如很远的航拍)。

    误区 6:符号约定与尺度

    \(R+\mathbf t\mathbf n\T/d\) 还是 \(R-\mathbf t\mathbf n\T/d\)?取决于 \(\mathbf X_2=R\mathbf X_1+\mathbf t\) 还是反向、平面写成 \(\mathbf n\T\mathbf X=d\) 还是 \(+d=0\)、\(\mathbf n\) 朝向哪边。读论文或调库时先对一对已知点数值验证。另外 \(H\) 只定义到一个比例:比较两个 \(H\) 要先归一化(令 \(\|H\|_F=1\)),而"令 \(h_{33}=1\)"在 \(h_{33}\approx0\) 时会爆炸;比例也可能带着负号。

    8小练习

    1. 用 DLT 估计两幅图像之间的单应性,至少需要几个点对(任意三点不共线)?
    \(H\) 有 9 个元素,整体比例不起作用,剩 8 个自由度;每个点对给 2 个独立方程,所以 \(8/2=4\)。3 个点对是仿射变换(6 个自由度)所需的个数,8 是误把"8 个自由度"当成"8 个点"。
    2. 相机 \(f=600\) px,主点在图像中心。相机绕光心水平转动 3°(没有平移)。图像中心附近的点大约移动多少像素?
    \(H=KRK^{-1}\),主光轴上的射线 \((0,0,1)\) 转到 \((\sin\theta,0,\cos\theta)\),像素位移 \(f\tan\theta=600\tan3^\circ\approx31.4\) px。与深度无关,这正是纯旋转的特点。选 0 是把"没有视差"误认成"没有运动";314 是把 3° 错成了 30°(\(600\times0.524\))。
    3. 用地面上的特征估出地面单应性 \(H\),再用它搬运一根 1 m 高杆的顶端像素。得到的位置是?
    \(H\) 对地面点才正确。杆顶像素的射线在地面上先交于一点 \(\mathbf Q\)(FIG 2 的紫色点),\(H\) 预测的就是 \(\mathbf Q\) 在图 2 里的像。它不是杆根(除非相机恰好在杆的正上方),也不是杆顶真实的位置;差值(视差)正比于杆高和基线,基线为零时消失。
    4. Hartley 归一化主要解决什么问题?
    它只是坐标的相似变换,不改变理想数据的解、不减少点数、不处理外点(那是 RANSAC 的事),只把 \(\kappa(A)\) 从 \(10^6\) 量级降到 \(10^2\) 量级。
    5. 相机高 2 m,鸟瞰图假设地面是平面。一个 0.5 m 高的箱子,水平距离 9 m。箱子顶端的点在鸟瞰图中会落在距离多远处?
    相似三角形:\(d'/h=d/(h-z_b)\),\(d'=9\times2/(2-0.5)=12\) m。顶端被"投影"到射线与地面的交点,比真实位置远了 3 m;\(z_b\to h\) 时 \(d'\to\infty\)。选 9 是忽略了高度,选 18 是把 \(d\) 直接乘了 \(h\)。

    9延伸阅读

    • R. Hartley & A. Zisserman, Multiple View Geometry in Computer Vision, 2nd ed., Cambridge University Press, 2004 — 第 4 章(二维射影变换的估计:DLT、归一化、代价函数)与第 13 章(场景平面与单应性、平面诱导的 \(H\))
    • R. Hartley, In Defense of the Eight-Point Algorithm, IEEE Trans. PAMI 19(6), 1997 — 坐标归一化的出处
    • R. Szeliski, Computer Vision: Algorithms and Applications, 2nd ed., Springer, 2022 — 第 8 章图像对齐与拼接(第 1 版为第 9 章)
    • M. Brown & D. G. Lowe, Automatic Panoramic Image Stitching using Invariant Features, IJCV 74(1), 2007 — 用旋转模型和单应性自动拼接全景
    • Z. Zhang, A Flexible New Technique for Camera Calibration, IEEE Trans. PAMI 22(11), 2000 — 由多个平面单应性求内参,10.4 节的方法
    • E. Malis & M. Vargas, Deeper Understanding of the Homography Decomposition for Vision-Based Control, INRIA Research Report RR-6303, 2007 — \(H\) 分解为 \((R,\mathbf t/d,\mathbf n)\) 的多解性与选择
    • E. Olson, AprilTag: A Robust and Flexible Visual Fiducial System, ICRA 2011 — 用四个角点的单应性估计标签位姿
    • R. Mur-Artal, J. M. M. Montiel & J. D. Tardós, ORB-SLAM: A Versatile and Accurate Monocular SLAM System, IEEE Trans. Robotics 31(5), 2015 — 初始化时在 \(H\) 与 \(F\) 之间选择
    • E. Malis, F. Chaumette & S. Boudet, 2½D Visual Servoing, IEEE Trans. Robotics and Automation 15(2), 1999 — 用单应性做视觉伺服