成像几何基础:针孔相机模型、坐标系转换、内参与外参矩阵

各位同学,今天我们聊一个非常核心的话题——成像几何。说白了,就是搞明白「世界上的一个点,是怎么跑到照片上的」。这个问题我当年刚入行时也绕了很久,后来发现,只要把针孔模型和坐标系转换吃透,后面所有双目视觉的东西都会顺很多。

一、针孔相机模型——最朴素的成像原理

先别被「模型」两个字吓到。针孔相机模型,本质上就是一个暗箱加一个小孔。光线从物体上反射过来,穿过小孔,在后面的感光平面上形成一个倒立的像。嗯,就这么简单。

数学上怎么描述?我们设相机光心为原点,光轴指向物体方向为Z轴。那么一个三维点 (X, Y, Z) 在成像平面上的投影位置 (x, y) 满足:

x = f * X / Z
y = f * Y / Z

这里的 f 就是焦距。注意,这个公式成立的前提是成像平面在光心后方。实际相机为了便于处理,通常把成像平面「虚拟」到光心前方,这样图像就是正立的了。

核心要点:针孔模型是线性模型,但真实相机存在畸变。我在项目中遇到过,直接用针孔模型标定广角镜头,误差能到十几个像素。所以后面我们还会讲畸变校正。

二、四个坐标系——你中有我,我中有你

做双目视觉,绕不开这四个坐标系。我习惯把它们想象成「四层套娃」:

  1. 世界坐标系:你说了算。随便选一个原点,比如车头中心、路口标志杆。单位是米。
  2. 相机坐标系:以相机光心为原点,Z轴朝前。单位也是米。
  3. 图像坐标系:在成像平面上,原点在光轴与平面的交点(主点)。单位是毫米。
  4. 像素坐标系:就是你在图像上看到的行列号。原点在左上角,单位是像素。

为什么会搞这么复杂?你想想看,世界上的物体是三维的,照片是二维的。每转换一次,就丢掉一个维度信息。而双目视觉的核心,就是通过两个相机把丢掉的深度信息「找回来」。

三、坐标系转换——从世界到像素的完整链条

一个点从世界坐标系到像素坐标系,要经过三次变换。我把它写成一条链:

世界 → 相机 → 图像 → 像素

每一步都有对应的矩阵操作。咱们一步步拆开看。

3.1 世界坐标系 → 相机坐标系(外参矩阵)

这一步用到的就是外参矩阵。它包含旋转矩阵 R 和平移向量 t。说白了,就是把世界坐标系「搬到」相机坐标系的位置和朝向。

P_cam = R * P_world + t

这里 R 是3x3的旋转矩阵,t 是3x1的平移向量。我刚开始学的时候,总觉得旋转矩阵很抽象。后来发现,你只要记住它描述的是「相机在世界中的姿态」就够了。具体数值,标定的时候会自动算出来。

我的经验:外参矩阵对双目系统极其重要。两个相机之间的外参(相对位姿)直接决定了深度估计的精度。我曾经因为外参标定差了0.1度,导致30米外的测距误差达到了半米。嗯,后来我养成了每次上车前先做一次外参校验的习惯。

3.2 相机坐标系 → 图像坐标系(内参矩阵的一部分)

这一步就是针孔模型的投影。把三维点 (X_c, Y_c, Z_c) 投影到归一化平面上:

x = X_c / Z_c
y = Y_c / Z_c

注意,这里得到的是归一化坐标,单位是「米/米」,无量纲。后面还要乘上焦距和像素尺寸,才能变成像素坐标。

3.3 图像坐标系 → 像素坐标系(内参矩阵的另一部分)

这一步把物理坐标变成像素坐标。需要两个参数:

  • f_x, f_y:焦距在x和y方向上的像素当量(单位:像素/米)
  • c_x, c_y:主点坐标(单位:像素)

合起来就是:

u = f_x * x + c_x
v = f_y * y + c_y

把前面两步合并,用齐次坐标表示,就是经典的内参矩阵 K

K = [[f_x,   0, c_x],
     [  0, f_y, c_y],
     [  0,   0,   1]]

四、内参与外参矩阵——相机的「身份证」和「定位器」

我个人喜欢这样比喻:

  • 内参矩阵:相机的「身份证」。它告诉你这个相机本身的特性——焦距多少、像素多大、主点在哪。同一个相机,内参是固定的(除非你调焦或变分辨率)。
  • 外参矩阵:相机的「定位器」。它告诉你相机在世界中的位置和朝向。相机一旦移动,外参就变了。

在双目视觉中,我们通常把左相机的外参设为单位矩阵(即左相机坐标系作为参考),右相机的外参就是相对于左相机的旋转和平移。这个相对外参,我们一般叫它 R, t(或者 R_lr, t_lr)。

避坑指南:我曾经在项目中犯过一个低级错误——把内参矩阵中的 f_xf_y 搞反了。结果深度图出来全是歪的。后来排查了两天才发现。所以,拿到标定结果后,第一件事就是验证内参是否正确。怎么验证?拍一张棋盘格,用内参反投影回去,看看重投影误差。

五、知识体系总览

下面这张图是我自己整理的,把整个成像几何的脉络画出来了。你可以把它当作一个「地图」,学完这一章后,对照着检查自己是否每个环节都理解了。

成像几何知识体系 世界坐标系 (Xw, Yw, Zw) 单位:米 外参 R, t 相机坐标系 (Xc, Yc, Zc) 单位:米 投影 针孔模型 图像坐标系 (x, y) 单位:毫米 量化 f_x, f_y, c_x, c_y 像素坐标系 (u, v) 单位:像素 内参矩阵 K [f_x, 0, c_x; 0, f_y, c_y; 0, 0, 1] 相机「身份证」 外参矩阵 [R | t] 相机「定位器」 完整变换链(齐次坐标形式) [u, v, 1]^T = K · [R | t] · [Xw, Yw, Zw, 1]^T 世界点 → 外参变换 → 相机点 → 内参投影 → 像素点

六、完整变换公式——把一切串起来

把上面所有步骤合并,就是一条完整的变换链。用齐次坐标写出来,非常简洁:

[u]   [f_x   0   c_x]   [r11 r12 r13 t1]   [Xw]
[v] = [  0  f_y  c_y] · [r21 r22 r23 t2] · [Yw]
[1]   [  0    0    1]   [r31 r32 r33 t3]   [Zw]
                                              [1]

左边是像素坐标,右边是世界坐标。中间两个矩阵,左边是内参,右边是外参。这个公式,我建议你手推一遍。真的,推完一遍,你对成像几何的理解会上一个台阶。

一个小技巧:在实际代码中,我们通常不会直接写这个矩阵乘法。OpenCV 提供了 projectPoints() 函数,一步到位。但理解背后的原理,能帮你更快地排查问题。比如,当你发现投影点偏了,你能立刻判断是内参问题还是外参问题。

七、总结

成像几何是双目视觉的基石。针孔模型告诉我们「怎么投影」,坐标系转换告诉我们「怎么对齐」,内参和外参矩阵告诉我们「相机是什么、在哪、朝哪看」。这四个东西搞明白了,后面立体匹配、三角测量、深度估计,都是水到渠成的事。

嗯,这一章内容不少,但都是硬核干货。我建议你花点时间,把每个公式在纸上写一遍,再对照着标定数据算一算。相信我,这个投入绝对值得。


公众号:蓝海资料掘金营,微信 deep3321