3. 相机畸变模型:径向畸变、切向畸变与校正原理

聊到相机标定,畸变是绕不开的话题。说白了,再好的镜头也不是完美的。光线穿过透镜时,总会发生一些“跑偏”,这就是畸变。我刚开始做双目项目时,觉得标定就是走个过场,结果视差图出来全是扭曲的,根本没法用。嗯,从那以后,我老老实实把畸变模型吃透了。

3.1 畸变从哪来?

畸变主要分两类:径向畸变和切向畸变。前者是镜头形状造成的,后者是装配误差导致的。你想想看,一个透镜磨得再圆,边缘部分的光路和中心也不可能完全一样。

核心观点:畸变是成像点偏离理想位置的现象。校正畸变,就是把这些“跑偏”的点拉回原位。

3.2 径向畸变:桶形与枕形

径向畸变沿着镜头半径方向分布。离中心越远,畸变越明显。我见过最典型的例子——用广角镜头拍棋盘格,边缘的格子都弯了。

  • 桶形畸变:图像向外膨胀,像木桶。常见于广角镜头、鱼眼镜头。
  • 枕形畸变:图像向内收缩,像枕头。常见于长焦镜头。

数学上,径向畸变用泰勒级数建模。通常取前两项或三项就够了:

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。别盲目加参数,过拟合反而会引入新误差。

3.3 切向畸变:镜头装歪了

切向畸变,说白了就是镜头和成像平面不平行。我在产线上遇到过一批相机,切向畸变特别大,拆开一看,镜头座装偏了。

切向畸变的模型:

x_corrected = x + [2 * p1 * x * y + p2 * (r² + 2 * x²)]
y_corrected = y + [p1 * (r² + 2 * y²) + 2 * p2 * x * y]

p1、p2 是切向畸变系数。这个畸变会让直线变成斜线,尤其在图像角落更明显。

避坑指南:我曾经只标定径向畸变,忽略切向,结果双目极线校正后还有残留视差。后来加上 p1、p2,精度直接提升了一个量级。

3.4 畸变系数总览

OpenCV 把畸变系数打包成一个向量,通常 5 个参数:

参数 符号 含义 典型范围
k1 径向畸变一阶 主导畸变方向 -0.5 ~ 0.5
k2 径向畸变二阶 边缘精细修正 -0.3 ~ 0.3
p1 切向畸变一阶 水平方向倾斜 -0.1 ~ 0.1
p2 切向畸变二阶 垂直方向倾斜 -0.1 ~ 0.1
k3 径向畸变三阶 高畸变镜头专用 -1.0 ~ 1.0

注意:标定得到的系数是相对于归一化坐标的。实际应用时,OpenCV 的 undistort 函数会自动处理坐标变换。

3.5 校正原理:从畸变到无畸变

校正的核心思路很简单:

  1. 建立映射:对每个输出像素,找到它在畸变图像中的位置。
  2. 插值采样:用双线性插值或最近邻插值,从畸变图像中取像素值。

具体流程:

  • 输入:畸变图像 + 相机内参 + 畸变系数
  • 输出:无畸变图像
  • 关键函数:cv2.undistort() 或 cv2.initUndistortRectifyMap() + cv2.remap()

我个人习惯用 initUndistortRectifyMap 生成映射表,再用 remap 执行。这样在视频流里只需计算一次映射表,后面每帧直接查表,效率高很多。

性能技巧:如果实时性要求高,把映射表存成 np.float32 的数组,避免重复计算。我在嵌入式设备上就是这么干的,帧率从 15fps 提到了 30fps。

3.6 畸变模型知识图谱

下面这张图帮你理清畸变模型的整体结构:

相机畸变模型知识结构图 相机畸变模型知识结构 相机畸变模型 径向畸变 切向畸变 桶形畸变 枕形畸变 系数 k1,k2,k3 水平倾斜 p1 垂直倾斜 p2 校正原理 建立映射表 插值采样

3.7 实战中的注意事项

标定畸变系数时,有几个坑我踩过,分享给你:

  • 棋盘格要覆盖全视野:只拍中间区域,边缘畸变根本标不出来。我早期吃过这个亏,校正后边缘还是弯的。
  • 多角度拍摄:至少 15-20 张不同角度的棋盘格照片。角度变化越大,切向畸变标定越准。
  • 检查重投影误差:标定完成后,看平均重投影误差。一般小于 0.5 像素就算合格。如果超过 1 像素,说明标定质量有问题。

重要提醒:畸变校正会裁剪图像边缘。因为校正后图像是“拉直”的,四个角会变黑。OpenCV 的 undistort 默认会裁剪这些区域。如果你需要保留全视野,可以设置 newCameraMatrix 参数来调整输出尺寸。