4、相机成像模型:针孔相机模型、内参矩阵、畸变模型

做手眼标定,绕不开相机成像模型。说白了,你得知道相机是怎么把三维世界“拍”成一张二维图片的。我刚开始接触这个领域时,总觉得标定就是算个矩阵,后来发现,不理解成像模型,标定结果很容易飘。

这一章,我们就把相机成像这件事拆开揉碎了讲。核心就三个东西:针孔模型、内参矩阵、畸变模型。

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

针孔模型,是所有相机模型的基础。它假设光线是直线传播的,穿过一个小孔,在后面的成像平面上形成倒像。嗯,听起来很简单,但数学上非常优雅。

我们通常把成像平面“虚拟”到相机前方,这样图像就是正的了,方便计算。这个虚拟平面到光心的距离,就是焦距 f。

空间中的一点 P(X, Y, Z),投影到成像平面上的点 p(x, y),关系如下:

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

这里有个关键点:Z 是深度。你想想看,物体离相机越远,它在图像上就越小,这就是透视效应。我在做机器人抓取时,经常需要根据这个关系反推物体的三维位置,如果深度不准,抓取点就偏了。

核心理解:针孔模型建立了“世界点 → 图像点”的线性映射关系。但实际相机有镜头,不是针孔,所以后面需要畸变模型来修正。

4.2 内参矩阵——把物理坐标变成像素坐标

上面那个公式得到的是物理单位(毫米)的坐标。但图像是由像素组成的,我们需要把物理坐标映射到像素坐标。这个映射,就是内参矩阵 K。

内参矩阵长这样:

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

其中:

  • fx, fy:分别是 x 和 y 方向上的焦距(像素单位)。通常 fx ≈ fy,但也不。
  • cx, cy:主点坐标,也就是光轴与成像平面的交点。理想情况下在图像中心,但实际会有偏移。

完整的投影公式就变成了:

u = fx * (X / Z) + cx
v = fy * (Y / Z) + cy

写成齐次坐标形式更简洁:

s * [u, v, 1]^T = K * [X, Y, Z, 1]^T

这里的 s 是尺度因子,其实就是 Z。

我的习惯:标定完相机后,第一件事就是看 cx, cy 是否接近图像中心的一半。如果偏差超过 10 个像素,我会检查标定板是否拍全了。有一次偏差很大,结果是标定板边缘被切掉了,重拍后就好了。

4.3 畸变模型——镜头带来的“变形”

实际镜头不是完美的针孔,光线经过透镜会发生折射,导致图像变形。这就是畸变。畸变主要分两类:径向畸变和切向畸变。

4.3.1 径向畸变

径向畸变是光线在透镜边缘弯曲得更厉害造成的。离光心越远,变形越明显。常见的有两种:

  • 桶形畸变:图像向外膨胀,像桶一样。常见于广角镜头。
  • 枕形畸变:图像向内收缩,像枕头一样。常见于长焦镜头。

数学模型用泰勒级数展开来修正:

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

其中 r 是像素点到光心的距离,k1, k2, k3 是径向畸变系数。通常 k1 和 k2 就够了,k3 用于鱼眼镜头等大畸变情况。

我曾经踩过的坑:用 OpenCV 标定时,默认只标定 k1, k2, p1, p2。如果镜头畸变很大(比如广角),一定要把 k3 加上,否则图像边缘的标定误差会很大,直接影响手眼标定的精度。

4.3.2 切向畸变

切向畸变是由于镜头和成像平面不平行造成的。说白了,就是镜头装歪了。这种畸变在工业相机中比较常见,尤其是安装不当时。

修正公式:

x_corrected = x + [2 * p1 * x * y + p2 * (r^2 + 2 * x^2)]
y_corrected = y + [p1 * (r^2 + 2 * y^2) + 2 * p2 * x * y]

p1, p2 就是切向畸变系数。

4.4 畸变校正流程

实际应用中,我们先用标定板得到畸变系数,然后对每一帧图像做校正。流程如下:

  1. 获取原始图像:从相机读取带畸变的图像。
  2. 计算畸变映射:根据内参和畸变系数,计算每个像素从畸变位置到校正位置的映射。
  3. 重映射:用映射关系重新采样图像,得到无畸变图像。

OpenCV 中,用 cv::initUndistortRectifyMap() 和 cv::remap() 两步搞定。

重要提醒:手眼标定时,一定要用校正后的图像提取角点。否则畸变会引入系统性误差,标定结果会偏。我见过有人直接用原始图像标定,结果误差大了 3 倍。

4.5 知识结构总览

下面这张图,把相机成像模型的整体脉络画出来了。你可以对照着看,心里有个谱。

相机成像模型知识结构 相机成像模型 针孔相机模型 内参矩阵 K 畸变模型 透视投影 焦距 f fx, fy cx, cy 径向畸变 切向畸变 桶形畸变 枕形畸变 镜头与像面不平行 核心:针孔模型 + 内参矩阵 + 畸变模型 = 完整的相机成像模型

4.6 畸变系数与内参的标定关系

标定相机时,内参和畸变系数是一起求解的。你不能先算内参再算畸变,它们是耦合的。常用的标定方法是张正友标定法,用棋盘格多角度拍摄,然后优化求解。

标定结果通常包含以下参数:

参数 符号 说明 典型值范围
焦距 x fx x 方向焦距(像素) 500 ~ 3000
焦距 y fy y 方向焦距(像素) 500 ~ 3000
主点 x cx 光心在 x 方向偏移 图像宽度的一半 ± 20
主点 y cy 光心在 y 方向偏移 图像高度的一半 ± 20
径向畸变 1 k1 二阶径向畸变系数 -0.5 ~ 0.5
径向畸变 2 k2 四阶径向畸变系数 -0.5 ~ 0.5
径向畸变 3 k3 六阶径向畸变系数(可选) -0.5 ~ 0.5
切向畸变 1 p1 切向畸变系数 -0.1 ~ 0.1
切向畸变 2 p2 切向畸变系数 -0.1 ~ 0.1

我的经验:标定完成后,一定要做重投影误差检查。如果平均误差超过 0.5 像素,说明标定质量有问题。我一般要求 0.2 像素以下才放心用于手眼标定。

4.7 小结

相机成像模型,说白了就是回答一个问题:三维空间中的点,到底落在图像哪个像素上?针孔模型给了我们一个线性框架,内参矩阵完成了物理到像素的转换,畸变模型修正了镜头的非线性误差。这三者合在一起,才是完整的相机模型。

理解了这个,后面做手眼标定时,你才能知道误差从哪里来,怎么去消除它。