成像几何基础:针孔相机模型、坐标系转换、内参与外参矩阵
各位同学,今天我们聊一个非常核心的话题——成像几何。说白了,就是搞明白「世界上的一个点,是怎么跑到照片上的」。这个问题我当年刚入行时也绕了很久,后来发现,只要把针孔模型和坐标系转换吃透,后面所有双目视觉的东西都会顺很多。
一、针孔相机模型——最朴素的成像原理
先别被「模型」两个字吓到。针孔相机模型,本质上就是一个暗箱加一个小孔。光线从物体上反射过来,穿过小孔,在后面的感光平面上形成一个倒立的像。嗯,就这么简单。
数学上怎么描述?我们设相机光心为原点,光轴指向物体方向为Z轴。那么一个三维点 (X, Y, Z) 在成像平面上的投影位置 (x, y) 满足:
x = f * X / Z
y = f * Y / Z
这里的 f 就是焦距。注意,这个公式成立的前提是成像平面在光心后方。实际相机为了便于处理,通常把成像平面「虚拟」到光心前方,这样图像就是正立的了。
核心要点:针孔模型是线性模型,但真实相机存在畸变。我在项目中遇到过,直接用针孔模型标定广角镜头,误差能到十几个像素。所以后面我们还会讲畸变校正。
二、四个坐标系——你中有我,我中有你
做双目视觉,绕不开这四个坐标系。我习惯把它们想象成「四层套娃」:
- 世界坐标系:你说了算。随便选一个原点,比如车头中心、路口标志杆。单位是米。
- 相机坐标系:以相机光心为原点,Z轴朝前。单位也是米。
- 图像坐标系:在成像平面上,原点在光轴与平面的交点(主点)。单位是毫米。
- 像素坐标系:就是你在图像上看到的行列号。原点在左上角,单位是像素。
为什么会搞这么复杂?你想想看,世界上的物体是三维的,照片是二维的。每转换一次,就丢掉一个维度信息。而双目视觉的核心,就是通过两个相机把丢掉的深度信息「找回来」。
三、坐标系转换——从世界到像素的完整链条
一个点从世界坐标系到像素坐标系,要经过三次变换。我把它写成一条链:
世界 → 相机 → 图像 → 像素
每一步都有对应的矩阵操作。咱们一步步拆开看。
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_x 和 f_y 搞反了。结果深度图出来全是歪的。后来排查了两天才发现。所以,拿到标定结果后,第一件事就是验证内参是否正确。怎么验证?拍一张棋盘格,用内参反投影回去,看看重投影误差。
五、知识体系总览
下面这张图是我自己整理的,把整个成像几何的脉络画出来了。你可以把它当作一个「地图」,学完这一章后,对照着检查自己是否每个环节都理解了。
六、完整变换公式——把一切串起来
把上面所有步骤合并,就是一条完整的变换链。用齐次坐标写出来,非常简洁:
[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