2. 相机成像模型:从针孔到非线性,从世界到像素

聊畸变校正,绕不开相机成像模型。说白了,你得先知道“理想情况下”图像是怎么来的,才能去修正那些“不理想”的偏差。这一节,我把针孔模型、非线性模型、内参外参,以及世界坐标到像素坐标的完整映射,一次性给你讲透。

2.1 针孔模型:最朴素的成像理想

针孔模型,是所有相机模型的“祖宗”。它假设光线通过一个小孔,在后面的成像平面上形成倒像。虽然简单,但它是理解内参矩阵的基础。

我个人习惯,把针孔模型拆成三步来看:

  1. 光心(投影中心):就是那个小孔的位置,记作 O。
  2. 成像平面:光线穿过光心后,落在距离 f(焦距)的平面上。
  3. 相似三角形:物体高度 Y 与像高 y 的关系是 y = f * (Y / Z),其中 Z 是物体到光心的距离。

核心公式(理想情况):

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

其中 (X, Y, Z) 是物体在相机坐标系下的三维坐标,(x, y) 是成像平面上的物理坐标(单位:毫米)。

嗯,这里要注意:针孔模型是线性的,它假设镜头没有任何畸变。但现实中的镜头,尤其是广角镜头,会引入明显的非线性畸变。所以,针孔模型只是我们的“起点”,不是终点。

2.2 非线性模型:现实中的镜头畸变

为什么需要非线性模型?因为真实镜头不是完美的针孔。我在项目中遇到过,用针孔模型去标定一个鱼眼镜头,结果误差大得离谱,后来才发现是径向畸变和切向畸变在作祟。

非线性模型,就是在针孔模型的基础上,加上畸变修正项。常见的畸变有两类:

畸变类型 产生原因 数学表达(简化) 典型表现
径向畸变 镜头曲率不完美,光线在边缘弯曲更严重 x_corrected = x * (1 + k1*r² + k2*r⁴ + k3*r⁶) 桶形畸变(广角)、枕形畸变(长焦)
切向畸变 镜头与成像平面不平行(装配误差) x_corrected = x + [2*p1*x*y + p2*(r²+2*x²)] 图像倾斜、梯形失真

避坑指南:我曾经在标定一个工业相机时,只考虑了径向畸变(k1, k2),结果在图像边缘的测量误差始终降不下来。后来加上切向畸变(p1, p2),误差才收敛。所以,如果你的应用对边缘精度要求高,千万别省切向畸变参数。

2.3 内参矩阵:从物理坐标到像素坐标

内参矩阵,描述的是相机内部的几何属性。它把成像平面上的物理坐标(毫米)转换成图像上的像素坐标(像素)。

内参矩阵 K 长这样:

K = [ fx   0   cx
      0   fy   cy
      0    0    1 ]
  • fx, fy:焦距在 x 和 y 方向上的像素当量(单位:像素/毫米)。
  • cx, cy:主点(光轴与成像平面的交点)的像素坐标。

你想想看,为什么 fx 和 fy 可能不一样?因为像素不一定是正方形的。我遇到过一些工业相机,像素是矩形,这时候 fx 和 fy 就会有明显差异。

个人经验:在标定内参时,我建议至少采集 15-20 张不同姿态的棋盘格图像。太少的话,主点 cx, cy 的估计会很不稳定,直接影响后续的畸变校正精度。

2.4 外参矩阵:从世界坐标系到相机坐标系

外参矩阵,描述的是相机在世界坐标系中的位置和朝向。它由旋转矩阵 R 和平移向量 t 组成。

[X_c]   [ R   t ] [X_w]
[Y_c] = [       ] [Y_w]
[Z_c]   [ 0   1 ] [Z_w]
[ 1 ]             [ 1 ]
  • R:3x3 旋转矩阵,表示相机坐标系相对于世界坐标系的旋转。
  • t:3x1 平移向量,表示相机光心在世界坐标系中的位置。

说白了,外参就是告诉你“相机放在哪、朝哪看”。在视觉测量中,外参的精度直接决定了三维重建的精度。我记得有一次做双目立体视觉,外参标定差了 0.1 度,结果在 2 米距离处的测量误差就达到了 5 毫米——这在实际项目中是不可接受的。

2.5 完整映射:世界坐标 → 像素坐标

把上面所有环节串起来,就是完整的成像过程:

  1. 世界坐标 → 相机坐标:通过外参矩阵 [R|t]。
  2. 相机坐标 → 归一化平面:除以 Z_c,得到 (x_n, y_n)。
  3. 畸变修正:对 (x_n, y_n) 应用径向和切向畸变模型。
  4. 归一化平面 → 像素坐标:通过内参矩阵 K。

完整公式(含畸变):

// 1. 外参变换
[X_c, Y_c, Z_c]^T = R * [X_w, Y_w, Z_w]^T + t

// 2. 归一化
x_n = X_c / Z_c
y_n = Y_c / Z_c

// 3. 畸变修正
r² = x_n² + y_n²
x_d = x_n * (1 + k1*r² + k2*r⁴ + k3*r⁶) + 2*p1*x_n*y_n + p2*(r² + 2*x_n²)
y_d = y_n * (1 + k1*r² + k2*r⁴ + k3*r⁶) + p1*(r² + 2*y_n²) + 2*p2*x_n*y_n

// 4. 像素坐标
u = fx * x_d + cx
v = fy * y_d + cy

这个流程,就是相机成像的“完整链路”。你做的畸变校正,本质上就是在第三步“畸变修正”上做文章——通过标定得到畸变参数,然后反向修正每个像素的位置。

2.6 知识结构图:成像模型全景

下面这张图,把整个成像模型的知识结构串起来了。你可以把它当作本章的“思维导图”。

相机成像模型知识结构图 相机成像模型:从世界坐标到像素坐标 世界坐标系 外参矩阵 [R|t] 相机坐标系 归一化平面 除以 Z_c 畸变修正 径向+切向 内参矩阵 K 像素坐标 (u,v) 💡 关键理解: • 外参决定“相机在哪看”,内参决定“图像怎么存”。 • 畸变修正是连接“理想针孔”和“真实镜头”的桥梁。

2.7 本章小结:你需要记住的

  • 针孔模型是理想基础,但真实镜头必须用非线性模型。
  • 内参矩阵(fx, fy, cx, cy)是相机的“身份证”,每个相机都不一样。
  • 外参矩阵(R, t)是相机在空间中的“位置和姿态”。
  • 从世界坐标到像素坐标,经历了四次变换:外参 → 归一化 → 畸变修正 → 内参。
  • 畸变校正的精度,取决于你对这四步中每一步的建模是否准确。

最后一句心里话:我见过太多工程师,拿着 OpenCV 的 calibrateCamera 跑一遍就完事了,结果测量精度上不去。其实,理解模型本身,比会调 API 重要得多。你只有知道每一步在干什么,才能在出问题时快速定位——是内参标偏了?还是外参没锁死?还是畸变模型没选对?