2. 相机成像模型:针孔模型、透镜模型、坐标系转换
相机是怎么把三维世界变成二维图像的?这个问题,我刚开始做图像处理时也琢磨了很久。说白了,成像模型就是一套数学规则,告诉我们光线怎么走、像素怎么来。今天咱们就把针孔模型、透镜模型和坐标系转换这三块彻底讲透。
核心要点:所有镜头畸变校正和色彩校正的算法,都建立在理解成像模型的基础上。模型不对,后面的校正全是白搭。
2.1 针孔模型——最朴素的成像原理
针孔模型是相机成像的"理想状态"。你想想看,一个小孔,光线穿过它,在后面的平面上形成倒像。这就是最原始的相机。
数学上,针孔模型用四个坐标系来描述:世界坐标系、相机坐标系、图像坐标系、像素坐标系。我习惯把它们分成两组来理解:
- 三维部分:世界坐标系 → 相机坐标系(刚体变换)
- 二维部分:相机坐标系 → 图像坐标系(透视投影)→ 像素坐标系(离散化)
投影公式很简单:
// 从相机坐标系 (Xc, Yc, Zc) 到图像坐标系 (x, y)
x = f * Xc / Zc
y = f * Yc / Zc
// 其中 f 是焦距,单位是毫米
嗯,这里要注意:针孔模型假设光线是直线传播,没有畸变。但现实中的镜头不是这样的。我在一个手机摄像头项目里就吃过这个亏——直接用针孔模型标定,结果边缘畸变校正得一塌糊涂。
2.2 透镜模型——更接近真实世界
真实镜头用的是透镜组,不是小孔。透镜模型在针孔模型基础上,引入了两个关键修正:
- 径向畸变:光线通过透镜边缘时弯曲更厉害,产生"桶形"或"枕形"畸变
- 切向畸变:透镜与成像平面不平行,产生"梯形"畸变
我曾经在一个工业检测项目里,用广角镜头拍电路板。边缘的焊点都歪了,算法死活检测不准。后来一查,径向畸变系数 k1 都到 -0.35 了,不校正根本没法用。
畸变模型用多项式表示:
// 径向畸变
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)
// 切向畸变
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]
// 其中 r^2 = x^2 + y^2
我的经验:对于普通手机镜头,用 k1、k2 两个径向畸变参数就够了。k3 和切向畸变参数 p1、p2 通常只在鱼眼镜头或高精度测量时才需要。别一上来就求全,反而容易过拟合。
2.3 坐标系转换——把世界变成像素
坐标系转换是整个成像模型的"粘合剂"。我把它拆成三步走:
| 步骤 | 变换 | 参数 | 说明 |
|---|---|---|---|
| 1 | 世界 → 相机 | 旋转矩阵 R + 平移向量 t | 刚体变换,6个自由度 |
| 2 | 相机 → 图像 | 焦距 f | 透视投影,3D变2D |
| 3 | 图像 → 像素 | 主点 (cx, cy) + 像素尺寸 (dx, dy) | 离散化,单位从mm变pixel |
完整的投影公式写成矩阵形式:
// 齐次坐标形式
s * [u] [fx 0 cx] [R11 R12 R13 t1] [Xw]
[v] = [ 0 fy cy] * [R21 R22 R23 t2] * [Yw]
[1] [ 0 0 1] [R31 R32 R33 t3] [Zw]
[1 ]
// 简化写法:s * p_pixel = K * [R|t] * P_world
// K 是内参矩阵,[R|t] 是外参矩阵
避坑指南:我曾经在标定一个双目相机系统时,发现左右相机的内参差异很大。排查了半天,原来是标定板放得太近,导致外参估计不准。记住:标定板距离至少是镜头焦距的20倍以上,否则外参的平移向量会严重偏差。
2.4 知识体系总览
下面这张图把本章的核心逻辑串起来了。我建议你把它当作"地图",后面讲畸变校正和色彩校正时,随时回来对照。
2.5 内参与外参——标定的核心
相机标定,说白了就是求内参和外参。我整理了一个对比表,方便你理解:
| 参数类型 | 包含内容 | 物理意义 | 标定方法 |
|---|---|---|---|
| 内参 | fx, fy, cx, cy, 畸变系数 | 镜头本身的固有属性 | 张正友标定法(棋盘格) |
| 外参 | R (3x3), t (3x1) | 相机在世界坐标系中的位姿 | PnP / 直接线性变换 |
我的习惯:标定内参时,至少拍15-20张不同角度的棋盘格照片。角度要覆盖俯仰、偏航、旋转三个维度。我见过有人只拍5张就标定,结果畸变校正后图像边缘还是弯的——省事一时爽,后面调试火葬场。
2.6 从模型到校正——承上启下
理解了成像模型,畸变校正就变成了一个"反问题":已知畸变后的像素坐标,求它在理想针孔模型下的位置。具体来说:
- 用内参把像素坐标反投影到归一化平面
- 用畸变模型计算畸变后的坐标
- 用内参重新投影回像素坐标
- 双线性插值得到校正后的像素值
这个过程,说白了就是"先找到每个像素在理想图像中应该在哪,然后去原图里采样"。我在做实时视频畸变校正时,会把映射关系预先算好存成查找表(LUT),这样每帧只需要查表+插值,速度能快10倍以上。
避坑指南:我曾经在嵌入式平台上做畸变校正,直接逐像素计算映射关系,结果帧率只有5fps。后来改成离线生成LUT,运行时只做查表和插值,帧率直接飙到30fps。记住:能离线算的,别在线算。