3. 相机成像模型
各位同学,欢迎来到第三章。
这一章是整个3D视觉的基石。说白了,相机是怎么把三维世界变成一张二维图片的?你看到的每个像素,背后都有一套严格的数学映射。我当年刚入行时,觉得这些公式枯燥,直到第一次做手眼标定,发现抓取点总是偏几毫米,才意识到——嗯,成像模型没吃透,后面全是空中楼阁。
3.1 针孔模型——最朴素的成像原理
先别被“模型”两个字吓到。你想想看,小孔成像大家都玩过吧?一个暗箱,前面戳个小孔,外面的景物就倒着映在后面的毛玻璃上。针孔模型就是把这个过程数学化。
核心就一句话:三维空间中的点,通过光心投影到成像平面上。
数学上,假设世界点坐标为 (X, Y, Z),成像点坐标为 (x, y),焦距为 f。根据相似三角形:
x = f * (X / Z)
y = f * (Y / Z)
注意,这里有个关键细节:Z 是深度,不是到光心的直线距离。我在项目中遇到过有人把 Z 理解成斜距,结果投影全错了,排查了一整天。
核心结论:针孔模型是线性模型,但真实相机因为透镜的存在,会引入畸变。所以针孔模型只是“理想情况”,实际使用时必须配合畸变校正。
3.2 畸变模型——为什么直线会变弯?
你拍一张棋盘格照片,放大边缘看看。原本笔直的线条,是不是有点弯?这就是畸变。
畸变主要分两类:径向畸变和切向畸变。
3.2.1 径向畸变
径向畸变是透镜形状不完美造成的。越靠近图像边缘,变形越明显。我习惯把它想象成“鱼眼效果”——只不过鱼眼是故意夸张,而我们是要消除它。
数学上,用泰勒级数来修正:
x_corrected = x * (1 + k1 * r² + k2 * r⁴ + k3 * r⁶)
y_corrected = y * (1 + k1 * r² + k2 * r⁴ + k3 * r⁶)
其中 r 是像素到图像中心的距离,k1、k2、k3 是径向畸变系数。一般工业相机用 k1、k2 就够了,k3 通常用于大畸变镜头(比如鱼眼)。
我的经验:标定时如果只给 k1、k2,结果往往还行。但如果你用广角镜头,一定要加上 k3。我曾经在一个料箱抓取项目里,因为没加 k3,边缘的抓取点偏差达到 5mm,后来加上就好了。
3.2.2 切向畸变
切向畸变是透镜和成像平面不平行造成的。说白了,就是镜头装歪了。
修正公式:
x_corrected = x + [2 * p1 * x * y + p2 * (r² + 2 * x²)]
y_corrected = y + [p1 * (r² + 2 * y²) + 2 * p2 * x * y]
p1、p2 是切向畸变系数。实际项目中,切向畸变通常比径向畸变小一个数量级。但别忽略它——在精密抓取中,0.1mm 的误差都可能让夹爪撞到工件。
避坑指南:我曾经在一个项目中,只标定了径向畸变,忽略了切向。结果在图像边缘区域,抓取点总是偏。后来加上切向畸变标定,问题解决。记住:畸变模型要完整,不要偷懒。
3.3 内参矩阵——相机自己的“身份证”
内参矩阵描述的是相机内部的几何特性。它把相机坐标系下的点,映射到像素坐标系。
标准形式:
K = [fx, 0, cx
0, fy, cy
0, 0, 1]
各参数物理意义:
| 参数 | 物理意义 | 单位 |
|---|---|---|
| fx, fy | 焦距在 x、y 方向的像素尺度 | 像素 |
| cx, cy | 主点(光轴与成像平面交点)的像素坐标 | 像素 |
你可能会问:为什么焦距会有两个值?因为像素不是正方形的。工业相机里,fx 和 fy 通常很接近,但不完全相等。我见过一些初学者直接把 fx 当 fy 用,结果图像比例失真。
关键理解:内参矩阵只跟相机本身有关。换镜头、调焦距,内参就会变。所以每次拆装镜头后,必须重新标定内参。
3.4 外参矩阵——相机在哪儿?朝哪儿看?
外参矩阵描述的是相机在世界坐标系中的位置和朝向。它由旋转矩阵 R 和平移向量 t 组成:
[R | t]
其中 R 是 3×3 的旋转矩阵,t 是 3×1 的平移向量。
物理意义很直观:
- R:相机朝哪个方向看(姿态)
- t:相机在哪儿(位置)
举个例子:你把相机固定在机械臂末端。机械臂动一下,外参就变了。但内参纹丝不动。这就是内外参的本质区别。
我的习惯:在无序抓取项目中,我通常把外参矩阵写成 4×4 的齐次变换矩阵。这样方便跟机械臂的位姿直接相乘,省去很多坐标转换的麻烦。
3.5 完整成像流程——从世界点到像素
把上面所有东西串起来,一个三维点变成像素的完整流程是:
- 世界坐标系 → 相机坐标系:乘以 [R | t]
- 相机坐标系 → 归一化平面:除以 Z
- 加畸变:用径向/切向模型修正
- 归一化平面 → 像素坐标系:乘以内参矩阵 K
写成数学形式:
s * [u, v, 1]ᵀ = K * [R | t] * [X, Y, Z, 1]ᵀ
其中 s 是尺度因子(其实就是 Z)。
这个公式,我建议你手推一遍。当年我就是靠手推,才真正理解了每个矩阵的物理意义。光看是记不住的。
3.6 标定实战——你需要知道的事
理论讲完了,说点实际的。标定相机内参和畸变,最常用的方法是张正友标定法。你只需要打印一张棋盘格,拍十几张不同角度的照片,然后用 OpenCV 的 calibrateCamera() 函数就能搞定。
但有几个坑,我帮你列出来:
- 棋盘格要平整:贴在硬板上,别用软纸。我见过有人贴墙上,结果墙面不平,标定出来畸变系数全是错的。
- 覆盖整个视野:照片要包含图像中心、边缘、四个角。只拍中间,边缘畸变标不准。
- 角度要多样:倾斜、旋转、远近都要有。只拍正面的,解算不稳定。
- 照片数量:15-20 张足够。太多反而增加计算量,太少精度不够。
重要提醒:标定完成后,一定要做重投影误差检查。如果平均误差超过 0.5 像素,说明标定质量不行,需要重新拍。我给自己定的标准是 < 0.3 像素。
3.7 本章小结
这一章的内容,是后续所有章节的基础。你理解了针孔模型,就知道为什么深度 Z 这么重要;你理解了畸变模型,就知道为什么边缘抓取点要特别小心;你理解了内外参,就知道手眼标定到底在标什么。
下一章,我们会把这些知识用到相机标定实战中。到时候,我会手把手带你走一遍完整的标定流程,包括代码实现和结果验证。
嗯,今天就到这儿。记得把公式手推一遍,别偷懒。