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

射影几何与齐次坐标

针孔相机的投影要除以深度,是个非线性运算;铁轨在远处会相交,而"过两点的直线""两条直线的交点"在平行线面前又要分情况讨论。给每个点多添一个坐标 w,只在"差一个比例"的意义下看待它,这些麻烦一并消失:投影变成矩阵乘法,平行线交在无穷远点,连线与求交都是同一个叉积。本节把 5.3 节里"补一个 1"的小技巧扩展成射影几何,它是 DLT、单应、对极几何、三角化等后面所有算法的共同语言。

约 35 分钟 前置:1.6 逆、秩与零空间 · 1.8 叉积 · 5.3 齐次变换 · 10.1 针孔相机 5 个交互

    1为什么机器人需要它

    10.1 节的针孔模型是 \(u = f_x X/Z + c_x,\ v = f_y Y/Z + c_y\)。分母里的 \(Z\) 使投影成为非线性映射:它不能写成一个矩阵乘法,不能把两个相机的变换连乘,也不能直接取逆。除此之外,你在图像里还会遇到这几件事:

    • 平行线会相交。路面上的车道线、桌子的边、走廊的墙角线,在三维里互相平行,在图像里却汇聚到一个消失点。消失点的位置藏着相机的朝向,甚至焦距。
    • 点和线的运算有特例。"过两点的直线""两条直线的交点",在普通坐标里要解方程组,还要单独讨论竖直线与平行线。
    • 后面的算法都是线性代数。由 4 个角点求单应(10.5)、由 6 个点标定相机(10.4)、由 8 对点求基础矩阵(11.1)、两视图三角化(11.3):它们统统写成"\(A\mathbf h = \mathbf 0\),取零空间"(1.6、1.12),前提是先把问题写成齐次向量上的线性方程。

    5.3 节已经用过齐次坐标:补一个 1,让平移也变成矩阵乘法。这一节把末位的数当作一个真正的坐标,并且不再要求它等于 1。这个小小的放松,就是射影几何的全部入口。

    2直觉:射影平面 = 过原点的射线

    让相机中心 \(O\) 位于原点,成像平面取 \(w = 1\)(10.1 节的归一化像平面,这里把光轴记作第三个坐标 \(w\))。从 \(O\) 出发的每一条射线恰好穿过成像平面一次,所以一个像点就是一条过原点的射线,这条射线上任何一个非零向量 \(\tilde{\mathbf x}=(x,y,w)\) 都可以代表它。把向量放大、缩小,甚至反号,射线没变,点就没变。要读出普通坐标,只需让射线与平面 \(w=1\) 相交:\((x/w,\ y/w)\)。

    有意思的是平行于成像平面的射线(\(w=0\)):它们永远打不到平面,却仍然是射线,是齐次向量。这就是无穷远点,它的坐标 \((x,y,0)\) 记录的是方向。而且一族平行线恰好对应这样一个点:每条直线与原点张成一个平面,这一族平面共享同一条射线。下图先拖滑块看一个点,再切到"平行线"看这件事。

    FIG 1射影平面 = 过原点的射线
    青色半透明方块是像平面 \(w=1\),底部的网格是平面 \(w=0\)(理想点所在),紫色圆是所有方向。琥珀色箭头是齐次向量 \(\tilde{\mathbf x}=\lambda\mathbf d\),青色虚线是它所在的射线。"点"模式:\(\alpha\) 是射线与光轴(\(w\) 轴)的夹角,\(\varphi\) 是方位角,\(\lambda\) 是向量的缩放(可以为负)。"平行线"模式:三条平行线(红、绿、蓝)各与原点张成一个平面,三个平面交于琥珀色的射线。可以用鼠标拖动画布旋转视角。
    试一试
    • 在"点"模式下把 \(\lambda\) 拖到负数:箭头反向了,可射线上的交点有没有动?这说明 \(\tilde{\mathbf x}\) 和 \(-\tilde{\mathbf x}\) 是什么关系?
    • 把 \(\alpha\) 一路拖到 \(90^\circ\):交点飞向哪里?\(w\) 变成多少?此时读数里的"点"变成了什么?
    核心洞见

    射影平面 \(\mathbb P^2\) 就是 \(\R^3\) 中过原点的直线(射线)的集合。普通点是穿过 \(w=1\) 平面的射线,无穷远点是平行于它的射线,二者在代数上没有区别,只是 \(w\) 恰好为 0。"平行线交于无穷远"不是一个约定,而是一个事实:平行线族对应的平面共享一条射线。

    3动手玩:连线、求交与对偶

    在齐次坐标里,直线 \(ax+by+c=0\) 就是向量 \(\mathbf l=(a,b,c)\),点 \(\tilde{\mathbf x}\) 在直线上当且仅当 \(\mathbf l^{\top}\tilde{\mathbf x}=0\)。过两点 \(\mathbf a,\mathbf b\) 的直线必须与两者都"垂直"(内积为 0),而叉积恰好给出同时垂直于两个向量的向量(1.8 节),所以 \(\mathbf l=\mathbf a\times\mathbf b\)。两条直线的交点同理:\(\tilde{\mathbf x}=\mathbf l\times\mathbf m\)。连线与求交是同一个运算,只是把点和线的角色对调,这叫对偶。

    下图拖动四个点:绿线过 \(\mathbf a,\mathbf b\),紫线过 \(\mathbf c,\mathbf d\),琥珀色点是它们的交点。读数里逐项验证了关联关系 \(\mathbf l^\top\mathbf a=0\) 等。点击"使 m ∥ l"让两线平行,再轻轻拖动一个点。

    FIG 2连线与求交:两个叉积
    点吸附到 0.25 的网格上,所以能做到精确平行。交点跑出画面时,边缘的琥珀色箭头指向它所在的方向;两线平行时交点是无穷远点 \((d_x,d_y,0)\),两个方向的箭头同时出现,因为 \((d_x,d_y,0)\) 与 \((-d_x,-d_y,0)\) 是同一个点。读数里的"相对残差"是 \(|\mathbf l^\top\mathbf p|/(\|\mathbf l\|\|\mathbf p\|)\),应为 0(舍入误差在 \(10^{-16}\) 量级,对网格点常常恰好为 0)。\(\det[\mathbf a\ \mathbf b\ \mathbf c]\) 等于三角形 \(abc\) 面积的两倍(带符号),为 0 当且仅当三点共线。
    • 让两条线精确平行(点"使 m ∥ l",或自己拖到网格点上)。交点 \(\tilde{\mathbf x}\) 的第三个分量变成了什么?程序有没有除以它?
    • 让交点先在画面很远的一侧,再慢慢转到另一侧(经过平行的位置)。交点是从无穷远"绕回来"的:射影平面是闭合的。
    对偶:同一个公式,两种读法

    \(\mathbf l^\top\tilde{\mathbf x}=0\) 对 \(\mathbf l\) 和 \(\tilde{\mathbf x}\) 是对称的。读成"点在线上",叉积给出连线;读成"线过点",叉积给出交点。凡是一个关于点和线的射影定理,把"点"与"线"、"共线"与"共点"互换,得到的仍是定理。这也是为什么本课之后会反复出现"一个 3×3 矩阵既可以看作点到点的映射,又可以看作点到线的映射"(11.1 节的基础矩阵就是后者)。

    4第二、第三视角:消失点与变换层级

    消失点与地平线

    三维里方向为 \(\mathbf d\) 的所有平行线,在相机坐标里的方向都是 \(R_{cw}\mathbf d\)。把"方向"当作 \(w=0\) 的齐次点 \((\mathbf d,0)\),投影矩阵作用上去,得到它们共同的像:消失点 \(\tilde{\mathbf v}=K R_{cw}\mathbf d\)(FIG 5 会验证)。几何上,过相机中心、平行于这族直线的那条射线,与像平面的交点就是消失点。地面上所有方向的消失点落在同一条线上,即地平线(地面的消失线);地平线是地面的无穷远线在图像里的像。

    下图左边是三维场景:地面、一座"房子"、相机和三条过相机中心的射线(沿 \(x,y,z\) 方向),射线与像平面的交点就是消失点。右边是相机拍到的图像。地平线画的是 \(K^{-\top}\mathbf n_c\)(\(\mathbf n_c\) 为地面法向在相机系中的方向);读数里再用两个消失点的叉积算一遍,两者一致,即使其中一个消失点跑到无穷远,叉积公式依然成立。

    FIG 3消失点与地平线
    三维场景(可旋转)
    相机图像(u 向右,v 向下)
    相机在以原点为中心、半径 7.5 m 的圆周上,朝向原点,再向下俯仰。图像为 640×480,主点在中心。红、绿、蓝是沿 \(x,y,z\) 的平行线族;明亮部分在图像内,暗淡部分在图像外;琥珀色虚线是地平线。消失点在画面外时,边缘的箭头给出方向。图中的虚线是房子的边向各自消失点的延长。
    • 把方位角调到 0°,让相机正对房子的一面。红色 \(x\) 线在图像里变成什么?\(\tilde{\mathbf v}_x\) 的 \(w\) 是多少?地平线还能算出来吗?
    • 把俯仰调到 0°:地平线落在图像的哪一行?再把相机升到 4 m 以上,地平线动了吗,地面网格呢?

    两个相互垂直的水平方向(\(x\) 和 \(y\))的消失点还满足 \(\tilde{\mathbf v}_x^\top\omega\,\tilde{\mathbf v}_y=0\),\(\omega=K^{-\top}K^{-1}\);主点已知、像素为方形时,这就是一行公式:\(f^2=-(\mathbf v_x-\mathbf c)\cdot(\mathbf v_y-\mathbf c)\)。读数里的 \(\hat f\) 正是这样算出来的,10.4 节会把它推广成标定方法。

    变换的层级:保持什么,丢掉什么

    平面上的 3×3 可逆矩阵 \(H\) 作用在齐次点上,叫射影变换(单应)。限制 \(H\) 的形状,得到越来越"刚"的子类:欧氏(刚体)→ 相似 → 仿射 → 射影。每放松一级,多丢掉一些几何性质,也多出几个自由度。下图让你亲手操作这四级,并实时测量哪些量还保持不变。最右的"四角点"模式直接拖动正方形的四个角,由 DLT 反求 \(H\),那就是 10.5 节的单应。

    FIG 42D 变换的层级
    虚线是原图,实线是 \(H\) 作用后的图像。两个直角标记 L₁、L₂ 的臂长都是 0.4(红臂沿 \(x\),绿臂沿 \(y\));圆变成了圆、椭圆或一般圆锥曲线;琥珀色的四个点在 \(x\) 轴上。紫色虚线是原图左右两条竖边的像,两线交点是消失点;琥珀色长虚线是 \(H^{-\top}\mathbf l_\infty\),即无穷远线的像。表中 ✓ 表示该量保持不变(相对误差 < 0.1%)。"四角点"模式下拖动四个圆圈。
    • 选"仿射",把"剪切 k"拉到 0.5 以上:哪几行变成 ✗?平行性呢?
    • 选"射影",调 \(v_1\) 或 \(v_2\) 使左右两边在图像里交于有限远的一点(距离 < 8)。这个点是 \(H\) 作用下哪两条线的交点?地平线在哪?
    • 选"四角点",把正方形拖成梯形。哪几行永远不会变成 ✗?
    一个 3-向量,四种身份

    同一个三元组可以是:图像点(\(w\neq0\)),方向/消失点(\(w=0\)),直线(用 \(\mathbf l^\top\tilde{\mathbf x}=0\) 的方式读),或者相机坐标系里的射线(\(K^{-1}\tilde{\mathbf x}\),10.1 节的反投影)。区别在于怎么变换:点用 \(H\),线用 \(H^{-\top}\),射线用 \(K^{-1}\)。写代码时给它们分别起名字(甚至用不同的类型),能避免一大类 bug。

    5再看数学

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

    齐次坐标与无穷远点

    射影平面是非零 3-向量模掉"相差一个非零倍数"的等价关系:

    $$ \begin{gathered}\mathbb P^2=(\R^3\setminus\{\mathbf 0\})/\!\sim,\qquad \hl{x}{\tilde{\mathbf x}}\sim\hl{lam}{\lambda}\tilde{\mathbf x}\ \ (\lambda\neq0)\\[4pt] (x,y)\ \mapsto\ (x,y,1),\qquad (x,y,\hl{w}{w})\ \mapsto\ \Big(\tfrac{x}{w},\tfrac{y}{w}\Big)\ \ (w\neq0).\end{gathered} $$

    三个数只有两个自由度(去掉一个整体比例)。\(w=0\) 的向量 \((x,y,0)\) 没有对应的普通点,它们是无穷远点,编码方向 \((x,y)\),也就是 5.3 节里"方向用 \((\mathbf d,0)\)"的那个 0。全体无穷远点构成一条线 \(\mathbf l_\infty=(0,0,1)\):\(\mathbf l_\infty^\top\tilde{\mathbf x}=w\)。注意 \(\lambda\) 可以是负数,\(\tilde{\mathbf x}\) 与 \(-\tilde{\mathbf x}\) 是同一个点。

    直线、连线与求交

    直线 \(ax+by+c=0\) 记作 \(\hl{l}{\mathbf l}=(a,b,c)\),同样只差一个比例。\((a,b)\) 是法向,当 \(\|(a,b)\|=1\) 时 \(\mathbf l^\top\tilde{\mathbf x}\)(\(w=1\))就是点到直线的带符号距离。点与线的关联、连线、求交:

    $$ \mathbf l^\top\tilde{\mathbf x}=0,\qquad \mathbf l=\tilde{\mathbf p}\times\tilde{\mathbf q}\ \ (\text{join}),\qquad \hl{x}{\tilde{\mathbf x}}=\hl{l}{\mathbf l}\times\hl{m}{\mathbf m}\ \ (\text{meet}). $$

    验证:\(\tilde{\mathbf p}^\top(\tilde{\mathbf p}\times\tilde{\mathbf q})=0\),\(\tilde{\mathbf q}^\top(\tilde{\mathbf p}\times\tilde{\mathbf q})=0\)(叉积垂直于两个因子,1.8 节)。当 \(\tilde{\mathbf p}\sim\tilde{\mathbf q}\) 时叉积为 0,连线不唯一;当 \(\mathbf l\sim\mathbf m\) 时同理。这是唯一的退化情形,不再需要"平行""竖直"之类的分类。两条直线 \(ax+by+c_1=0\) 与 \(ax+by+c_2=0\) 平行,叉积为 \((c_2-c_1)\,(b,\,-a,\,0)\),正是方向 \((b,-a)\) 的无穷远点。叉积也是线性的:用 1.8 节的反对称矩阵(第 5 章里的 hat 映射)写成

    $$ \mathbf a\times\mathbf b=[\mathbf a]_\times\mathbf b=\begin{bmatrix}0&-a_3&a_2\\ a_3&0&-a_1\\ -a_2&a_1&0\end{bmatrix}\mathbf b,\qquad \mathbf a\times\mathbf b=\mathbf 0\iff\mathbf a\sim\mathbf b. $$

    于是"两个齐次向量表示同一点"可以写成线性方程 \([\mathbf a]_\times\mathbf b=\mathbf 0\)。这是比较齐次向量的正确方式,也是 DLT 的出发点(见下)。

    点怎么变换,线怎么变换

    可逆 3×3 矩阵 \(H\) 把点映成点:\(\tilde{\mathbf x}'=H\tilde{\mathbf x}\)。线不能直接用 \(H\),而要用 \(H^{-\top}\)。推导只要一行:点在线上的关系必须被保持,\(\mathbf l'^\top\tilde{\mathbf x}'=0\)。

    $$ \begin{gathered}0=\mathbf l^\top\tilde{\mathbf x}=\mathbf l^\top H^{-1}H\tilde{\mathbf x}=\big(H^{-\top}\mathbf l\big)^{\!\top}\tilde{\mathbf x}'\quad\Longrightarrow\quad \mathbf l'=H^{-\top}\mathbf l,\\[4pt] (H\mathbf a)\times(H\mathbf b)=\det(H)\,H^{-\top}(\mathbf a\times\mathbf b).\end{gathered} $$

    第二个恒等式说:先变换两点再连线,等于先连线再用 \(H^{-\top}\) 变换。FIG 3 里的地平线是它的一个实例:\(K\mathbf r_1\times K\mathbf r_2=\det K\cdot K^{-\top}(\mathbf r_1\times\mathbf r_2)=\det K\cdot K^{-\top}\mathbf r_3\)。对二次曲线 \(\tilde{\mathbf x}^\top C\tilde{\mathbf x}=0\),同理 \(C'=H^{-\top}CH^{-1}\)(读数里不用,只作指针)。若 \(H\) 是纯旋转(\(R^{-\top}=R\)),线和点用同一个矩阵变换,你不会发现差别;刚体运动下的法向量也只按 \(R\) 旋转,同样看不出来。但齐次形式的平面在 \(T\in\mathrm{SE}(3)\) 下仍要用 \(T^{-\top}\)(平移会改变平面的常数项);一旦出现缩放、剪切或透视,差别立刻显现(见"误区 3")。

    层级、自由度与不变量

    类别H自由度保持不变的量
    欧氏\(\begin{bmatrix}R&\mathbf t\\ \mathbf 0^\top&1\end{bmatrix}\)3长度、角度、面积
    相似\(\begin{bmatrix}sR&\mathbf t\\ \mathbf 0^\top&1\end{bmatrix}\)4角度、长度之比
    仿射\(\begin{bmatrix}A&\mathbf t\\ \mathbf 0^\top&1\end{bmatrix}\)6平行性、平行线段的长度比、面积比;\(\mathbf l_\infty\) 映到自身
    射影\(\begin{bmatrix}A&\mathbf t\\ \mathbf v^\top&1\end{bmatrix}\)8关联性(共线、共点)、交比

    射影类的 \(H\) 有 9 个元素,去掉整体比例剩 8 个自由度。仿射类的最后一行是 \((0,0,1)\),\(\mathbf l_\infty\) 被映到自己,所以平行线仍然平行;射影类的 \(\mathbf v\neq\mathbf 0\),\(\mathbf l_\infty\) 被映成有限远的一条线 \(H^{-\top}\mathbf l_\infty\),这就是地平线(FIG 4 的琥珀色长虚线)。仿射部分 \(A\) 可以分解为旋转、各向异性缩放、旋转(SVD,1.12 节);FIG 4 中用 \(R(\theta)\begin{bmatrix}s_x&k\\0&s_y\end{bmatrix}\) 参数化。

    交比:射影变换下仍然不变的"比"

    长度比在射影变换下不保持,但共线四点的交比保持。设四点在其所在直线上的一维坐标为 \(t_1,\dots,t_4\):

    $$ \operatorname{Cr}(t_1,t_2;t_3,t_4)=\frac{(t_1-t_2)(t_3-t_4)}{(t_1-t_3)(t_2-t_4)}. $$

    一维射影变换是 \(t\mapsto(\alpha t+\beta)/(\gamma t+\delta)\),代入后 \(t_i'-t_j'=\det\cdot(t_i-t_j)/\big((\gamma t_i+\delta)(\gamma t_j+\delta)\big)\),分子分母里的 \(\det\) 与 \((\gamma t_i+\delta)\) 恰好抵消。交比是"图像里的尺子":已知三个点的真实间距,可以由图像上的四个点反推第四个点的位置(例如算出路面上某个标记的实际距离)。

    相机是 \(\mathbb P^3\to\mathbb P^2\) 的线性映射

    三维点也有齐次坐标 \(\tilde{\mathbf X}=(\mathbf X,1)\in\mathbb P^3\),平面是 4-向量 \(\boldsymbol\pi\)(\(\boldsymbol\pi^\top\tilde{\mathbf X}=0\)),无穷远平面是 \(\boldsymbol\pi_\infty=(0,0,0,1)\)。10.3 节的相机矩阵 \(P=K[R\,|\,\mathbf t]\) 是 3×4 矩阵:

    $$ \begin{gathered}\lambda\tilde{\mathbf x}=P\tilde{\mathbf X}=K\big[R\,|\,\mathbf t\big]\begin{bmatrix}\mathbf X\\1\end{bmatrix}\ \ (\mathbf t={}^{c}\mathbf t_{w}),\qquad P\begin{bmatrix}\mathbf d\\0\end{bmatrix}=KR\mathbf d,\\[4pt] P\tilde{\mathbf C}=\mathbf 0\ \Longrightarrow\ \tilde{\mathbf C}=\begin{bmatrix}-R^\top\mathbf t\\1\end{bmatrix}.\end{gathered} $$

    第二个式子:无穷远点 \((\mathbf d,0)\) 的像只与 \(KR\) 有关,与平移无关,这就是消失点公式。第三个式子:\(P\) 的秩为 3,所以有一维零空间;相机中心是唯一被映成 \((0,0,0)\)(不是任何像点)的点,因此相机中心 = \(P\) 的右零向量(FIG 5 用 SVD 数值验证,1.12 节)。这里的 \(\lambda\) 是投影深度(带正负号:为负表示点在相机后面),所以在相机里符号是有意义的,下面"误区 2"会再谈。

    为什么 DLT 是零空间问题

    已知对应点 \(\tilde{\mathbf x}\leftrightarrow\tilde{\mathbf x}'\) 求 \(H\)。不能写 \(\tilde{\mathbf x}'=H\tilde{\mathbf x}\)(只差比例,\(\lambda\) 未知),而应写"平行"条件 \(\tilde{\mathbf x}'\times H\tilde{\mathbf x}=\mathbf 0\),它对 \(H\) 的 9 个元素 \(\mathbf h=(\mathbf h_1;\mathbf h_2;\mathbf h_3)\) 是线性的。设 \(\tilde{\mathbf x}'=(x',y',w')\):

    $$ \begin{bmatrix}\mathbf 0^\top&-w'\tilde{\mathbf x}^\top&y'\tilde{\mathbf x}^\top\\ w'\tilde{\mathbf x}^\top&\mathbf 0^\top&-x'\tilde{\mathbf x}^\top\\ -y'\tilde{\mathbf x}^\top&x'\tilde{\mathbf x}^\top&\mathbf 0^\top\end{bmatrix}\begin{bmatrix}\mathbf h_1\\ \mathbf h_2\\ \mathbf h_3\end{bmatrix}=\mathbf 0. $$

    三行里只有两行线性无关(叉积的三个分量满足一个线性关系),所以每对点提供 2 个方程;\(H\) 有 8 个自由度,因此4 对点(任意三点不共线)刚好够。把 \(n\) 对点的方程叠成 \(A\mathbf h=\mathbf 0\),\(\mathbf h\) 是 \(A\) 的零空间,噪声下取最小奇异值对应的右奇异向量(1.12 节)。因为未知量只定义到比例,必须约束 \(\|\mathbf h\|=1\),而不是 \(h_{33}=1\)(后者在 \(h_{33}\approx0\) 时出问题)。同样的做法对相机矩阵 \(P\)(11 个自由度,每个 3D–2D 点对 2 个方程,至少 6 对点,10.4 节)、基础矩阵 \(F\)(\(\tilde{\mathbf x}'^\top F\tilde{\mathbf x}=0\),一个线性方程,11.1 节)都成立。

    6机器人中的它:地平线、车道线与"无穷远"

    想象一台移动机器人(或一辆车)的前视相机,高度 \(h\),向下俯仰 \(\theta\)。两条车道线平行,向前延伸到无穷远。把车道线上的点写成 \(\tilde{\mathbf X}(w)=(\mathbf d+w\mathbf P_0,\ w)\),\(w=1/s\) 是"离得多远"的倒数:

    $$ \tilde{\mathbf x}(w)=P\tilde{\mathbf X}(w)=\cx{KR\mathbf d}+w\,P\tilde{\mathbf P}_0,\qquad \tilde{\mathbf P}_0=(\mathbf P_0,1). $$

    \(w\) 取 1 时是近处的点;\(w\to0\) 时,点飞向无穷远,像素 \(\tilde{\mathbf x}(w)\) 沿一条直线收敛到 \(KR\mathbf d\),也就是消失点。它在 \(w=0\) 处平滑地"到达",因为齐次坐标把"走到无穷远"变成了 \(w=0\) 这个普通数值。拖动距离滑块,再改变车道的坡度和相机的俯仰:平路的消失点落在地平线上,上坡的消失点跑到地平线之上。左边同时用 SVD 数值求出 \(P\) 的零空间,核对相机中心。

    FIG 5相机矩阵 P:无穷远点的像是消失点
    三维:机器人相机与车道(可旋转)
    图像(v 向下)
    相机在原点正上方 \(h\) 米处,朝 \(+y\) 看,俯仰 \(\theta\),焦距 500 px。两条车道 \(x=\pm1.8\) m,方向 \(\mathbf d=(0,1,g)\)(\(g\) 为坡度);琥珀色点是右车道上 \(\mathbf P_0+\mathbf d/w\) 处的点。右图中的细线是像素随 \(w\) 从 1 到 0 走过的路径,它是一条直线。"零空间"一行是 \(\operatorname{null}(P)\) 的 SVD 结果,应与相机中心一致。
    • 把距离拖到 \(w\le0.01\)(100 m 以外):点距离消失点还有多少像素?它还在近处的车道线上吗?
    • 把坡度 \(g\) 调到 0.1 以上(约 6° 上坡):消失点和地平线的关系变成了什么?这对"用消失点估计俯仰角"意味着什么?
    真实系统里

    车道线与路面平面:车道检测常用"逆透视映射"(IPM)把前视图变成俯视图,它就是一个由相机高度、俯仰和内参决定的单应;地平线决定了哪里是路面的尽头。由消失点估计姿态:室内走廊和楼宇环境(Manhattan 世界)里,三个正交方向的消失点给出相机的旋转,也能给出焦距,用于无标定相机的初始化。基准标记:AprilTag、ArUco 的角点与标记平面之间是一个单应,OpenCV 的 findHomography、warpPerspective、solvePnP 都建立在这套齐次坐标的工具上。SLAM 前端:ORB-SLAM 一类系统的单目初始化会同时估计单应和基础矩阵,并用 DLT 三角化地图点,这些都是本课的"零空间问题";OpenCV 提供 convertPointsToHomogeneous / convertPointsFromHomogeneous,Eigen 则是 .homogeneous() / .hnormalized()。图形学:GPU 里的裁剪坐标 \((x,y,z,w)\) 与"透视除法"正是同一件事(12.3 节)。tf / SE(3):ROS tf 里的坐标变换(常被当作 4×4 矩阵处理)是 5.3 节的刚体变换,其中的 1 不能随意缩放;这里的齐次坐标则允许任意缩放,二者形式相似,含义不同。

    7常见误区

    误区 1:随手除以 w

    \(w=0\) 是合法的点(无穷远点),\(w\approx0\) 的点除出来是一个巨大的数,误差被整体放大。尽量把运算留在齐次形式里,最后才除,并在除之前检查 \(|w|\) 相对于 \(\|\tilde{\mathbf x}\|\) 是否足够大(FIG 2 的判据就是这样写的)。更微妙的是:射影变换不保持"线段"。一条线段若跨过 \(w=0\)(比如 FIG 4 里把 \(v_1\) 拉得很大),它的像不是一段,而是穿过无穷远的两段,画图时必须在 \(w\) 变号处断开。

    误区 2:把"相等"当成"相等到比例"

    \((2,4,2)\) 与 \((1,2,1)\) 是同一个点,\((-1,-2,-1)\) 也是,所以不能直接逐元素比较,也不能用 allclose。正确的做法是各自归一化后比较(并处理符号),或检查 \(\tilde{\mathbf a}\times\tilde{\mathbf b}\approx\mathbf 0\)。但在相机里符号有物理意义:\(P\tilde{\mathbf X}\) 的第三分量为负,说明点在相机后面,却会投影到画面里(针孔相机看不见,而射影几何并不知道)。需要区分前后时,要用"定向射影几何"的思路或单独检查深度("手性检查",11.1、11.4 节)。

    误区 3:用 H 去变换线(或法向量)

    线、平面、法向量要用 \(H^{-\top}\)。旋转矩阵碰巧满足 \(R^{-\top}=R\),所以只做旋转、或者只变换法向量时这个错误不会暴露(带平移的齐次平面照样需要 \(T^{-\top}\));一旦 \(H\) 含有缩放、剪切或透视(相机内参 \(K\)!),错误的线就不再过变换后的点。FIG 4 的"平行性"一行正是用 \(H^{-\top}\) 变换左右两条边再求交。验证方法永远是:变换后检查 \(\mathbf l'^\top\tilde{\mathbf x}'\approx0\)。

    误区 4:条件数与几乎平行的线

    像素坐标是 \(10^3\) 量级而 \(w=1\),叠成 \(A\mathbf h=\mathbf 0\) 后各列数量级相差 \(10^6\),SVD 解出的 \(H\) 精度很差。DLT 之前要做 Hartley 归一化:把点平移到质心、缩放到平均距离 \(\sqrt2\)(10.5 节),做完再变换回来。另一个陷阱是两条几乎平行的线:它们的叉积很小,交点在很远处,位置对线的微小误差极度敏感(夹角为 \(\epsilon\) 时误差放大 \(1/\epsilon\) 倍)。消失点估计因此要用很多条线做最小二乘,而不是两条线求交。

    误区 5:把两种"齐次"混为一谈

    5.3 节里 \(T\in\mathrm{SE}(3)\) 的 4×4 矩阵,最后一个分量必须保持 1:把 \(T\) 乘以 2,就不再是刚体变换。本节的 \(H\) 乘以任何非零常数都是同一个变换。反过来,用 SE(3) 的求逆公式 \(T^{-1}=[R^\top,-R^\top\mathbf t]\) 去求逆一个射影矩阵是错的,射影矩阵要用通用的 3×3 或 4×4 求逆。相机矩阵 \(P\) 的左 3×3 块也不是旋转(它是 \(KR\)),用 RQ 分解(如 OpenCV 的 decomposeProjectionMatrix)来拆分,而不是把它当成位姿。

    8小练习

    1. 点 \((1,2)\) 与 \((3,1)\) 的连线(齐次形式,差一个比例)是?
    \((1,2,1)\times(3,1,1)=(2\cdot1-1\cdot1,\ 1\cdot3-1\cdot1,\ 1\cdot1-2\cdot3)=(1,2,-5)\),即 \(x+2y-5=0\)。验证:\(1+4-5=0\),\(3+2-5=0\)。选项 A 是把前两个分量写反了:\((2,1,-5)\) 过 \((1,3)\),不过 \((1,2)\)。
    2. 直线 \(x+2y-5=0\) 与 \(x+2y+1=0\) 的交点(齐次坐标,差一个比例)是?
    \((1,2,-5)\times(1,2,1)=(2\cdot1-(-5)\cdot2,\ (-5)\cdot1-1\cdot1,\ 1\cdot2-2\cdot1)=(12,-6,0)\sim(2,-1,0)\):无穷远点,方向 \((2,-1)\) 正是两条线的公共方向(沿线移动时 \(x+2y\) 不变)。选项 B 给出的是法向 \((1,2)\) 而不是方向;选项 D 偷偷把 \(w\) 改成了 1。
    3. 变换 \(H=\operatorname{diag}(2,1,1)\)(x 方向放大 2 倍)作用于直线 \(x+y-1=0\),即 \(\mathbf l=(1,1,-1)\)。像是?
    \(\mathbf l'=H^{-\top}\mathbf l=\operatorname{diag}(\tfrac12,1,1)(1,1,-1)=(\tfrac12,1,-1)\),即 \(x/2+y-1=0\)。验证:点 \((1,0)\to(2,0)\) 与 \((0,1)\to(0,1)\) 都满足。选项 A 是 \(H\mathbf l\),那是把线当成点来变换的典型错误:它不过 \((2,0)\)。
    4. 相机 \(f=500\) px,主点 \((320,240)\)。相机坐标系中方向为 \((1,0,2)\) 的一族平行线,消失点的像素坐标是?
    \(\tilde{\mathbf v}=K\mathbf d=(500\cdot1+320\cdot2,\ 240\cdot2,\ 2)=(1140,480,2)\),除以 \(w=2\):\((570,240)\)。选项 C 忘了除以 \(w\);选项 B 只除了一半:\(500\cdot1+320=820\) 没有除以深度 2;选项 D 只在 \(d_z=0\)(方向平行于像平面)时才成立,此时 \(w=0\)。
    5. 用 DLT 求平面单应 \(H\)(8 个自由度),至少需要几对一般位置的对应点?为什么?
    叉积的三个分量只有两个独立,每对点 2 个方程;8 个自由度需要 8 个方程,所以 4 对点(任意三点不共线)。3 对点只有 6 个方程,\(A\) 的零空间是 3 维的,\(H\) 不唯一;更多的点用于最小二乘抗噪(SVD 的最小奇异值向量)。

    9延伸阅读

    • R. Hartley & A. Zisserman, Multiple View Geometry in Computer Vision, 2nd ed., Cambridge University Press, 2004, Ch. 2 and Ch. 3 — 本课内容的标准出处:射影平面、对偶、变换层级、交比、三维射影几何;第 4 章的 DLT 与归一化
    • Y. Ma, S. Soatto, J. Košecká & S. S. Sastry, An Invitation to 3-D Vision, Springer, 2004, Ch. 3 — 图像形成与透视投影的齐次坐标表述
    • R. Szeliski, Computer Vision: Algorithms and Applications, 2nd ed., Springer, 2022, §2.1 — 几何基元与变换的层级,图文并茂的简明版本,可免费在线阅读
    • J. Richter-Gebert, Perspectives on Projective Geometry, Springer, 2011 — 纯几何视角的射影几何,适合想理解"为什么对偶、交比成立"的读者
    • J. Stolfi, Oriented Projective Geometry: A Framework for Geometric Computations, Academic Press, 1991 — 区分 \(\tilde{\mathbf x}\) 与 \(-\tilde{\mathbf x}\) 的"定向"射影几何,对应上面的误区 2