4、数学基础(三):相机几何——针孔相机模型、内参矩阵、外参矩阵、畸变模型

好,咱们继续往下走。前面聊了坐标系和刚体变换,那些是三维世界的“骨架”。今天要聊的,是连接三维世界和二维图像的“桥梁”——相机几何。

说白了,相机几何就是回答一个问题:三维空间里的一个点,是怎么跑到照片上那个像素位置的? 这个问题看似简单,但背后藏着针孔模型、内外参矩阵、畸变模型这一整套逻辑。我当年刚入行时,觉得这东西太理论,结果第一次做标定就吃了大亏——拍出来的棋盘格图像,角点提取总是歪的。嗯,从那以后,我再也不敢小看相机几何了。

核心一句话:相机几何就是描述“世界坐标 → 相机坐标 → 图像坐标 → 像素坐标”的完整映射链条。

相机几何核心知识体系 世界坐标系 相机坐标系 图像坐标系 像素坐标系 外参矩阵 内参矩阵 畸变校正 关键公式: P像素 = K · [R|t] · P世界 其中: · K:内参矩阵(焦距、主点、畸变) · [R|t]:外参矩阵(旋转+平移) · 畸变模型:径向畸变 + 切向畸变

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

先说说针孔相机模型。你想想看,一个暗箱,前面戳个小孔,光线穿过小孔在后面的胶片上成像。这就是最原始的相机。

数学上怎么描述?很简单,相似三角形。假设相机坐标系的原点在光心,Z轴指向物体方向。那么空间点 (X, Y, Z) 在成像平面上的投影 (x, y) 满足:

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

这里的 f 是焦距(光心到成像平面的距离)。注意,这个模型假设成像平面在光心前方(虚拟成像平面),这样图像就是正立的,方便计算。

我的经验:实际相机不是针孔,而是透镜组。但针孔模型是基础,所有标定算法都基于它。我在做双目立体匹配时,第一步就是把图像校正到针孔模型下,否则视差计算全是错的。

4.2 内参矩阵——从物理世界到像素

针孔模型给出的是物理坐标(毫米),但照片是像素。怎么转换?这就需要内参矩阵 K。

内参矩阵 K 是一个 3x3 的上三角矩阵:

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

其中:

  • fx, fy:分别是 x 和 y 方向的焦距(像素单位)。通常 fx = f / dx,fy = f / dy,dx、dy 是每个像素的物理尺寸。
  • cx, cy:主点坐标(像素单位),即光轴与成像平面的交点。理想情况下在图像中心,但实际有偏移。

所以,从相机坐标系到像素坐标系的完整映射是:

[ u ]   [ fx   0   cx ] [ X/Z ]
[ v ] = [ 0   fy   cy ] [ Y/Z ]
[ 1 ]   [ 0    0    1 ] [  1  ]

说白了,内参矩阵就是描述“相机内部”的几何属性。每个相机都有自己的内参,而且会随着焦距、光圈变化而变化。

避坑指南:我曾经在标定一个广角相机时,发现 fx 和 fy 差异很大。一开始以为是标定板不平,后来才发现是传感器像素不是正方形。所以,不要假设 fx = fy,除非你用的是高端工业相机。

4.3 外参矩阵——相机放在哪里?

内参管的是“相机内部”,外参管的是“相机在哪儿、朝哪儿看”。

外参矩阵 [R|t] 是一个 3x4 的矩阵,由旋转矩阵 R(3x3)和平移向量 t(3x1)组成。它把世界坐标系下的点变换到相机坐标系下:

P_cam = R * P_world + t

或者写成齐次形式:

[ X_cam ]   [ R   t ] [ X_world ]
[ Y_cam ] = [       ] [ Y_world ]
[ Z_cam ]   [ 0   1 ] [ Z_world ]
[  1    ]             [   1     ]

外参矩阵有 6 个自由度:3 个旋转角度(绕 X、Y、Z 轴)和 3 个平移量。旋转矩阵 R 是正交矩阵,满足 R^T R = I,det(R) = 1。

我的习惯:在实际项目中,我通常用四元数表示旋转,而不是欧拉角。为什么?因为欧拉角有万向锁问题,而四元数插值更平滑。做 SLAM 或运动恢复结构(SfM)时,这个细节能省很多调试时间。

4.4 畸变模型——镜头不是完美的

现实中的镜头不是完美的针孔。透镜的曲率、装配误差都会导致图像变形。这就是畸变。

畸变主要分两类:

  1. 径向畸变:光线通过透镜边缘时弯曲更厉害,导致图像边缘向内凹(桶形畸变)或向外凸(枕形畸变)。数学模型用泰勒展开:
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)

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

  1. 切向畸变:透镜和成像平面不平行,导致图像倾斜。数学模型:
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]

其中 p1、p2 是切向畸变系数。

完整的畸变模型通常用 5 个参数表示:(k1, k2, p1, p2, k3)。

注意:畸变校正必须在投影到像素坐标之前完成。也就是说,先校正畸变,再用内参矩阵投影。顺序搞反了,图像会变得很奇怪。我曾经在调试一个 AR 项目时,把畸变校正放在投影之后,结果虚拟物体怎么都对不齐真实场景——折腾了两天才发现是顺序问题。

4.5 完整映射流程

把上面所有内容串起来,从世界坐标到像素坐标的完整流程是:

步骤 描述 公式
1 世界坐标 → 相机坐标 P_cam = R * P_world + t
2 相机坐标 → 归一化平面 x = X_cam / Z_cam, y = Y_cam / Z_cam
3 畸变校正 x' = f_distort(x, y), y' = f_distort(x, y)
4 归一化平面 → 像素坐标 u = fx * x' + cx, v = fy * y' + cy

核心公式(齐次形式):

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

其中 s 是尺度因子(等于 Z_cam)。这个公式是三维重建的基石,所有标定、三角化、PnP 算法都基于它。

4.6 实际项目中的注意事项

  • 标定板要足够大:覆盖整个视场,否则边缘畸变参数不准。我习惯用 10x7 的棋盘格,每个格子 30mm。
  • 多角度拍摄:至少 15-20 张不同角度的图像,包括倾斜、旋转、靠近、远离。
  • 检查重投影误差:标定完成后,计算重投影误差(通常小于 0.5 像素算合格)。如果误差大,检查标定板角点是否提取准确。
  • 固定焦距:标定过程中不要变焦,否则内参会变。变焦镜头需要重新标定。

我的经验:如果你用的是手机摄像头,注意它可能有自动对焦和光学防抖。这些功能会改变内参。我建议用固定焦距的工业相机做三维重建,或者用 OpenCV 的 calibrateCamera() 时传入 CALIB_FIX_PRINCIPAL_POINT 等标志来约束参数。

好了,相机几何的核心内容就这些。内参、外参、畸变,这三者构成了从三维到二维的完整映射。理解了这个映射,你就能看懂标定、三角化、PnP 这些后续算法的原理了。


专注资料整理