2. 针孔相机模型:成像原理、内参矩阵与畸变模型
说到相机标定,咱们得先搞清楚一件事:相机到底是怎么看到世界的?
你可能会觉得这问题太基础了。但说实话,我在做SLAM的初期,就因为对成像模型理解不够深,吃过不少亏。有一次标定出来的内参,怎么看怎么不对劲,折腾了两天才发现——我用的畸变模型跟相机实际的不匹配。
所以这一章,咱们把针孔相机模型彻底聊透。从原理到数学,再到实际工程中的坑,一步到位。
2.1 针孔成像:最简单的相机
针孔相机模型,说白了就是一个小黑盒,前面戳个针孔,后面放个感光平面。光线从物体上反射过来,穿过针孔,在后面的平面上形成一个倒立的像。
这个模型虽然简单,但它抓住了成像的本质:3D世界到2D图像的投影。
实际相机当然不是真的用针孔,而是用透镜。但透镜会引入畸变,这个我们后面再聊。先把这个理想模型吃透。
核心思想:针孔模型假设所有光线都通过一个点(光心),然后投影到成像平面上。这是一个线性模型,数学上非常干净。
2.2 从世界到像素:四个坐标系的变换
一个3D点怎么变成图像上的像素?中间要经过四次坐标变换。我习惯把这四个步骤记成一张流程图:
2.3 内参矩阵:相机的"基因"
内参矩阵K,是相机最核心的参数。它描述了从归一化平面到像素坐标的映射关系。
数学形式长这样:
K = [fx 0 cx]
[ 0 fy cy]
[ 0 0 1]
四个参数各司其职:
| 参数 | 含义 | 工程影响 |
|---|---|---|
| fx | x方向焦距(像素单位) | 决定图像水平方向的缩放 |
| fy | y方向焦距(像素单位) | 决定图像垂直方向的缩放 |
| cx | 主点x坐标(像素) | 光轴与成像平面的交点 |
| cy | 主点y坐标(像素) | 通常接近图像中心,但不完全 |
我的经验:fx和fy理论上应该相等(如果像素是正方形)。但实际中,很多相机的fx和fy会有微小差异。我遇到过一台工业相机,fx和fy差了0.3%,虽然不大,但在高精度测量场景下,这个差异必须标定出来。
2.4 畸变模型:现实总是不完美的
针孔模型是理想情况。但实际相机用了透镜,透镜就会引入畸变。说白了,就是图像变形了。
畸变主要分两类:
2.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 是径向畸变系数。
避坑指南:我曾经在标定一个鱼眼镜头时,只用了k1和k2两个参数,结果标定出来的图像边缘还是弯的。后来加上k3才搞定。对于视场角超过120°的镜头,建议至少用三个径向畸变参数。
2.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 是切向畸变系数。
2.5 完整的畸变校正流程
在实际工程中,我们拿到一张图像,第一步往往就是做畸变校正。流程如下:
- 获取原始像素坐标 (u, v)
- 反算到归一化平面:x = (u - cx)/fx, y = (v - cy)/fy
- 计算畸变量:用上面提到的径向和切向公式
- 得到校正后的归一化坐标
- 重新投影到像素坐标
代码实现大概长这样:
def undistort_point(u, v, K, dist_coeffs):
fx, fy, cx, cy = K[0,0], K[1,1], K[0,2], K[1,2]
k1, k2, p1, p2, k3 = dist_coeffs
# 归一化坐标
x = (u - cx) / fx
y = (v - cy) / fy
# 计算畸变
r2 = x*x + y*y
r4 = r2*r2
r6 = r4*r2
# 径向畸变
k_radial = 1 + k1*r2 + k2*r4 + k3*r6
x_rad = x * k_radial
y_rad = y * k_radial
# 切向畸变
x_corr = x_rad + 2*p1*x*y + p2*(r2 + 2*x*x)
y_corr = y_rad + p1*(r2 + 2*y*y) + 2*p2*x*y
# 投影回像素
u_corr = x_corr * fx + cx
v_corr = y_corr * fy + cy
return u_corr, v_corr
重要提醒:畸变校正通常是对整张图像做的,不是对单个点。OpenCV的cv2.undistort()函数就是干这个的。但如果你在做SLAM,只需要对特征点做校正,那就用上面的逐点方法,效率高得多。
2.6 工程中的常见问题
做标定和畸变校正时,有几个坑我踩过,分享给你:
| 问题 | 现象 | 解决方案 |
|---|---|---|
| 标定板图像太少 | 内参不稳定,每次标定结果差异大 | 至少拍15-20张不同角度的标定板图像 |
| 标定板占画面比例太小 | 畸变参数不准 | 让标定板覆盖画面1/3以上 |
| 忽略切向畸变 | 图像有梯形变形 | 工业相机一定要标定p1、p2 |
| 畸变模型选错 | 校正后边缘仍有弯曲 | 鱼眼镜头用专门模型,别用普通针孔 |
2.7 小结
针孔相机模型是整个多视角几何的基石。内参矩阵描述了相机的"基因",畸变模型修正了现实的不完美。理解透这两块,后面的立体匹配、三角化、BA优化才能走得稳。
嗯,这一章就到这里。记住:标定不是一次性的活,相机温度变化、镜头松动都会导致内参漂移。定期重新标定,是个好习惯。