2. 相机成像模型:针孔相机模型、世界坐标系到像素坐标系的转换、内参与外参矩阵

做立体匹配,第一件事是什么?

不是调算法,不是调参数。是先把相机怎么成像这件事搞明白。

我见过太多同学,上来就怼SGM、怼代价聚合,结果标定矩阵写错了,视差图怎么调都不对。最后发现,是坐标系转换出了问题。嗯,这种坑我踩过不止一次。

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

说白了,相机成像就是一个「三维世界 → 二维平面」的投影过程。

针孔模型是最简单的模型。想象一个密闭盒子,前面戳一个小孔,光线穿过小孔,在后面的感光平面上倒立成像。这就是针孔相机。

核心思想: 三维空间中的点P(X, Y, Z),通过光心O,投影到成像平面上的点p(x, y)。

数学关系很简单:x = f * X / Zy = f * Y / Z

其中f是焦距,Z是物距。

这里有个细节要注意:实际相机不是针孔,是透镜。透镜会引入畸变。但针孔模型是基础,畸变校正是在这个模型上做的修正。

我个人习惯,在讲立体匹配之前,先让学生手推一遍针孔模型的投影公式。为什么?因为后面所有的坐标系转换、视差计算、三角测量,都建立在这个公式上。

针孔相机成像模型 世界坐标系 物体 P(X,Y,Z) 光心 O 成像平面 像点 p(x,y) 焦距 f 物距 Z 倒立、缩小的实像 x = f · X / Z, y = f · Y / Z

2.2 四个坐标系:从世界到像素

实际工程中,我们不会直接用物理坐标。我们需要在四个坐标系之间来回切换。

哪四个?

  1. 世界坐标系:你放相机的地方。单位是米或毫米。
  2. 相机坐标系:以光心为原点,Z轴指向镜头前方。
  3. 图像坐标系:在成像平面上,单位是毫米。原点在光轴与平面的交点。
  4. 像素坐标系:最终你看到的图像。单位是像素。原点在左上角。

我的经验: 很多初学者搞混「图像坐标系」和「像素坐标系」。图像坐标系的原点在图像中心,像素坐标系的原点在左上角。两者差一个平移量。我在做双目标定时,就因为这个平移量没算对,导致视差图偏移了十几个像素。排查了一整天。

2.3 世界坐标系 → 相机坐标系:外参矩阵

世界坐标系和相机坐标系之间是什么关系?

说白了,就是刚体变换——旋转加平移。

一个点在世界坐标系下的坐标是Pw = (Xw, Yw, Zw)T,在相机坐标系下是Pc = (Xc, Yc, Zc)T

转换公式:

Pc = R · Pw + t

其中R是3×3旋转矩阵,t是3×1平移向量。

写成齐次形式:

[Xc]   [R   t] [Xw]
[Yc] = [     ] [Yw]
[Zc]   [0   1] [Zw]
[1  ]           [1  ]

这个4×4矩阵,就是外参矩阵

外参矩阵的意义: 描述相机在世界坐标系中的位置和朝向。

每个相机都有自己的外参。在双目系统中,左右相机的外参不同,它们之间的相对关系就是「双目外参」。

我记得有一次做双目测距,左相机外参标定好了,右相机外参怎么都对不上。后来发现是旋转矩阵的欧拉角顺序搞反了。嗯,这里要注意:旋转矩阵不满足交换律,顺序错了结果完全不一样。

2.4 相机坐标系 → 图像坐标系:内参矩阵

这一步就是针孔模型的投影。

相机坐标系下的点Pc = (Xc, Yc, Zc)T,投影到图像坐标系:

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

写成矩阵形式:

[x]   [f  0  0] [Xc]
[y] = [0  f  0] [Yc]
[1]   [0  0  1] [Zc]

但这是理想情况。实际相机还有两个问题:

  • 像素不是正方形,x和y方向的焦距可能不同(fx和fy
  • 主点(光轴与成像平面的交点)不一定在像素中心,有偏移(cx, cy)

所以实际的内参矩阵是:

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

避坑指南: 我曾经在标定的时候,把fx和fy当成同一个值处理。结果校正后的图像出现了拉伸变形。后来才发现,工业相机的像素尺寸不一定是正方形,fx和fy必须分别标定。

2.5 图像坐标系 → 像素坐标系:离散化

这一步最简单,就是把连续坐标变成离散像素坐标。

假设每个像素的物理尺寸是dx × dy(毫米/像素),那么:

u = x / dx + u0
v = y / dy + v0

其中(u0, v0)是图像坐标系原点在像素坐标系中的位置。

把这一步和上一步合并,就得到完整的内参矩阵

K = [f/dx   0     u0]
    [0    f/dy  v0]
    [0      0      1 ]

通常记作:

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

2.6 完整转换:世界 → 像素

把上面所有步骤串起来:

世界坐标 → 相机坐标 → 图像坐标 → 像素坐标

s · [u]   [fx   0   cx] [R   t] [Xw]
    [v] = [0   fy  cy] [     ] [Yw]
    [1]   [0    0    1 ] [0   1] [Zw]
                               [1  ]

其中s是尺度因子(其实就是Zc)。

这个公式,就是整个相机成像的核心公式

一句话总结: 内参K描述相机本身的属性(焦距、主点),外参[R|t]描述相机在世界中的位姿。

标定的目的,就是求K和[R|t]。

2.7 畸变模型:现实世界的修正

针孔模型是理想情况。实际镜头有畸变,主要是两种:

  • 径向畸变:光线在透镜边缘弯曲更厉害,产生「桶形」或「枕形」畸变
  • 切向畸变:透镜与成像平面不平行

畸变校正公式(以径向畸变为例):

xcorrected = x(1 + k1r² + k2r⁴ + k3r⁶)
ycorrected = y(1 + k1r² + k2r⁴ + k3r⁶)

其中r² = x² + y²,k1、k2、k3是径向畸变系数。

我的建议: 做立体匹配之前,一定要先做畸变校正和立体校正。否则匹配出来的视差图会有系统性误差。我一般用OpenCV的stereoRectify函数,一步到位。

2.8 本章核心知识图谱

相机成像模型:坐标系转换流程 世界坐标系 相机坐标系 图像坐标系 像素 外参 [R|t] 内参 K(投影) 离散化 完整转换公式 s · [u, v, 1]ᵀ = K · [R | t] · [Xw, Yw, Zw, 1]ᵀ 其中 K 为内参矩阵,[R|t] 为外参矩阵 内参矩阵 K K = [fx 0 cx] [0 fy cy] [0 0 1 ] fx, fy: 焦距(像素) 外参矩阵 [R|t] [R t] 3×4 矩阵 R: 旋转矩阵(3×3) t: 平移向量(3×1) 描述相机在世界中的位姿

你想想看,整个成像过程,其实就是把三维世界里的一个点,通过四次坐标变换,最终映射到二维图像上的一个像素。每一步都有明确的数学表达。

搞懂了这些,后面讲立体校正、视差计算、三角测量,你就知道每一步在做什么了。

嗯,这一章的内容就到这。记住:内参是相机的「身份证」,外参是相机的「GPS坐标」。两者缺一不可。