2、相机成像模型:针孔相机模型、世界坐标系、相机坐标系、图像坐标系、像素坐标系
做双目标定,第一个绕不开的概念就是相机成像模型。说白了,相机是怎么把三维世界里的一个点,变成二维照片上的一个像素的?
我个人习惯把这个问题拆成两步来理解:第一步是几何投影,也就是光线怎么走;第二步是坐标变换,也就是点在不同坐标系之间怎么换算。今天我们就把这套东西彻底讲透。
2.1 针孔相机模型——最朴素的成像原理
你想想看,最早的相机其实就是个暗箱,前面戳个小孔,光线透过小孔在后面的感光面上成像。这就是针孔相机模型的原型。
这个模型做了三个理想化假设:
- 光线沿直线传播(不考虑衍射)
- 小孔足够小(保证成像清晰)
- 像平面是平的(忽略镜头畸变)
实际镜头当然比这复杂得多,但针孔模型是理解所有相机几何的基础。我在项目中调试畸变校正时,经常先拿针孔模型算一遍理论值,再跟实际图像对比,偏差一目了然。
x = f * X / Z
y = f * Y / Z
其中 f 是焦距(小孔到像平面的距离)。
2.2 四个坐标系——从世界到像素的完整链条
一个三维点要变成像素坐标,中间要经过四次坐标变换。我刚开始学的时候总觉得绕,后来画了个流程图就清楚了。
2.3 世界坐标系 → 相机坐标系(外参)
世界坐标系是我们定义三维空间的基准。你可以把标定板放在桌上,棋盘格角点所在的坐标系就是世界坐标系。
相机坐标系呢?它以相机光心为原点,Z轴指向镜头前方。从世界坐标到相机坐标,说白了就是一个刚体变换:旋转 + 平移。
数学表达很简单:
[Xc] [R11 R12 R13] [Xw] [Tx]
[Yc] = [R21 R22 R23] [Yw] + [Ty]
[Zc] [R31 R32 R33] [Zw] [Tz]
这里的 R 和 t 就是相机外参。双目标定要算两个相机的各自外参,还要算它们之间的相对位姿。
2.4 相机坐标系 → 图像坐标系(内参投影)
这一步就是针孔模型的核心了。三维点 (Xc, Yc, Zc) 投影到像平面上,变成 (x, y)。
公式就是前面说的:
x = f * Xc / Zc
y = f * Yc / Zc
注意这里有个除法,所以成像模型本质上是非线性的。这也是为什么后来要引入齐次坐标来线性化处理。
2.5 图像坐标系 → 像素坐标系(离散化)
图像坐标系 (x, y) 的单位是毫米,是连续的物理坐标。但相机最终输出的是像素,所以需要离散化。
这个变换很简单:
u = x / dx + u0
v = y / dy + v0
其中:
- dx, dy:每个像素在x、y方向上的物理尺寸(mm/pixel)
- u0, v0:主点(光轴与像平面交点)的像素坐标
把这些参数合起来,就得到了相机内参矩阵 K:
[fx 0 u0]
K = [ 0 fy v0]
[ 0 0 1]
其中 fx = f/dx,fy = f/dy,是焦距的像素表示。
2.6 完整变换——从世界到像素
把上面三步串起来,一个世界点 Pw 到像素点 p 的完整变换就是:
p = K * [R | t] * Pw
用齐次坐标写得更清楚:
[u] [fx 0 u0] [R11 R12 R13 Tx] [Xw]
[v] = [0 fy v0] [R21 R22 R23 Ty] [Yw]
[1] [0 0 1] [R31 R32 R33 Tz] [Zw]
[0 0 0 1 ] [1 ]
2.7 畸变模型——现实世界的修正
针孔模型是理想情况。实际镜头都有畸变,主要是两种:
| 畸变类型 | 产生原因 | 数学模型 | 典型表现 |
|---|---|---|---|
| 径向畸变 | 透镜形状不完美 | k1, k2, k3 三个参数 | 图像边缘弯曲(桶形/枕形) |
| 切向畸变 | 镜头与像平面不平行 | p1, p2 两个参数 | 图像倾斜变形 |
畸变校正的公式我就不列了,OpenCV 的 cv2.calibrateCamera() 会自动帮你算。但我要提醒一句:畸变参数和相机内参是耦合的,标定时要一起优化。
2.8 本章小结
相机成像模型,说白了就是回答一个问题:三维世界的一个点,最终落在像素图像的哪个位置?
答案分三步:
- 世界坐标 → 相机坐标(外参:旋转+平移)
- 相机坐标 → 图像坐标(内参:针孔投影)
- 图像坐标 → 像素坐标(内参:离散化+主点偏移)
再加上畸变模型做修正,就是完整的相机几何模型。双目标定要解的,就是这些参数。
嗯,这套模型我用了快十年,每次遇到标定精度问题,回头检查的永远是这几个坐标系之间的变换关系。基础打牢了,后面立体匹配、深度计算才不会跑偏。