2. 相机成像模型:从世界到像素的数学之旅

做双目视觉,第一件事不是调算法,而是搞懂相机是怎么「看」世界的。说白了,相机成像模型就是一套数学规则,告诉你三维空间里的一个点,最终落在图像传感器的哪个像素上。我刚开始接触这个领域时,总觉得这些坐标系绕来绕去很烦人。但后来发现,不理解这个,标定和校正根本无从下手。

这一节,我们就把针孔相机模型、四个坐标系、内外参这些东西彻底讲清楚。

2.1 针孔相机模型:最朴素的成像原理

针孔相机模型,是所有相机模型的鼻祖。它假设光线通过一个小孔,在后面的成像平面上形成倒立的像。你想想看,这其实跟初中物理课上做的实验一模一样。

数学上,这个模型可以用一个简单的相似三角形关系来描述:

X_image = f * (X_world / Z_world)
Y_image = f * (Y_world / Z_world)

其中 f 是焦距,也就是小孔到成像平面的距离。实际相机虽然用了透镜,但绝大多数情况下,针孔模型已经足够精确。我在项目中遇到过用鱼眼镜头的情况,那才需要更复杂的模型。

我的经验: 对于普通工业相机和手机摄像头,针孔模型完全够用。别一上来就搞复杂模型,先跑通基础再说。

2.2 四个坐标系:世界、相机、图像、像素

一个三维点要变成像素坐标,需要经过四次坐标变换。我习惯把这四个坐标系串成一条流水线:

  1. 世界坐标系 (Xw, Yw, Zw) — 你定义的三维空间,单位是米或毫米
  2. 相机坐标系 (Xc, Yc, Zc) — 以相机光心为原点,Z轴指向镜头前方
  3. 图像坐标系 (x, y) — 在成像平面上,单位是毫米,原点在光轴与平面交点
  4. 像素坐标系 (u, v) — 最终在图像上的行列号,单位是像素

为什么要搞这么多坐标系?说白了,每个坐标系都有自己的「主场优势」。世界坐标系方便你描述物体位置,相机坐标系方便你描述投影关系,像素坐标系方便你读写图像数据。

核心流程: 世界点 → 刚体变换 → 相机点 → 透视投影 → 图像点 → 仿射变换 → 像素点

下面这张图,把整个流程画清楚了:

相机成像模型:坐标系变换流水线 世界坐标系 (Xw, Yw, Zw) 单位:米/毫米 外参 相机坐标系 (Xc, Yc, Zc) 光心为原点 投影 图像坐标系 (x, y) 单位:毫米 内参 像素坐标系 (u, v) 单位:像素 关键说明: • 外参(R, t):世界坐标系 → 相机坐标系,描述相机的位姿(旋转+平移) • 内参(fx, fy, cx, cy):图像坐标系 → 像素坐标系,描述相机的内部光学特性 • 透视投影:相机坐标系 → 图像坐标系,基于针孔模型的相似三角形关系 • 畸变参数:修正实际透镜带来的径向和切向畸变

2.3 世界坐标系与相机坐标系:外参的舞台

世界坐标系到相机坐标系的变换,靠的是外参。外参包括一个旋转矩阵 R 和一个平移向量 t。数学表达式很简单:

Xc = R * Xw + t

这里 R 是 3×3 的旋转矩阵,t 是 3×1 的平移向量。说白了,就是把世界坐标系下的点,先旋转再平移,挪到相机坐标系下。

我记得有一次做双目标定,左右相机的外参死活对不上。后来发现是我把旋转矩阵的欧拉角顺序搞反了。嗯,这里要注意:OpenCV 用的是 R = Rz * Ry * Rx 的顺序,别搞混。

避坑指南: 我曾经因为旋转矩阵的表示方式不同,导致标定结果差了十万八千里。建议统一用 Rodrigues 向量,别手动拼矩阵。

2.4 图像坐标系与像素坐标系:内参的舞台

相机坐标系下的点,先通过透视投影变成图像坐标(单位毫米),再通过内参变成像素坐标(单位像素)。

透视投影公式:

x = f * Xc / Zc
y = f * Yc / Zc

然后从图像坐标到像素坐标:

u = fx * x + cx
v = fy * y + cy

这里 fx 和 fy 是焦距在像素单位下的值,cx 和 cy 是光心在像素坐标系中的位置。我习惯把内参矩阵写成这样:

K = [[fx,  0, cx],
     [ 0, fy, cy],
     [ 0,  0,  1]]

这个 K 矩阵,就是相机的内参矩阵。它包含了相机的所有内部参数。你想想看,只要知道了 K,就能把相机坐标系下的点映射到像素坐标。

2.5 相机内参与外参:一张表说清楚

我把内外参的核心区别整理成了一张表,方便你对照:

参数类型 包含内容 物理意义 维度 是否随相机移动变化
内参 fx, fy, cx, cy, 畸变系数 描述相机内部光学特性 固定值(4+5个参数) 否
外参 旋转矩阵 R, 平移向量 t 描述相机在世界坐标系中的位姿 6个自由度 是
一句话总结: 内参是相机的「基因」,出厂就定了;外参是相机的「位置」,每次移动都会变。

2.6 畸变模型:现实世界不完美

针孔模型是理想情况。实际镜头有畸变,主要是径向畸变和切向畸变。径向畸变让直线变弯,切向畸变让图像倾斜。

OpenCV 里常用的畸变模型有 5 个参数:k1, k2, p1, p2, k3。其中 k1, k2, k3 是径向畸变系数,p1, p2 是切向畸变系数。

矫正公式:

x_corrected = x * (1 + k1*r^2 + k2*r^4 + k3*r^6) + 2*p1*x*y + p2*(r^2 + 2*x^2)
y_corrected = y * (1 + k1*r^2 + k2*r^4 + k3*r^6) + p1*(r^2 + 2*y^2) + 2*p2*x*y

其中 r^2 = x^2 + y^2。看着复杂,但 OpenCV 的 cv2.undistort() 函数一行代码就搞定了。我在项目中遇到过畸变特别严重的镜头,k1 值到了 -0.4,矫正后边缘还是有点模糊。这时候就得考虑用更高级的模型了。

我的建议: 标定时多拍几组不同角度的棋盘格照片,畸变参数会更稳定。我一般拍 20-30 张。

好了,这一节的内容就到这里。相机成像模型是双目视觉的基石,搞懂了这些坐标系和参数,后面的标定和校正才能顺利进行。记住:内参是相机的「身份证」,外参是相机的「GPS」,两者缺一不可。