Part III · 第 10 章 相机与投影 · 10.5Part III · Ch. 10 Cameras & Projection · 10.5

单应性 HomographyHomographies

同一块平面被两台相机看到(或一台相机看地面、机器人走了一步),两幅图像之间只差一个 3×3 矩阵:单应性。四个点对就能解出它,于是有了地面鸟瞰图、全景拼接、AprilTag 位姿、文档矫正和 10.4 节的平面标定。它只对平面(或纯旋转)成立:平面之外的一切都会出现视差,而这恰好是检测障碍物的线索。 When two cameras look at the same plane (or one camera looks at the floor before and after the robot takes a step), the two images differ by a single 3×3 matrix: a homography. Four point pairs determine it, which gives bird's-eye views of the ground, panorama stitching, AprilTag pose, document rectification and the plane-based calibration of Lesson 10.4. It holds only for a plane (or a pure rotation): everything off the plane shows parallax, and that is exactly the cue for detecting obstacles.

约 35 分钟~35 min 前置:1.6 秩与零空间 · 1.12 SVD · 1.13 最小二乘 · 5.3 SE(3) · 10.1 针孔模型 · 10.2 射影几何 · 10.3 内参与外参Prerequisites: 1.6 rank & null space · 1.12 SVD · 1.13 least squares · 5.3 SE(3) · 10.1 pinhole · 10.2 projective geometry · 10.3 intrinsics & extrinsics 5 个交互5 interactives

    1为什么机器人需要它Why robots need this

    相机把三维世界压成二维图像,深度丢了,一般无法反过来。但有一种特殊情形,反过来完全没有歧义:被看的点都落在同一个平面上。地面、桌面、墙、棋盘格、一页文档、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)。

    A camera squashes the 3D world into 2D and the depth is lost, so in general you cannot go back. One special case has no ambiguity at all: all the points you look at lie on one plane. The ground, a tabletop, a wall, a checkerboard, a page of a document, the black-and-white square of an AprilTag are all planes. When two cameras see the same plane, the relation between corresponding points in the two images is a single 3×3 matrix \(H\): \(\lambda\tilde{\mathbf x}'=H\tilde{\mathbf x}\). That matrix is called a homography.

    A second case is just as "free": the camera only rotates and does not translate (looking around from one spot, a pan-tilt head, a phone taking a panorama). Then it does not matter how deep the scene is: the two images again differ by a homography. This one 3×3 matrix carries a long list of robot-vision applications:

    • Bird's-eye view (inverse perspective mapping): turn the ground pixels of a forward camera into a top-down metric map for lane lines, AMR navigation and drivable area (FIG 5);
    • Obstacle detection: pixels on the ground obey \(H\), the ones that do not stand above the ground (FIG 2);
    • Panorama stitching: images from a rotating camera merge into one (FIG 3);
    • Pose of a planar marker: the four corners of an AprilTag / ArUco → \(H\) → the marker's pose relative to the camera; document and whiteboard rectification is the same computation;
    • Planar calibration: in Lesson 10.4 every checkerboard photo yields one \(H\), and Zhang's method recovers the intrinsics \(K\) from several of them;
    • SLAM initialization: when the scene is nearly planar or the camera nearly purely rotates, epipolar geometry (Lesson 11.1) degenerates and \(H\) takes over.

    We first build intuition with four handles (FIG 1) and watch the DLT solve the matrix from four point pairs; then derive \(H=K'(R+\mathbf t\mathbf n\T/d)K^{-1}\) from the geometry and let points off the plane give themselves away (FIG 2); then pure rotation (FIG 3), noise and normalization (FIG 4); finally a bird's-eye view of a synthetic road (FIG 5).

    2直觉:拖四个角,矩阵自己出来Intuition: drag four corners, the matrix follows

    想象把一张印好的图平放在桌上,从斜上方拍照:矩形变成了梯形,近大远小,直线仍是直线,平行线却可能汇聚。左图是原图,右图是你"拍到"的样子。拖动右图的四个角,每个角对应原图的一个角。四个点对 \((\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)\),消失点跑到无穷远,映射退化为仿射。

    Lay a printed picture flat on a table and photograph it from an oblique angle: the rectangle becomes a trapezoid, near parts are larger, straight lines stay straight and parallel lines may converge. The left image is the original, the right image is "what the camera sees". Drag the four corners of the right image; each corresponds to one corner of the original. Four pairs \((\mathbf x_i\mapsto\mathbf x_i')\) are exactly enough for one \(H\): each pair gives two equations, \(H\) has nine entries, but an overall scale changes nothing, so only 8 degrees of freedom remain, and \(4\times2=8\). Every frame runs the real DLT algorithm (derived in the math section), then maps every output pixel backwards through \(H^{-1}\) into the original and samples it bilinearly to produce the right image.

    The columns of \(H\) have a geometric meaning: columns 1 and 2 are the images of the points at infinity of the original's \(x\) and \(y\) axes, that is, vanishing points (Lesson 10.2); column 3 is the image of the origin. When the quadrilateral becomes a parallelogram the last row of \(H\) becomes \((0,0,1)\), the vanishing points run off to infinity, and the map degenerates to an affine one.

    FIG 1拖四个角:DLT 实时求 \(H\) 并扭曲图像Drag four corners: the DLT solves \(H\) live and warps the image
    原图 (x, y)SOURCE (x, y)
    拖动 ①②③④ → 扭曲后 (x′, y′)DRAG ①②③④ → WARPED (x′, y′)
    左右两幅图的像素坐标都是 \(v\) 向下的图像坐标。琥珀色手柄是 \(\mathbf x_i'\),DLT 用 \(\mathbf x_i=\) 原图四个角、\(\mathbf x_i'=\) 手柄位置解出 \(H\);青色虚线把原图上下边、左右边延长到消失点。手柄靠近"三点共线"或"平行四边形"位置时会轻微吸附。 Both panels use image coordinates with \(v\) pointing down. The amber handles are \(\mathbf x_i'\); the DLT solves \(H\) from \(\mathbf x_i=\) the four corners of the source and \(\mathbf x_i'=\) the handle positions. Cyan dashes extend the source's top/bottom and left/right edges to their vanishing points. Handles snap slightly near "three points collinear" and "parallelogram" positions.
    试一试Try this
    • 把上边两个角往中间收,做出"梯形"(像远处的墙)。读出 \(w\) 比值和消失点,棋盘格的横线怎样汇聚?Pull the two top corners toward the middle to make a trapezoid (like a far wall). Read the \(w\) ratio and the vanishing point: how do the checkerboard rows converge?
    • 把四边形拖成平行四边形(吸附会帮你)。\(h_{31},h_{32}\) 变成什么?平行线现在还平行吗?Drag the quadrilateral into a parallelogram (the snap helps). What do \(h_{31},h_{32}\) become? Are parallel lines parallel again?
    • 把三个角拖到一条直线上(会吸附)。\(H\) 的奇异值比 \(\sigma_3/\sigma_1\) 发生了什么?图像为什么消失了?Drag three corners onto one line (it snaps). What happens to the singular-value ratio \(\sigma_3/\sigma_1\) of \(H\)? Why does the image vanish?
    核心洞见Key insight

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

    A homography is an 8-degree-of-freedom projective map: straight lines stay straight, but lengths, angles and parallelism do not survive. Four point pairs (no three collinear) determine it exactly. If three target points are collinear but their sources are not, no invertible \(H\) exists (the DLT returns a singular matrix that squashes the picture onto a line); if three points are collinear in both images, only 7 independent equations remain and \(H\) is no longer unique.

    3实验:平面诱导的单应性与视差Play: the plane-induced homography and parallax

    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\) 的位置看到杆顶,而真正的杆顶在别处。这就是"地面单应性残差"检测障碍物的原理:地面像素残差为零,高出地面的物体残差正比于高度和基线。

    The \(H\) in FIG 1 was "fitted". For a real camera pair it is completely determined by the geometry. Let the plane be \(\mathbf n\T\mathbf X_1=d\) in camera 1's frame (\(\mathbf n\) a unit normal, \(d\) the distance from camera 1's centre to the plane) and let camera 2 be related by \(\mathbf X_2=R\mathbf X_1+\mathbf t\). Then (derived in the math section) $$H=K'\Big(R+\frac{\hl{t}{\mathbf t}\,\hl{n}{\mathbf n}\T}{\hl{d}{d}}\Big)K^{-1}.$$ In the lab below, cameras 1 and 2 look at a plane (which you can tilt) with a pole standing at its middle. Move camera 2, tilt the plane, change the pole height; the page does three things: it computes \(H\) from the geometry with the formula above; it solves \(H\) independently with the DLT from the projections of 25 points on the plane; and it uses \(H\) to carry points from camera 1 to camera 2. Points on the plane match perfectly (errors of order \(10^{-12}\) px); the pole tip is not on the plane, \(H\) carries it to the wrong place, and that error is the parallax.

    The 3D view shows why: \(H\) "pushes" camera 1's ray onto the plane and then looks at that plane point from camera 2. The ray through the pole tip first meets the plane at \(\mathbf Q\) (purple); \(H\) predicts that camera 2 sees the tip where it sees \(\mathbf Q\), but the real tip is elsewhere. That is the principle of detecting obstacles by the ground-homography residual: ground pixels have zero residual, objects above the ground have a residual proportional to their height and to the baseline.

    FIG 2平面诱导的单应性:公式 vs DLT,以及杆顶的视差Plane-induced homography: formula vs DLT, and the pole's parallax
    图像 1IMAGE 1
    图像 2:实线 = 真实,紫色 = H 的预测IMAGE 2: solid = actual, purple = predicted by H
    蓝色锥体 = 相机 1,绿色锥体 = 相机 2(光心、像平面)。青色网格是平面,琥珀色是杆。紫色点 \(\mathbf Q\) 是相机 1 经过杆顶的射线与平面的交点。图像 2 中紫色虚线网格是用 \(H\) 搬运图像 1 平面点的结果,与青色实线重合;紫色圆圈是 \(H\) 对杆顶的预测,红线是视差残差。图像坐标 \(v\) 向下。 Blue frustum = camera 1, green frustum = camera 2 (centre and image plane). The cyan grid is the plane, amber is the pole. The purple point \(\mathbf Q\) is where camera 1's ray through the pole tip meets the plane. In image 2 the purple dashed grid is image 1's plane points carried by \(H\); it coincides with the cyan solid grid. The purple ring is \(H\)'s prediction for the pole tip and the red line is the parallax residual. Image coordinates have \(v\) pointing down.
    试一试Try this
    • 移动相机 2 的方位角、再把平面倾斜 25° 以上。\(\mathbf n,d\) 和 \(H\) 都变了,"公式 − DLT"误差仍是 \(10^{-12}\) 量级吗?Move camera 2's azimuth, then tilt the plane by more than 25°. \(\mathbf n\), \(d\) and \(H\) all change; does "formula − DLT" stay near \(10^{-12}\)?
    • 把杆升高到 0.6 m 以上,杆顶残差超过 3 px,被标成"不在平面上"。再把杆高降到 0,残差消失。Raise the pole above 0.6 m: the tip residual exceeds 3 px and is flagged "off the plane". Lower it to 0 and the residual disappears.
    • 把相机 2 的方位角调到 −25°、高度调到 2.8 m(与相机 1 重合),杆保持高度。基线 \(\|\mathbf t\|\to0\),视差为什么也消失了?Set camera 2 to azimuth −25° and height 2.8 m (on top of camera 1) with the pole still tall. With the baseline \(\|\mathbf t\|\to0\), why does the parallax vanish too?
    同一个想法的三个视角One idea, three views

    几何:\(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 的纯旋转。

    Geometry: \(H\) means "drop the ray onto the plane, then look at it from the other camera". Algebra: \(R+\mathbf t\mathbf n\T/d\) equals \(R\mathbf X+\mathbf t\) on the plane and misses \(\mathbf t(1-d'/d)\) off it. Information: the plane equation "absorbs" the depth inside \(H\), so a single 3×3 matrix suffices whenever depth does not matter: a plane, or \(\mathbf t=0\). That is the pure rotation of FIG 3.

    4另外两个视角:纯旋转与噪声Two more views: pure rotation, and noise

    纯旋转:对任何场景都成立Pure rotation: valid for any scene

    让 \(\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)。

    Set \(\mathbf t=\mathbf 0\) and the whole term \(\mathbf t\mathbf n\T/d\) disappears: \(H=K'RK^{-1}\); neither \(\mathbf n\) nor \(d\) appears, and the scene may have any 3D structure. Intuitively, when the camera rotates about its centre each ray merely changes direction, and a point images along the same ray however far away it is. The scene below has 60 points at depths from 3 m to 25 m. The sliders rotate the camera about the vertical axis by \(\theta\) and (or not) translate it to the right by \(t_x\). The purple circles are the predictions of the best homography fitted to all points with the DLT; under pure rotation they coincide with the true points even though depths differ by a factor of eight. Once you translate, near points move more (\(\approx f\,t_x/Z\)) and no single \(H\) explains the image.

    Conversely, \(H\) reveals the rotation: \(R=K^{-1}HK\) (after scaling \(H\) by \(\det^{-1/3}\) so that \(\det=1\)), then \(\theta=\arccos\frac{\operatorname{tr}R-1}2\) or the \(\Log\) of Lesson 5.6. This is how panorama stitching estimates the relative rotation of neighbouring images (Brown–Lowe, 2007).

    FIG 3纯旋转 vs 平移:谁能被单应性解释Pure rotation vs translation: what a homography can explain
    图像 1(颜色 = 深度)IMAGE 1 (colour = depth)
    图像 2:实心 = 真实,圆圈 = 最优 HIMAGE 2: filled = actual, ring = best H
    琥珀色 = 近(\(Z\lt6\) m),紫色 = 中,青色 = 远(\(Z\ge12\) m)。红线从圆圈连到真实点,长度就是该点的残差。只统计同时出现在两幅图内的点。读数里"最优 \(H\) 残差"是 DLT 拟合后的最大值;"已知 \(R\) 的 \(K R K^{-1}\)"则完全不拟合,直接用真实旋转算。 Amber = near (\(Z\lt6\) m), purple = middle, cyan = far (\(Z\ge12\) m). Red lines run from the ring to the true point; their length is that point's residual. Only points visible in both images are counted. "Best-\(H\) residual" is the maximum after DLT fitting; "\(K R K^{-1}\) from the known \(R\)" fits nothing and uses the true rotation directly.
    试一试Try this
    • 选"纯旋转 15°"。残差是否是 \(10^{-10}\) 量级?读数里恢复出的角度对吗?再换一个角度试。Choose "pure rotation 15°". Is the residual of order \(10^{-10}\)? Is the recovered angle right? Try another angle.
    • 选"纯平移 0.6 m"。谁的残差大,近点还是远点?此时从 \(H\) 里"恢复"的旋转还是旋转矩阵吗(看正交性误差)?Choose "pure translation 0.6 m". Whose residual is larger, near or far points? Is the "recovered" rotation still a rotation (look at the orthogonality error)?

    带噪声的 DLT:归一化、点数与分布The DLT with noise: normalization, point count and spread

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

    Real data are noisy, come in more than four pairs, and contain mismatches. Below, Gaussian noise \(\sigma\) is added to the points of image 2 and \(H\) is estimated twice: by the Hartley-normalized DLT (cyan) and by the DLT on raw pixel coordinates (red). Both are scored by the RMS error on a 9×7 test grid over the whole 640×480 image (grey is the truth). Three knobs: number of points, the fraction of the image they occupy ("spread") and the noise. What to see: when points fill the image the two agree closely; when points are packed into a small region far from the coordinate origin, the raw DLT's condition number \(\kappa(A)\) explodes and its error is an order of magnitude larger; and in either case extrapolating to regions without points is dangerous. "Add outlier" shifts individual points by about 50 px and least squares is pulled off at once; "RANSAC" samples 4 points, fits repeatedly and keeps the inliers (Lesson 11.5 treats it in detail).

    FIG 4带噪声的 DLT:归一化 vs 未归一化The DLT with noise: normalized vs raw
    图像 2(640×480)IMAGE 2 (640×480)
    测试网格误差 vs 分布TEST-GRID ERROR vs SPREAD
    灰色 = 真实 \(H\) 搬运的网格,青色 = 归一化 DLT,红色 = 未归一化 DLT。琥珀色点是带噪声的 \(\mathbf x_i'\),红色圆环是外点,空心圆环外加绿色勾边表示 RANSAC 保留的内点。右图是当前点数和噪声下 15 次随机试验的中位数误差,竖线是当前分布。 Grey = grid carried by the true \(H\), cyan = normalized DLT, red = raw DLT. Amber dots are the noisy \(\mathbf x_i'\), red rings are outliers, and a green outline marks the inliers RANSAC kept. The right plot shows the median error over 15 random trials at the current point count and noise; the vertical line marks the current spread.
    试一试Try this
    • 把"分布"拉到 25% 以下。两种 DLT 的误差差几倍?\(\kappa(A)\) 差几个数量级?再多加点数,误差能救回来吗?Pull the "spread" below 25 %. By what factor do the two DLT errors differ, and by how many orders of magnitude do the \(\kappa(A)\) differ? Does adding more points rescue the error?
    • 点"加外点"三次,看最小二乘的网格被拖偏;切到 RANSAC,误差降到最小二乘误差的五分之一以下,回到读数里"去掉外点"的量级。Press "Add outlier" three times and watch the least-squares grid get pulled; switch to RANSAC and the error drops below a fifth of the least-squares error, back to the order of the readout's "without outliers" value.

    5数学The math

    提示:把鼠标悬停在公式中带底色的符号上,FIG 2 的 3D 视图中对应的元素会被高亮。Tip: hover the highlighted symbols in the formulas; the matching element in FIG 2's 3D view lights up.

    单应性是什么:8 个自由度What a homography is: 8 degrees of freedom

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

    In the homogeneous coordinates \(\tilde{\mathbf x}=(x,y,1)\T\) of Lesson 10.2, a homography is an invertible 3×3 matrix acting on \(\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}\)。

    \(cH\) (\(c\neq0\)) gives the same map, so the nine entries carry only 8 degrees of freedom; each point pair supplies 2 equations, so at least 4 pairs are needed. The denominator \(w=h_{31}x+h_{32}y+h_{33}\) is FIG 1's "\(w\) ratio", and dividing by \(w\) is what makes the map nonlinear. If the last row of \(H\) is \((0,0,1)\) the map is affine (6 DoF, 3 pairs, parallelism preserved); if the upper-left 2×2 is additionally a rotation times a scale it is a similarity (4 DoF, 2 pairs). Composition is matrix multiplication, \(H_{13}=H_{23}H_{12}\), and the reverse direction is \(H^{-1}\).

    直接线性变换(DLT)The direct linear transform (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\),展开:

    \(\lambda\) is unknown, so instead of \(\tilde{\mathbf x}'=H\tilde{\mathbf x}\) we state that the two vectors are parallel: \(\tilde{\mathbf x}'\times H\tilde{\mathbf x}=\mathbf 0\) (cross product, Lesson 1.8). Write \(\tilde{\mathbf x}'=(u',v',1)\T\) and let \(\mathbf h_1\T,\mathbf h_2\T,\mathbf h_3\T\) be the rows of \(H\). Expanding:

    $$ \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\) 时方程无精确解,取

    The third row is a linear combination of the first two (\(u'\times\)row 1 \(+\,v'\times\)row 2 \(=-\)row 3), so every pair contributes only 2 independent equations: that is the "8 = 4×2". Stack the \(A_i\) of \(n\) pairs into \(A\in\R^{2n\times9}\): \(A\mathbf h=\mathbf 0\). With exactly 4 points (no three collinear) \(A\) has rank 8, its null space (Lesson 1.6) is one-dimensional and \(\mathbf h\) is unique up to scale; for \(n>4\) there is no exact solution and we take

    $$ \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\|\) 叫代数误差,它没有几何含义,只是方便;本节末尾会回到几何误差。

    (The SVD of Lesson 1.12.) If three points are collinear in both images, the rank drops to 7, \(\sigma_8\approx0\), the null space gains a dimension and \(H\) is not unique; if they are collinear in one image only, \(A\) keeps full rank but the solution \(H\) is singular (the \(\sigma_3(H)/\sigma_1(H)\) readout of FIG 1). \(\|A\mathbf h\|\) is the algebraic error: it has no geometric meaning and is merely convenient; we return to geometric errors at the end of this section.

    Hartley 归一化:为什么先挪动坐标Hartley normalization: why shift the coordinates first

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

    Pixel coordinates are in the hundreds, so one row of \(A\) mixes the scales \(1\), \(x\sim10^2\) and \(u'x\sim10^4\); \(\kappa(A)\) exceeds \(10^6\), and the smallest singular vector reacts violently to noise (see FIG 4's readout). The remedy: apply a similarity \(T,T'\) to each image, translating the centroid to the origin and scaling the mean distance from the origin to \(\sqrt2\); solve for \(\hat H\) in normalized coordinates, then transform back:

    $$ 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。

    It adds no points and does not change the solution for ideal data (with four noise-free points both DLTs are equally exact); it only improves the conditioning, at the cost of a few lines of code. Hartley (1997) proposed it for the eight-point algorithm, and the same idea applies to every DLT.

    平面诱导的单应性的推导Deriving the plane-induced homography

    相机 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":

    Camera 2's coordinates are \(\mathbf X_2=R\mathbf X_1+\mathbf t\) (as in Lesson 5.3: \(R,\mathbf t\) is the relative pose camera 1 → camera 2) and the plane is \(\mathbf n\T\mathbf X_1=d\), \(\mathbf n\) a unit normal in camera 1's frame, \(d>0\). Points on the plane satisfy \(\mathbf n\T\mathbf X_1/d=1\), so \(\mathbf t\) may be multiplied by this "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\) 时为零。

    This uses \(\mathbf X_1=\lambda K^{-1}\tilde{\mathbf x}_1\), with \(\lambda\) swallowed by "\(\sim\)". A few remarks.

    • Sign: the plane is written \(\mathbf n\T\mathbf X=d\) here, hence the plus. Hartley–Zisserman write the plane as \(\mathbf n\T\mathbf X+d=0\) and obtain \(R-\mathbf t\mathbf n\T/d\). FIG 2 verifies the plus sign numerically; the wrong sign is off by hundreds of pixels.
    • Only \(\mathbf t/d\) appears: scaling the scene and the baseline by 2 leaves \(H\) unchanged, which is the scale ambiguity of monocular vision.
    • Euclidean homography: \(K'^{-1}HK=R+\mathbf t\mathbf n\T/d\) contains only motion and plane. Decomposing it yields \((R,\mathbf t/d,\mathbf n)\), with up to 4 mathematical solutions, usually 2 after requiring the points to be in front of both cameras, and a third view or a known normal resolves the rest (Malis–Vargas 2007; OpenCV's decomposeHomographyMat).
    • Points off the plane: if \(\mathbf n\T\mathbf X_1=d'\neq d\), then \(\mathbf X_2=(R+\mathbf t\mathbf n\T/d)\mathbf X_1+\mathbf t\,(1-d'/d)\). The extra \(\mathbf t(1-d'/d)\) is the parallax: proportional to the baseline \(\mathbf t\) and to the distance from the plane, directed along the epipolar line (towards the epipole, Lesson 11.1). It vanishes for \(\mathbf t=\mathbf 0\).

    三个特例:纯旋转、地面 \(z=0\)、平面目标的位姿Three special cases: pure rotation, the ground \(z=0\), and the pose of a planar target

    $$ \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\) 向上):

    Pure rotation: \(d\to\infty\) (the plane at infinity) acts like \(\mathbf t=\mathbf 0\), giving \(H_\infty=K'RK^{-1}\). If the camera rotates by \(\theta\) about its centre, with equal \(K\), the image centre moves by about \(f\tan\theta\) pixels (\(\approx f\theta\) for small angles), independent of depth. The ground: a point \(\mathbf X=(X,Y,0)\) of the world plane \(Z=0\) has \(\mathbf x_c=R\mathbf X+\mathbf t=\mathbf r_1X+\mathbf r_2Y+\mathbf t\); the third column \(\mathbf r_3\) is multiplied by 0 and drops out, so \(H_g=K[\mathbf r_1\ \mathbf r_2\ \mathbf t]\), where \((R,\mathbf t)\) are the extrinsics world → camera \({}^cT_w\) (Lesson 10.3). For a forward-looking camera at height \(h\), pitched down by \(\alpha\) (world \(X\) right, \(Y\) forward, \(Z\) up):

    $$ 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 节)或迭代优化。

    \(Y\to\infty\) gives the horizon \(v=c_y-f\tan\alpha\). Conversely, recovering the camera pose from \(H\) (the pose of a planar target, the first step of AprilTag and of Lesson 10.4's calibration): \(K^{-1}H_g\propto[\mathbf r_1\ \mathbf r_2\ \mathbf t]\); take \(\lambda=1/\|K^{-1}\mathbf h_1\|\) so that \(\mathbf r_1\) is a unit vector, set \(\mathbf r_3=\mathbf r_1\times\mathbf r_2\), project \([\mathbf r_1\ \mathbf r_2\ \mathbf r_3]\) onto the nearest rotation by SVD (\(R=UV\T\), Lesson 1.12) and pick the sign with \(t_z>0\) (the target is in front of the camera). FIG 5's readout recovers the camera height and pitch from a 4-point DLT with exactly this recipe. With noisy data PnP (Lesson 11.4) or iterative refinement does better.

    误差:代数、几何与最大似然Errors: algebraic, geometric and maximum likelihood

    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 精化。

    What the DLT minimizes, \(\|A\mathbf h\|\), is an algebraic quantity; what you really want is pixel error. The transfer error \(\sum_i\|\mathbf x_i'-\pi(H\tilde{\mathbf x}_i)\|^2\) (\(\pi\) divides by \(w\)) counts the error in image 2 only; the symmetric transfer error adds \(\|\mathbf x_i-\pi(H^{-1}\tilde{\mathbf x}_i')\|^2\); if points in both images are noisy, the maximum-likelihood criterion is the reprojection error: estimate \(H\) and the exact points \(\hat{\mathbf x}_i,\hat{\mathbf x}_i'\) together (the Sampson distance is its first-order approximation). The latter two are nonlinear least squares solved by Gauss–Newton / LM (Lessons 6.6, 6.9) started from the DLT result. OpenCV's findHomography also runs an LM refinement on the inliers after RANSAC.

    6在机器人里:鸟瞰图(逆透视映射)In robotics: the bird's-eye view (inverse perspective mapping)

    前视相机在路上看到的车道线汇聚到消失点,这对"在地图上走多远、车道多宽"毫无帮助。如果假设地面是平面,则 \(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\) 是高度)。

    The lane lines seen by a forward camera converge to a vanishing point, which is no help for "how far to drive" or "how wide is the lane". If we assume the ground is a plane, \(H_g\) maps ground coordinates \((X,Y)\) in metres to pixels, and its inverse \(H_g^{-1}\) maps every pixel back to metric ground coordinates. For every output pixel \((X,Y)\) of the bird's-eye view, \(H_g\) tells where to sample the camera image, producing a top-down metric picture: lane lines parallel, lane width a constant 3.5 m, uniform distance ticks. That is inverse mapping (output → input), so no holes appear. Below is a synthetic two-lane road (every pixel is rendered by intersecting rays with the ground) with adjustable camera height \(h\) and pitch \(\alpha\). \(H_g\) can come from two sources: the formula \(K[\mathbf r_1\ \mathbf r_2\ \mathbf t]\) (mounting height and pitch known) or four handles: click the four corners of a known rectangle on the ground (the crossings of the lane lines with two painted cross-bars, 3.5 m × 10 m) and run the DLT, which is what you do when there is no calibration data.

    But this holds only for things on the ground. An object standing above the ground (the amber box) violates the planar assumption: the ray through its top continues to a farther ground point, so the box is smeared along the line of sight. The similar triangles of the side view give the landing point of the top \(d'=d\,\dfrac{h}{h-z_b}\) (\(d\) the horizontal distance, \(z_b\) the height).

    FIG 5鸟瞰图:由地面单应性做逆透视映射Bird's-eye view: inverse perspective mapping by the ground homography
    前视相机图像 (u, v)FORWARD CAMERA (u, v)
    侧视图(竖直方向拉伸):为什么箱子被拖长SIDE VIEW (vertical stretched): why the box smears
    鸟瞰图(米制,0.1 m/像素)BIRD'S-EYE VIEW (metric, 0.1 m/px)
    "4 点"模式下,把相机图里的四个琥珀色手柄点在矩形角上(对应地面坐标 \((\pm1.75,5)\)、\((\pm1.75,15)\) m);初始位置是取整到像素的真实投影,拖离它就像点错了。拖动相机高度或俯仰会让手柄重新回到真实位置。鸟瞰图里的虚线框是箱子的真实占地,被拖长的琥珀色区域就是违反平面假设的后果。 In "4 points" mode, place the four amber handles of the camera image on the corners of the rectangle (ground coordinates \((\pm1.75,5)\), \((\pm1.75,15)\) m); they start at the true projections rounded to whole pixels, and dragging one away is like clicking the wrong spot. Changing the camera height or pitch puts the handles back on the true positions. The dashed frame in the bird's-eye view is the box's true footprint; the stretched amber region is the price of violating the planar assumption.
    试一试Try this
    • 把箱子高度升到 0.8 m 以上。侧视图里顶端射线落在哪里?读数里的 \(d'\) 与鸟瞰图里的拖长对得上吗?Raise the box above 0.8 m. Where does the ray through the top land in the side view? Does the readout's \(d'\) match the smear in the bird's-eye view?
    • 切到"4 点",把一个手柄拖离 15 像素以上。车道线还平行吗?读数里的车道宽度、恢复出的高度和俯仰变成多少?Switch to "4 points" and drag one handle more than 15 px away. Are the lane lines still parallel? What do the lane widths and the recovered height and pitch become?
    真实系统里In real systems

    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\)。

    OpenCV: getPerspectiveTransform (4 points → \(H\)), findHomography (DLT + RANSAC / LMEDS / RHO, with LM refinement), warpPerspective (inverse mapping + interpolation), decomposeHomographyMat. AprilTag / ArUco: estimate \(H\) from the tag's four corners, then recover the tag pose (the AprilTag reference implementation has a "pose from homography" step; OpenCV's ArUco typically uses planar PnP, Lesson 11.4). Lanes and drivable area: the classic car and AMR recipe is the IPM bird's-eye view; end-to-end driving stacks now mostly use learned BEV representations (e.g. Lift-Splat-Shoot, BEVFormer), partly because IPM's "the ground is a plane" assumption fails on slopes and for vehicles. Panorama stitching: OpenCV's Stitcher follows Brown–Lowe, estimating rotations and running bundle adjustment. ORB-SLAM: initialization estimates both \(H\) and \(F\) and picks a model by score, choosing \(H\) for planar or low-parallax scenes. Visual servoing: 2½D visual servoing (Malis et al.) decomposes the homography between the current and desired images into a rotation and a normalized translation (Part IV). Lesson 10.4: every checkerboard image of Zhang's calibration first yields one \(H\).

    7常见误区Common pitfalls

    误区 1:平面假设不成立,却以为 \(H\) 在说真话Pitfall 1: the plane assumption fails and you still trust \(H\)

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

    Pole tops, box tops, vehicles, kerbs and slopes are not "on the ground": the tip residual in FIG 2 grows with height and baseline, and in FIG 5 the box is smeared metres away. Near-planar scenes (distant buildings, farmland seen from the air) may use \(H\), but the error grows with parallax; only under pure rotation does any scene work. If the camera also translates while stitching, use depth or hide the seams by blending.

    误区 2:退化与病态的点分布Pitfall 2: degenerate and ill-conditioned point layouts

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

    Three collinear points (FIG 1) either make \(H\) singular (collinear in one image only) or make \(A\) rank-deficient and \(H\) non-unique (collinear in both); nearly collinear points or points crowded into one corner (FIG 4 at 10 % spread) are "almost" rank-deficient, the solution is extremely noise-sensitive, and extrapolating elsewhere amplifies the error hundredfold. Spread the points: an AprilTag's four corners form a well-posed rectangle, yet a tiny, distant tag still gives an unstable pose under pixel noise; calibration boards should fill the field of view.

    误区 3:不归一化,或不处理外点Pitfall 3: no normalization, or no outlier handling

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

    An un-normalized DLT may look "fine" when the points fill the image but degrades sharply once they cluster (FIG 4's red curve), and the fix is a few lines. Least squares has no immunity to outliers: one 50 px mismatch can drag the whole grid by tens of pixels. Feature matching always contains mismatches, so the real pipeline is "match → RANSAC for inliers → DLT + LM refinement on the inliers" (Lesson 11.5).

    误区 4:方向、除以 \(w\)、前向映射Pitfall 4: direction, dividing by \(w\), and forward mapping

    三个小错误。①方向:\(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 才是反过来。

    Three small errors. ① Direction: \(H\) carries image-1 points to image 2; going image 2 → image 1 needs \(H^{-1}\), and using the wrong one mirrors or displaces the whole picture. ② Forgetting to divide by \(w\): the first two components of \(H\tilde{\mathbf x}\) are not pixel coordinates; near FIG 5's horizon \(w\to0\) and coordinates fly to infinity. ③ Forward mapping: pushing every input pixel to the output leaves holes and overlaps; instead sample the input for each output pixel through the inverse map (what FIG 1 and FIG 5 do, and what warpPerspective does). A related trap: warpPerspective takes \(H\) as src → dst by default, and you need WARP_INVERSE_MAP for the opposite.

    误区 5:用仿射代替射影Pitfall 5: using an affine map for a projective one

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

    getAffineTransform solves 6 parameters from 3 pairs and always preserves parallelism. For a plane seen obliquely at close range this produces systematic distortion: fitting FIG 1's trapezoid with an affine map matches at most three of the four corners. Affine suits only weak perspective (depth variation much smaller than the distance, e.g. from far above).

    误区 6:符号约定与尺度Pitfall 6: sign conventions and scale

    \(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\) 时会爆炸;比例也可能带着负号。

    \(R+\mathbf t\mathbf n\T/d\) or \(R-\mathbf t\mathbf n\T/d\)? It depends on whether \(\mathbf X_2=R\mathbf X_1+\mathbf t\) or the reverse, whether the plane is \(\mathbf n\T\mathbf X=d\) or \(+d=0\), and which way \(\mathbf n\) points. When reading a paper or calling a library, verify numerically on known points first. Also, \(H\) is defined only up to scale: normalize before comparing two of them (\(\|H\|_F=1\)); "set \(h_{33}=1\)" blows up when \(h_{33}\approx0\), and the scale may carry a minus sign.

    8小练习Check yourself

    1. 用 DLT 估计两幅图像之间的单应性,至少需要几个点对(任意三点不共线)?1. At least how many point pairs (no three collinear) does the DLT need to estimate the homography between two images?
    \(H\) 有 9 个元素,整体比例不起作用,剩 8 个自由度;每个点对给 2 个独立方程,所以 \(8/2=4\)。3 个点对是仿射变换(6 个自由度)所需的个数,8 是误把"8 个自由度"当成"8 个点"。\(H\) has 9 entries, the overall scale is irrelevant, leaving 8 degrees of freedom; each pair gives 2 independent equations, so \(8/2=4\). Three pairs is what an affine map (6 DoF) needs; 8 mistakes "8 degrees of freedom" for "8 points".
    2. 相机 \(f=600\) px,主点在图像中心。相机绕光心水平转动 3°(没有平移)。图像中心附近的点大约移动多少像素?2. A camera has \(f=600\) px and its principal point at the image centre. It pans horizontally by 3° about its optical centre (no translation). About how many pixels does a point near the image centre move?
    \(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\))。With \(H=KRK^{-1}\), the ray along the axis \((0,0,1)\) turns to \((\sin\theta,0,\cos\theta)\), a displacement of \(f\tan\theta=600\tan3^\circ\approx31.4\) px, independent of depth, which is the signature of pure rotation. 0 confuses "no parallax" with "no motion"; 314 slips 3° into 30° (\(600\times0.524\)).
    3. 用地面上的特征估出地面单应性 \(H\),再用它搬运一根 1 m 高杆的顶端像素。得到的位置是?3. You estimate the ground homography \(H\) from ground features and use it to transfer the image of the top of a 1 m pole. The result is:
    \(H\) 对地面点才正确。杆顶像素的射线在地面上先交于一点 \(\mathbf Q\)(FIG 2 的紫色点),\(H\) 预测的就是 \(\mathbf Q\) 在图 2 里的像。它不是杆根(除非相机恰好在杆的正上方),也不是杆顶真实的位置;差值(视差)正比于杆高和基线,基线为零时消失。\(H\) is right only for ground points. The ray through the pole-top pixel meets the ground at a point \(\mathbf Q\) (FIG 2's purple point), and \(H\) predicts the image of \(\mathbf Q\) in image 2. That is neither the foot (unless the camera is exactly above the pole) nor the true tip; the difference (parallax) is proportional to the pole height and the baseline, and vanishes when the baseline is zero.
    4. Hartley 归一化主要解决什么问题?4. What does Hartley normalization mainly fix?
    它只是坐标的相似变换,不改变理想数据的解、不减少点数、不处理外点(那是 RANSAC 的事),只把 \(\kappa(A)\) 从 \(10^6\) 量级降到 \(10^2\) 量级。It is only a similarity of the coordinates: it neither changes the solution for ideal data, nor reduces the point count, nor handles outliers (that is RANSAC's job); it brings \(\kappa(A)\) from order \(10^6\) down to order \(10^2\).
    5. 相机高 2 m,鸟瞰图假设地面是平面。一个 0.5 m 高的箱子,水平距离 9 m。箱子顶端的点在鸟瞰图中会落在距离多远处?5. A camera 2 m high builds a bird's-eye view assuming the ground is a plane. A 0.5 m tall crate stands 9 m away horizontally. At what distance does a point on the crate's top land in the bird's-eye view?
    相似三角形:\(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\)。By similar triangles, \(d'/h=d/(h-z_b)\), so \(d'=9\times2/(2-0.5)=12\) m. The top is "projected" to where the ray meets the ground, 3 m farther than the truth; as \(z_b\to h\), \(d'\to\infty\). 9 ignores the height; 18 simply multiplies \(d\) by \(h\).

    9延伸阅读Further reading

    • R. Hartley & A. Zisserman, Multiple View Geometry in Computer Vision, 2nd ed., Cambridge University Press, 2004 — 第 4 章(二维射影变换的估计:DLT、归一化、代价函数)与第 13 章(场景平面与单应性、平面诱导的 \(H\))Ch. 4 (estimating 2D projective transformations: DLT, normalization, cost functions) and Ch. 13 (scene planes and homographies, the plane-induced \(H\))
    • R. Hartley, In Defense of the Eight-Point Algorithm, IEEE Trans. PAMI 19(6), 1997 — 坐标归一化的出处The origin of coordinate normalization
    • R. Szeliski, Computer Vision: Algorithms and Applications, 2nd ed., Springer, 2022 — 第 8 章图像对齐与拼接(第 1 版为第 9 章)Ch. 8 on image alignment and stitching (Ch. 9 of the 1st ed.)
    • M. Brown & D. G. Lowe, Automatic Panoramic Image Stitching using Invariant Features, IJCV 74(1), 2007 — 用旋转模型和单应性自动拼接全景Automatic panoramas from a rotation model and homographies
    • Z. Zhang, A Flexible New Technique for Camera Calibration, IEEE Trans. PAMI 22(11), 2000 — 由多个平面单应性求内参,10.4 节的方法Intrinsics from several plane homographies, the method of Lesson 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)\) 的多解性与选择The multiple solutions of decomposing \(H\) into \((R,\mathbf t/d,\mathbf n)\) and how to choose
    • E. Olson, AprilTag: A Robust and Flexible Visual Fiducial System, ICRA 2011 — 用四个角点的单应性估计标签位姿Tag pose from the homography of four corners
    • 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\) 之间选择Model selection between \(H\) and \(F\) at initialization
    • E. Malis, F. Chaumette & S. Boudet, 2½D Visual Servoing, IEEE Trans. Robotics and Automation 15(2), 1999 — 用单应性做视觉伺服Visual servoing with homographies