
做图像矫正或者视觉测量的时候大家一定遇到过这种情况明明是同一块地面换了个角度拍照两条线段的像素长度比就完全变了靠长度比例去估算距离的土办法直接翻车。几何上这就是透视投影破坏了长度比例。但在所有被扭曲的量里有一个量始终纹丝不动那就是交比cross ratio也叫交叉比、复比。交比不变性说的是一条直线上四个点在任意中心投影下交比保持不变。这篇文章就做一件事把这一定理的证明从零推一遍给出一个可以直接复现的数值验证再聊聊它在相机标定、透视矫正、单目测量里到底怎么用。适合被一堆射影几何符号绕晕的工程师也适合刚开始接触视觉几何的本科生。1. 先搞清楚交比到底是什么1.1 透视让长度“失真”但没有带走一切站在走廊尽头看脚下的地砖近处一块砖在照片里可能有几百个像素远处同样一块砖可能只剩几十个像素。这说明线段长度和长度比例都不是透视不变量。但是如果你在地砖缝的延长线上取四个等间距点用相机拍一张照片再回到照片上量这四个点的交比会发现它和地面上真实四点的交比完全相同。这个现象很反直觉因为距离明明被压缩了为什么一个看起来由距离构成的东西反而没变答案在于透视压缩不是均匀的但压缩方式被一个统一规则控制。射影变换把直线上的坐标变成分式线性形式而交比正是在分式线性变换下保持不变的那个组合量。可以说交比是射影几何里最核心的“尺子”度量几何里的长度、角度会因为视角变化而变化交比则不会。搞懂交比不变性不只是满足数学洁癖。相机成像、图像拼接、三维重建、单目测量很多算法底层都在偷偷用它。如果你只是调用 OpenCV 的 findHomography可能一辈子不用手动证明它可一旦遇到诡异结果比如标定漂移、矫正图弯曲回头查原理时交比往往是那条最重要的线索。1.2 交比的定义与符号陷阱先约定一条直线上四个不重合点 A、B、C、D交比定义为[ (A,B;C,D)\frac{\overline{AC}/\overline{BC}}{\overline{AD}/\overline{BD}} ]其中 (\overline{AC}) 表示有向长度也就是带符号的距离。等价地可以写成[ (A,B;C,D)\frac{\overline{AC}\cdot\overline{BD}}{\overline{AD}\cdot\overline{BC}} ]如果 A、B、C、D 在某个坐标轴上的值分别是 a、b、c、d那么[ (A,B;C,D)\frac{(c-a)/(c-b)}{(d-a)/(d-b)} ]这里最容易被坑的是顺序。交比和点的顺序强相关交换 C 和 D结果会变成倒数交换 A 和 B结果也会变成倒数做更复杂的置换还会出现 (1-x)、(1/(1-x)) 这类值。所以看论文或代码时第一件事就是确认作者定义的点的顺序否则同一个题目可能得到完全不同的结果。另外一个常见困惑是“那是不是四个点越远交比越大”不是。交比跟四点间的间隔相关但没有单调关系。比如四个点等间距分布时交比等于一个固定值 4/3但这个值并不直观你把 C 或 D 移动一点交比立刻变化。所以交比更像一个“指纹”用于判断两组四点是否在射影意义上等价。2. 证明交比在射影变换下不变2.1 先建立直觉中心投影只是换了一种方式给直线标刻度证明之前先确保我们对“射影变换”有一个直观印象。中心投影可以理解为“换一个角度看同一条直线”。想象你站在点 O看地面上一条直线 l视线把 l 上的每一个点映射到相机传感器所在直线 l 上。这个映射只要不遇到投影中心 O就是连续且可逆的。在非齐次坐标下这个映射不是线性关系而是分式线性关系[ t \frac{a t b}{c t d},\quad ad-bc \neq 0 ]也就是说原来直线上坐标为 t 的点经过中心投影后在像直线上的坐标变成上面这个分式。如果用齐次坐标这个分式会立刻变成线性形式[ \begin{bmatrix} x \ y \end{bmatrix}M \begin{bmatrix} x \ y \end{bmatrix} ,\quad M\begin{bmatrix} a b \ c d \end{bmatrix} ]其中非齐次坐标 (tx/y)而 (tx/y)代入后正好还原出分式线性关系。M 可逆是因为 (ad-bc\neq0)。那二维或三维空间里的射影变换作用到一条直线上为什么也能写成这种形式因为在齐次坐标下直线上任意点可以写成两个基点的线性组合 (P\alpha U\beta V)经过一个射影变换 T 后像点 (T(P)\alpha T(U)\beta T(V))仍然是两个像基点的线性组合。换句话说射影变换把“直线”仍然变成“直线”并且在直线的坐标系诱导出一个 2x2 的线性映射。所以我们只需要证明任意的 2x2 可逆矩阵乘在四个点前面交比不变。2.2 用二阶行列式改写交比把四个点的齐次坐标记为[ P_i \begin{bmatrix} x_i \ y_i \end{bmatrix}, \quad i1,2,3,4 ]定义两两之间的二阶行列式[ [ij] \det\begin{pmatrix} x_i x_j \ y_i y_j \end{pmatrix} x_i y_j - x_j y_i ]这个量几何上表示两个点齐次坐标张成的“面积”带上符号。用它可以简洁地表示交比[ CR(P_1,P_2;P_3,P_4)\frac{[13]/[23]}{[14]/[24]} ]为什么不直接用坐标差因为用行列式的好处是当某个点跑到无穷远时也就是 y_i0 时公式依然成立不会出现分母为无穷大的尴尬。验证一下也能发现把非齐次坐标 (t_ix_i/y_i) 代进去它就会还原成前面那个有向长度的比值。2.3 核心步骤所有二阶行列式共享同一个缩放因子现在让所有点经过同一个一维射影变换[ P_i M P_i ]M 是任意 2x2 可逆矩阵。于是[ [ij] \det(M P_i, M P_j) \det(M) \cdot [ij] ]这个式子很关键线性变换作用后任意两点的二阶行列式都会整体乘上 (\det(M))。它和 i,j 具体是哪两个点没有关系四个行列式乘以同一个因子。然后把变换后的交比写出来[ CR(P_1,P_2;P_3,P_4)\frac{\det(M)[13] / \left(\det(M)[23]\right)} {\det(M)[14] / \left(\det(M)[24]\right)}\frac{[13]/[23]}{[14]/[24]}CR(P_1,P_2;P_3,P_4) ]约分完成证明结束。为什么这个证明这么短因为交比只关心两两点之间张成的“面积”而线性变换对这些面积的作用统一是乘以行列式。所有点的坐标信息都被吸收进同一个因子然后被比值结构抵消了。这里不需要展开 M 的具体元素也不需要讨论射影变换中心在哪只要它是可逆的线性映射交比就一定不变。2.4 一个容易被忽略的前提M 必须可逆如果 M 不可逆意味着变换把整条直线压成一个点或者压成一条线但没有逆变换。这种退化情况会让所有像点变成共点交比自然没有意义。实际的中心投影只要投影中心不在直线上或者像平面不与直线平行到无穷远处诱导的一维变换就是可逆的。换句话说一张正常拍摄的照片里地面直线上的点列诱导出来的变换都可逆交比一定成立。3. 用 3x3 单应矩阵做一次完整数值验证3.1 二维单应与一维交比的关系在图像处理中二维平面之间的射影变换通常用 3x3 单应矩阵 H 表达。用 H 去变换一条直线上的点列像点通常不会落在原来的直线上但仍然共线。只要把像点重新投影到一条新的直线上再取直线参数坐标诱导出来的变换就是上一节所说的 2x2 可逆矩阵。所以最直接的验证方法构造一个普通 H把四个共线点变换过去证明它们依然共线并计算变换前后的交比。3.2 可复现的 Python 代码import numpy as np # 任意取一个行列式不为0的单应矩阵 H np.array([ [0.8, -0.3, 1.2], [0.5, 0.7, 0.4], [0.1, -0.2, 1.5] ]) # 原始直线 y0 上的四个点 pts np.array([ [0, 0, 1], [1, 0, 1], [2, 0, 1], [3, 0, 1] ], dtypefloat) def apply_homography(H, pts): mapped pts H.T return mapped / mapped[:, 2:3] def cross_ratio_on_line(points): # 输入为 (4,3) 齐次坐标取欧氏部分 p0, p1, p2, p3 points[:, :2] v p1 - p0 # 把每个点投影到直线上得到一维参数 t t np.array([np.dot(p - p0, v) for p in [p0, p1, p2, p3]]) t t / np.dot(v, v) # 交比 (A,B;C,D) ((C-A)/(C-B)) / ((D-A)/(D-B)) return ((t[2] - t[0]) / (t[2] - t[1])) / ((t[3] - t[0]) / (t[3] - t[1])) pts_t apply_homography(H, pts) print(原始四点交比:, cross_ratio_on_line(pts)) print(单应变换后交比:, cross_ratio_on_line(pts_t)) print(变换后的点坐标:) print(pts_t[:, :2])这段代码里cross_ratio_on_line 没有直接取 x 或 y 坐标而是先构造方向向量 v然后把每个点投影到直线上得到参数 t。这样即使像点发生了旋转、平移、缩放只要它们还共线参数 t 就能还原真实的一维位置关系。我在本地跑过一次输出大概是原始四点交比: 1.3333333333333333 单应变换后交比: 1.3333333333333333 变换后的点坐标: [[0.8 0.26666667] [1.25 0.5625 ] [1.64705882 0.82352941] [2. 1.05555556]]浮点误差在 1e-15 量级可以认为完全相等。这也说明验证交比不变性并不需要复杂的几何库一个 numpy 脚本就够。3.3 把数值验证再往前推一步如果只是验证一个 H说服力有限。你可以把上面的代码包在一个循环里随机生成几十个 H检查交比是否始终一致。关键点是每次随机生成 H 后先检查行列式是否接近 0避免选到退化矩阵。实测下来只要 H 可逆交比误差始终落在浮点精度范围内。这个脚本也可以直接改造成一个小工具用于检查某组对应点是否符合单应关系。如果你有一堆匹配点先判断它们是否共线然后用交比判断这四组点是否来自同一个射影变换比直接拟合单应再算重投影误差更快因为它不涉及矩阵求解只是一个标量比较。4. 证明之外交比到底帮我们解决了什么4.1 单张照片测高度交比就是透视下的尺子交比最常见的工程应用之一是从单张图片中测出真实高度。比如你拍了一面墙墙脚是 A墙顶是 C画面里还有一个高度为 1m 的箱子箱子的底部和顶部在竖直方向上的投影点分别是 A 和 B。如果四条点都在同一条竖直直线上那么 A、B、C 和消失点 D 构成四个共线点。这里 D 在无限远处。在真实世界的竖直方向坐标里可以认为 D 的坐标趋向无穷。交比公式中当 D 趋于无穷时[ (A,B;C,D)\frac{(C-A)/(C-B)}{(D-A)/(D-B)} \to \frac{C-A}{C-B} ]也就是说当第四个点是无穷远点时交比退化成两个有向长度的比值。换句话说竖直方向上消失点参与的四个点把交比变成了“墙高除以墙高减箱子高度”这样的式子。假设图像中 A、B、C 对应的像素纵坐标分别为 yA20、yB80、yC120。那么图像坐标下的退化的交比为[ \frac{120-20}{120-80}2.5 ]真实世界坐标取 A0B1CHD∞交比为[ \frac{H-0}{H-1} ]由交比不变性[ \frac{H}{H-1}2.5 ]解得 H≈1.667m。整个过程只需要一条直线上的三个有限点和消失点方向不需要相机内参也不需要复杂的标定板。这正是交比被频繁用于交通事故现场重建、航空测量、单目视觉测距的原因。4.2 消失点、单应矩阵和三个自由度一个更有意思的推论是一条直线上的射影变换只有 3 个自由度。2x2 矩阵有 4 个元素但它整体乘一个非零常数不会改变映射结果所以真正自由的是 3 个参数。这也解释了为什么给定直线上三对对应点就能唯一确定一个一维射影变换第四个点不能随便给它的位置由交比不变性强制决定。二维平面上的单应矩阵有 8 个自由度因此需要四对对应点才能唯一确定。这个经典结论背后其实也能看到交比的影子四个点一旦给定它们的交比就是射影不变量相当于给单应求解提供了一条额外的几何约束。在图像拼接、相机标定、AR 场景中单应矩阵是绝对核心。每次你用四个匹配点去解 H 时交比不变性都在暗中约束着解的可靠性。如果匹配点里有某个点发生误匹配算出来的 H 很可能让交比产生明显偏差根据这个偏差就能识别出外点。4.3 向相机标定和绝对二次曲线延伸再往深处走一步交比不变性还通向现代相机标定。射影几何里有一个经典结论平面上两条“圆环点”在相似变换下不变而圆环点本质上可以被理解为复平面上的无穷远点对。更漂亮的结论是绝对二次曲线在射影变换下保持不变而相机内参的约束就藏在绝对二次曲线图像的映射关系里。这些概念听着玄但源头都可以追溯到交比不变性因为交比是射影不变量所以一切可以被交比表达的结构在射影变换下都有稳定性。棋盘格标定法为什么能只用几张不同角度的照片就恢复内参因为角点之间的交比关系在成像过程中被保留下来多视角之间共享的射影不变量为优化提供了稳定约束。5. 最容易踩的坑和排查记录5.1 分母为零退化情形四点中有任何两点重合或者三点的关系让某个分母变成 0交比就会变成无穷大或未定义。比如 AB或者 BC都会让分式失去意义。实际使用中要提前检查尤其是自动提取角点时如果特征点重复程序很容易计算出一个巨大值。判断是否可用直接看分母绝对值是否小于某个阈值即可。5.2 顺序不对导致结果完全不对交比不是对称的。同样四个点按 A、B、C、D 算和按 A、B、D、C 算结果是倒数关系。如果拿这个结果和别人论文里的数值对比必须确认双方使用的是同一种顺序约定。很多库函数的参数名写得比较省事比如cross_ratio(p1, p2, p3, p4)但内部到底怎么排列四个点每个库都可能不一样。5.3 直接用原始像素坐标算交比畸变分分钟教你做人镜头畸变是交比在图像上失效的最大敌人。畸变会让原本共线的点变成一条轻微弯曲的曲线而交比不变性赖以成立的前提就是“四个点必须在同一条直线上”。如果照片来自广角镜头没有做去畸变处理直接拿像素坐标算交比结果通常会有百分之几甚至更多的偏差。正确做法是先做相机畸变校正或者至少先用直线拟合把所有点投影到拟合直线上再做一维参数化。我在实际项目中习惯用“先拟合直线再投影取参数”的方法能明显降低噪声带来的误差。5.4 把“比例”当成“交比”用网上有些讲法把交比说成“比例的比例”这只是一个辅助理解的说法不能直接当作 AC/BC 这种简单比例来用。长度比例在透视下会变而交比是两个比例的比值这样才能约掉透视带来的缩放效应。你如果在代码里只做一次除法那得到的不是交比而是普通比例结果当然会随视角变化。5.5 数值计算中的浮点误差齐次坐标归一化时如果某个像点恰好落在无穷远点附近也就是 w 分量非常小归一化之后坐标会爆掉。更稳妥的做法是不在欧氏坐标下归一化而是直接用齐次坐标算二阶行列式这样无穷远点也能参与计算。交比公式在齐次坐标下天然支持无穷远点这是它比普通距离比值更优雅的地方。6. 再往前一步交比与莫比乌斯变换如果继续沿着射影变换往下走会碰到复平面上的莫比乌斯变换[ w \frac{azb}{czd} ]这和前面讲到的一维射影变换是同构的。莫比乌斯变换有一个重要性质它保持复平面上四点交比不变。这个结论在复分析、调和函数、共形映射里都有应用。如果你学过复分析再回头看射影几何的交比会发现两个学科在这里完全汇合了。在三维重建和多视图几何里交比同样无处不在。基础矩阵、本质矩阵、单应矩阵的约束本质上都是射影不变量在不同几何结构上的体现。从某条直线上的四个点出发最后可以一路推导到整个多视图几何的架构这种“少即是多”的感觉正是射影几何的魅力所在。我自己在实际操作中的体会是交比不变性的证明只需要一行核心代数但真正把它用好需要大量的工程细节。比如先判断四点是否严格共线、再处理畸变、再约定点的顺序。每次在这些细节上较真都会避免一次算法结果的翻车。如果你正被某个透视问题困扰不妨先画一条直线取四个点算一下交比很多疑惑会迎刃而解。