1. 相机成像原理:小孔成像模型、透镜畸变、相机坐标系与像素坐标系

相机标定这件事,说白了就是搞清楚「三维世界里的点,是怎么跑到二维照片上的」。我刚开始做视觉项目时,总觉得标定就是拍几张棋盘格、跑个函数完事。直到有一次在产线上,标定出来的内参死活不对,投影误差大得离谱……后来才发现,是我没搞懂最基础的成像模型。

这一节,咱们就把相机成像的底子打牢。你理解了小孔成像、畸变、坐标系变换,后面的角点提取和标定才能做得稳。

1.1 小孔成像模型

相机最原始的模型,就是小孔成像。你想想看,一个暗箱,前面戳个小孔,外面的光线穿过小孔,在后面的感光面上形成一个倒立的像。这就是最朴素的成像原理。

核心公式(小孔成像):

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

其中 f 是焦距(小孔到成像面的距离),负号表示像是倒立的。

实际相机为了处理方便,会把倒像「正过来」,所以公式里通常省略负号。现代相机用透镜代替小孔,但核心思想没变——世界坐标到图像坐标,是一个透视投影关系。

我的习惯:在推导标定公式时,我总把成像模型画成「针孔-成像面-物体」三条线,这样坐标系关系一目了然。别嫌简单,这步画错了,后面全白搭。

1.2 透镜畸变

理想的小孔模型没有畸变,但真实相机用的是透镜。透镜有厚度、有曲率,光线穿过时会发生折射偏移。这就导致了畸变。

畸变主要分两类:

畸变类型 现象 产生原因
径向畸变 直线变弯,越靠近边缘越明显 透镜曲率不完美,光线偏折角度随距离变化
切向畸变 图像倾斜、梯形失真 透镜与成像面不平行(装配误差)

径向畸变又分两种:

  • 桶形畸变:图像向外鼓,像鱼眼镜头那样。我最早用广角摄像头做室内定位时,就被桶形畸变坑过——墙角明明是直的,拍出来却是弯的。
  • 枕形畸变:图像向内缩,长焦镜头容易出现。

畸变的数学模型长这样:

// 径向畸变(k1, k2, k3 是畸变系数)
x_distorted = x * (1 + k1*r^2 + k2*r^4 + k3*r^6)
y_distorted = y * (1 + k1*r^2 + k2*r^4 + k3*r^6)

// 切向畸变(p1, p2 是畸变系数)
x_distorted = x + [2*p1*x*y + p2*(r^2 + 2*x^2)]
y_distorted = y + [p1*(r^2 + 2*y^2) + 2*p2*x*y]

我曾经踩过的坑:标定畸变系数时,棋盘格图像必须覆盖整个视场。如果你只拍了中间区域,边缘畸变没被约束,标出来的 k1、k2 会严重偏离真实值。后来我每次标定都至少拍 20 张图,四角和边缘必须到位。

1.3 相机坐标系与像素坐标系

搞懂坐标系,是标定的基本功。我见过不少新手,把世界坐标、相机坐标、图像坐标、像素坐标混在一起算,结果怎么算都不对。咱们一个一个捋清楚。

一共涉及四个坐标系:

  1. 世界坐标系 (Xw, Yw, Zw):你自定义的全局参考系。棋盘格标定板上的角点坐标,就是在这个系里定义的。
  2. 相机坐标系 (Xc, Yc, Zc):以相机光心为原点,Zc 轴沿光轴方向。世界坐标到相机坐标,靠的是旋转矩阵 R 和平移向量 t。
  3. 图像坐标系 (x, y):在成像面上,以光轴与成像面交点为原点,单位是毫米。相机坐标到图像坐标,靠的是小孔成像的透视投影。
  4. 像素坐标系 (u, v):在图像上,以左上角为原点,单位是像素。图像坐标到像素坐标,靠的是缩放和平移(内参矩阵 K 的一部分)。

整个变换链条是这样的:

世界坐标 (Xw,Yw,Zw) 
  → [R|t] 外参 
  → 相机坐标 (Xc,Yc,Zc) 
  → 透视投影 
  → 图像坐标 (x,y) 
  → 内参矩阵 K 
  → 像素坐标 (u,v)

内参矩阵 K 长这样:

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

fx, fy 是焦距的像素表示(f / 像元尺寸),cx, cy 是光心在像素坐标系中的位置。标定的核心任务之一,就是算出这 4 个参数 + 畸变系数。

1.4 知识结构总览

下面这张图,把这一节的核心逻辑串起来了。我建议你把它存下来,后面学标定流程时随时回来对照。

相机成像与标定知识结构 世界坐标系 (Xw, Yw, Zw) 外参 [R|t] 相机坐标系 (Xc, Yc, Zc) 透视投影 图像坐标系 (x, y) 毫米 内参 K 像素 (u,v) 透镜畸变 径向 + 切向 修正 标定输出 内参 K (fx, fy, cx, cy) + 畸变系数 (k1,k2,p1,p2,k3) 💡 标定本质 标定就是求解「外参 [R|t] + 内参 K + 畸变系数」的过程。 输入:已知世界坐标的棋盘格角点 + 图像中检测到的角点像素坐标。 输出:让重投影误差最小的那组参数。

1.5 坐标系变换的数学表达

把上面的链条写成矩阵形式,就是标定里最核心的公式:

s * [u, v, 1]^T = K * [R|t] * [Xw, Yw, Zw, 1]^T

其中:

  • s 是尺度因子(因为透视投影丢失了深度信息)
  • K 是内参矩阵(3×3)
  • [R|t] 是外参矩阵(3×4)
  • [Xw, Yw, Zw, 1]^T 是世界坐标的齐次形式

我的建议:刚开始学标定的人,我建议你亲手把上面这个矩阵乘法展开一次。把 K 和 [R|t] 的每个元素写出来,算一遍 u 和 v 是怎么由 Xw、Yw、Zw 表达出来的。这一步做通了,后面张正友标定法的推导你就不会晕。

1.6 为什么需要标定?

说白了,相机出厂时内参和畸变系数是未知的。就算厂家给了标称值,也跟实际有偏差——温度、装配、镜头批次都会影响。我遇到过最夸张的一次,同一型号的两台相机,fx 差了 15 个像素。不标定直接做三维重建,误差能偏到天上去。

标定的目的,就是通过拍摄已知几何结构的标定物(比如棋盘格),用数学方法反算出 K 和畸变系数。有了这些参数,你才能:

  • 把像素坐标还原成相机坐标(去畸变 + 逆透视)
  • 做三维重建、视觉定位、测距
  • 保证多相机系统的空间一致性

注意:标定不是一劳永逸的。如果相机被摔过、镜头重新拧过、或者温度变化剧烈,内参可能会变。我每做一个新项目,都会重新标一次,哪怕用的是同一台相机。