3. 相机成像模型:从光线到像素的数学映射
相机是怎么把三维世界变成二维图像的?这个问题,我当年刚入行时也琢磨了很久。说白了,就是一套从世界坐标到像素坐标的数学变换。今天咱们就把它拆开揉碎了讲清楚。
3.1 针孔相机模型:最朴素的成像原理
针孔相机模型是所有成像模型的基础。它假设光线沿直线传播,穿过一个小孔后在成像平面上形成倒立的像。虽然真实相机复杂得多,但这个模型能解决90%的几何标定问题。
核心公式:
λ * [u, v, 1]^T = K * [R | t] * [X, Y, Z, 1]^T
其中:λ 是尺度因子,[u,v] 是像素坐标,K 是内参矩阵,[R|t] 是外参矩阵,[X,Y,Z] 是世界坐标。
这个公式看着唬人,其实就三步:
- 世界坐标 → 相机坐标:通过旋转矩阵 R 和平移向量 t
- 相机坐标 → 归一化平面:除以 Z 值,得到归一化坐标 (x, y)
- 归一化平面 → 像素坐标:通过内参矩阵 K 映射到像素
我个人习惯把第一步叫"摆相机",第二步叫"透视投影",第三步叫"数字化"。这样好记。
3.2 内参矩阵:相机的"身份证"
内参矩阵 K 描述了相机内部的几何特性。它长这样:
K = [fx, 0, cx;
0, fy, cy;
0, 0, 1]
| 参数 | 含义 | 典型值(1080p相机) |
|---|---|---|
| fx, fy | 焦距(像素单位) | ~1400 px |
| cx, cy | 主点坐标(光轴与像面交点) | ~960, 540 |
实战经验:fx 和 fy 理论上应该相等,但实际生产中传感器像素不是完美的正方形,所以会有微小差异。我遇到过一台工业相机,fx=1423.7,fy=1425.1,差了1.4个像素——这在亚像素精度测量中必须修正。
3.3 外参矩阵:相机在哪儿?朝哪儿看?
外参矩阵 [R | t] 描述了相机在世界坐标系中的位姿。R 是3×3旋转矩阵,t 是3×1平移向量。
举个例子:假设相机放在桌子上,距离地面1米,正对着前方。那么:
- t = [0, 0, 1]^T(相机在Z轴方向偏移1米)
- R = 单位矩阵(没有旋转)
但实际项目中,相机很少摆得这么规矩。我记得有一次在产线上装相机,安装支架有0.5度的倾斜,结果测量误差直接超了0.3mm。后来我养成了一个习惯:每次装完相机,先用标定板跑一遍外参,确认旋转角小于0.1度再干活。
3.4 透镜畸变:理想很丰满,现实很骨感
针孔模型假设光线完美直线传播,但真实镜头有畸变。主要分两类:
3.4.1 径向畸变
光线通过透镜边缘时弯曲更厉害,导致图像边缘向内或向外偏移。
- 桶形畸变:图像边缘向外凸出,像桶一样。常见于广角镜头。
- 枕形畸变:图像边缘向内凹陷。常见于长焦镜头。
数学模型(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)
其中 r^2 = x^2 + y^2,是归一化坐标到光心的距离。
避坑指南:我曾经用过一个廉价镜头,k1 达到 -0.35,边缘畸变超过15个像素。如果不校正,在图像边缘做测量,误差能到毫米级。所以,做高精度测量时,一定要用低畸变镜头,或者做完整的畸变校正。
3.4.2 切向畸变
镜头和传感器不平行时产生。说白了,就是镜头装歪了。
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 是切向畸变系数。
切向畸变在工业相机中比较少见,因为镜头座都是精密加工的。但我在手机摄像头项目里遇到过——手机镜头模组组装时,胶水固化不均匀,导致传感器倾斜,切向畸变系数 p1 达到 0.002。虽然看着不大,但在图像边缘能产生2-3个像素的偏移。
3.5 完整畸变模型:五参数模型
实际标定时,我们通常用5个畸变参数:[k1, k2, p1, p2, k3]。k3 只在畸变特别严重时才用,比如鱼眼镜头。
| 参数 | 范围 | 说明 |
|---|---|---|
| k1 | -0.5 ~ 0.5 | 主要径向畸变,绝对值越大畸变越严重 |
| k2 | -0.2 ~ 0.2 | 高阶径向畸变,通常比k1小一个数量级 |
| p1, p2 | -0.01 ~ 0.01 | 切向畸变,好的镜头接近0 |
| k3 | -0.1 ~ 0.1 | 更高阶径向畸变,非必要不用 |
3.6 知识体系总览
下面这张图把整个相机成像模型串起来了。你想想看,从世界坐标到像素坐标,每一步都有明确的数学对应。
3.7 标定流程:从理论到实践
理论讲完了,怎么拿到这些参数?我一般走这四步:
- 采集标定板图像:至少15-20张,覆盖不同角度和位置
- 提取角点:用OpenCV的 findChessboardCorners 或 findCirclesGrid
- 求解参数:用 calibrateCamera 函数,得到内参、外参、畸变系数
- 验证精度:重投影误差小于0.5像素才算合格
我的习惯:标定完成后,我会拍一张棋盘格放在图像中心,再拍一张放在边缘。分别计算角点坐标的理论值和实际值,看看误差分布。如果边缘误差比中心大很多,说明畸变模型没拟合好,需要增加标定板在边缘位置的图像。
3.8 常见问题与避坑
- 标定板不平:打印的棋盘格贴在玻璃板上,不要贴纸板上。纸板会弯曲。
- 图像太少:少于10张标定结果不稳定。我一般拍25张。
- 忽略切向畸变:大部分工业镜头切向畸变很小,但手机摄像头必须考虑。
- 焦距单位搞混:fx = f / dx,其中 f 是物理焦距(mm),dx 是像素尺寸(mm/pixel)。
嗯,相机成像模型就讲到这里。这套东西我用了十年,从最初的死记硬背到现在的条件反射,中间踩过不少坑。希望你能一次搞明白,少走弯路。