4. 相机成像模型:针孔相机模型、内参矩阵、畸变模型
做机器视觉这么多年,我始终觉得相机成像模型是绕不开的基石。你想想看,手眼标定说白了就是让机器人知道相机看到的物体在什么位置。如果连相机怎么成像的都不清楚,那后面的标定工作就是空中楼阁。
这一章,我们就来把相机成像这件事彻底讲透。我会从最经典的针孔模型开始,然后带你理解内参矩阵,最后把畸变模型也掰开揉碎。嗯,这些概念在 HALCON 里都有对应的算子,理解了原理,你写代码的时候心里就有底了。
4.1 针孔相机模型:最朴素的成像原理
针孔相机模型,说白了就是小孔成像。你小时候可能玩过:一个暗盒,前面戳个小孔,外面的景物就倒着映在后面的墙上。相机镜头虽然复杂,但核心思想是一样的——把三维世界投影到二维平面上。
我个人习惯把针孔模型拆成三个坐标系来看:
- 世界坐标系:物体在真实世界中的位置,单位是毫米或米
- 相机坐标系:以相机光心为原点,Z轴指向镜头前方
- 图像坐标系:成像平面上的像素位置,单位是像素
从世界坐标到像素坐标,中间经历了两次变换。第一次是刚体变换(旋转+平移),把世界坐标转到相机坐标系。第二次是透视投影,把三维点映射到成像平面上。
关键公式:针孔模型的投影关系
假设相机坐标系下有一个点 P(X, Y, Z),它在成像平面上的投影位置是:
x = f * X / Z
y = f * Y / Z
其中 f 是焦距。注意这里有个 Z 在分母上,这就是透视效果——近大远小。
我在项目中遇到过不少新手,上来就问为什么标定板要倾斜着拍。其实原因很简单:针孔模型假设所有光线都穿过光心,如果标定板始终正对着相机,那很多参数就解不出来了。你想想看,一个平面正对着相机,它提供的约束其实很少。
4.2 内参矩阵:从物理世界到像素的桥梁
内参矩阵,我更喜欢叫它"相机自己的身份证"。每个相机都有自己独特的内参,包括焦距、主点位置、像素尺寸等。这些参数一旦固定,只要不调焦、不换镜头,就不会变。
内参矩阵通常写成 3x3 的形式:
[ fx 0 cx ]
K = [ 0 fy cy ]
[ 0 0 1 ]
这里面的参数含义:
| 参数 | 含义 | 单位 |
|---|---|---|
| fx, fy | 焦距在 x、y 方向的像素当量 | 像素 |
| cx, cy | 主点坐标(光轴与成像平面的交点) | 像素 |
为什么 fx 和 fy 可能不一样?因为像素不一定是正方形的。我见过一些工业相机,像素是矩形的,这时候 fx 和 fy 就会有差异。另外,cx 和 cy 也不一定在图像正中心,这跟镜头安装精度有关。
我的经验:在 HALCON 里,内参矩阵用 cam_par 这个元组来表示。你调用 camera_calibration 算子后,得到的结果里就包含了内参。我建议你每次标定完都把内参存下来,下次用的时候直接加载,省得重复标定。
有了内参矩阵,我们就可以把相机坐标系下的点映射到像素坐标了。整个过程可以写成:
像素坐标 = K * [R|t] * 世界坐标
其中 [R|t] 是外参矩阵,负责把世界坐标转到相机坐标系。这个公式,就是整个视觉定位的数学基础。
4.3 畸变模型:现实世界没有完美的镜头
理想很丰满,现实很骨感。针孔模型假设镜头是完美的,但实际镜头都有畸变。你拍一张棋盘格照片,如果发现边缘的格子变弯了,那就是畸变在作怪。
畸变主要分两种:径向畸变和切向畸变。我一个个说。
4.3.1 径向畸变:镜头天生的"肚子"
径向畸变是因为镜头的曲率不完美造成的。离光心越远,畸变越明显。它有两种表现形式:
- 桶形畸变:图像向外凸出,像桶一样。广角镜头常见。
- 枕形畸变:图像向内凹陷,像枕头。长焦镜头常见。
数学上,径向畸变用三个参数来描述:k1、k2、k3。其中 k1 是主要畸变,k2 和 k3 用来修正边缘区域的畸变。校正公式是:
x_corrected = x * (1 + k1*r^2 + k2*r^4 + k3*r^6)
y_corrected = y * (1 + k1*r^2 + k2*r^4 + k3*r^6)
这里的 r 是像素点到光心的距离。你看,r 越大,畸变越严重。
注意:k3 通常只在鱼眼镜头或畸变特别大的镜头中才需要。普通工业镜头,标定到 k2 就够了。我曾经见过有人把 k3 也标出来,结果过拟合了,校正后的图像反而更差。
4.3.2 切向畸变:镜头装歪了
切向畸变,说白了就是镜头和成像平面不平行。这通常是因为镜头安装时有点歪,或者 CMOS 芯片没贴正。
切向畸变用两个参数描述:p1、p2。校正公式是:
x_corrected = x + [2*p1*x*y + p2*(r^2 + 2*x^2)]
y_corrected = y + [p1*(r^2 + 2*y^2) + 2*p2*x*y]
切向畸变的影响通常比径向畸变小,但在高精度测量中不能忽略。我做手眼标定时,一般会把 p1、p2 都标出来,反正 HALCON 的标定算子会自动处理。
4.4 畸变校正:让图像回归真实
知道了畸变参数,我们就可以对图像进行校正了。HALCON 里有一个非常方便的算子 change_radial_distortion_cam_par,它可以生成一个无畸变的内参,然后用 map_image 算子把畸变图像映射成无畸变图像。
我个人的工作流程是这样的:
- 用标定板拍 15-20 张不同角度的图片
- 调用
camera_calibration算子,得到内参和畸变参数 - 用
change_radial_distortion_cam_par生成无畸变内参 - 用
map_image对图像做畸变校正 - 在校正后的图像上做后续的视觉处理
避坑指南:我曾经犯过一个错误——在校正前的图像上做特征提取,然后用手眼标定结果去引导机器人。结果发现精度总差那么一两个像素。后来才意识到,畸变图像上的坐标和实际物理坐标不对应,必须校正后才能用。从那以后,我都是先校正再处理。
4.5 本章知识结构
为了让你更直观地理解相机成像模型的整体脉络,我画了一张结构图。它把针孔模型、内参矩阵、畸变模型之间的关系串起来了。
这张图把本章的核心内容串起来了。你从顶层往下看,先理解针孔模型怎么把三维世界投影到二维平面,再掌握内参矩阵如何描述相机自身的属性,最后搞清楚畸变模型怎么校正镜头带来的误差。这三块内容,就是相机成像的全部秘密。
本章要点回顾:
- 针孔模型是相机成像的基础,核心是透视投影
- 内参矩阵包含焦距和主点,是相机自身的"身份证"
- 径向畸变由镜头曲率引起,用 k1、k2、k3 描述
- 切向畸变由镜头安装偏差引起,用 p1、p2 描述
- 畸变校正是手眼标定前的必要步骤,千万别跳过