径向畸变原理:桶形畸变、枕形畸变与数学模型
镜头畸变,说白了就是镜头“不老实”。
光线本该直直地走,结果被镜片组带偏了。我最早接触这问题是在做无人机航拍拼接时,明明拍了十几张图,拼出来却像哈哈镜——边缘的建筑全弯了。后来才明白,这就是径向畸变在捣鬼。
两种最常见的畸变形态
径向畸变主要分两种:桶形畸变和枕形畸变。名字很形象,你看一眼就记住了。
| 畸变类型 | 现象描述 | 常见场景 |
|---|---|---|
| 桶形畸变 | 图像中心向外膨胀,直线向外弯曲,像木桶的弧面 | 广角镜头、手机前置摄像头、鱼眼镜头 |
| 枕形畸变 | 图像边缘向内收缩,直线向内弯曲,像枕头凹陷 | 长焦镜头、变焦镜头长焦端 |
关键判断口诀:桶形畸变——直线向外弯,像肚子鼓出来;枕形畸变——直线向内弯,像肚子瘪进去。
为什么会这样?
桶形畸变通常是因为镜头前组镜片对边缘光线的折射力太强,把边缘光线“掰”向了中心。枕形畸变则相反,边缘光线被“掰”向了外侧。嗯,你可以理解为镜片组的光学设计没做到完美平衡。
径向畸变的数学模型
数学上,我们用多项式来建模这个畸变。别怕,公式其实很直观。
假设理想图像中某点的归一化坐标为 (x, y),畸变后的坐标为 (xd, yd)。那么:
x_d = x * (1 + k1 * r² + k2 * r⁴ + k3 * r⁶)
y_d = y * (1 + k1 * r² + k2 * r⁴ + k3 * r⁶)
其中 r² = x² + y²,k1、k2、k3 是畸变系数。
这个公式的核心思想很简单:离图像中心越远(r 越大),畸变越严重。系数 k1 控制主要畸变方向,k2 和 k3 用来修正高阶畸变。
我的经验:实际项目中,大部分镜头只用 k1 和 k2 就够了。k3 通常只在鱼眼镜头或极端广角镜头中才需要。我曾经为了省事,给普通手机镜头也用了三阶模型,结果过拟合了——校正后的图像反而出现了波浪形失真。
系数正负与畸变类型的关系
这里有个很直观的对应关系:
| k1 符号 | 畸变类型 | 效果 |
|---|---|---|
| k1 < 0 | 桶形畸变 | 图像向外膨胀,边缘像素被“拉伸” |
| k1 > 0 | 枕形畸变 | 图像向内收缩,边缘像素被“压缩” |
你想想看,k1 为负时,1 + k1 * r² 小于 1,意味着畸变后的坐标比理想坐标更靠近中心——这不就是桶形畸变吗?反过来,k1 为正时,坐标被推离中心,形成枕形畸变。
注意:k1 的值通常很小,一般在 10⁻³ 到 10⁻⁶ 量级。如果你标定出来的 k1 值异常大(比如 0.1 以上),大概率是标定过程出了问题,或者镜头本身有机械损伤。
径向畸变校正流程
校正过程其实就三步,我习惯这么记:
- 标定——用棋盘格或圆点标定板,算出 k1、k2、k3 和相机内参
- 映射——对输出图像的每个像素,反查它在畸变图像中的位置
- 插值——因为反查到的坐标通常是小数,需要用双线性插值取像素值
这里有个坑:很多人直接正向映射——遍历畸变图像的每个像素,算它应该去输出图像的哪个位置。结果输出图像里会出现空洞和重叠。我刚开始也犯过这个错,后来才明白必须用反向映射。
知识结构图
下面这张图帮你理清径向畸变的完整脉络:
实际项目中的避坑指南
讲几个我踩过的坑,你遇到了能少走弯路:
- 标定板要拍够角度——我曾经只拍了 5 张棋盘格就去标定,结果 k1 值每次都不一样。后来养成习惯,至少拍 15-20 张不同角度、不同位置的标定图像。
- 边缘区域不要直接裁掉——校正后的图像边缘会有黑边,很多人直接裁剪。但如果你做的是测量类项目,边缘信息可能很重要。我一般用边缘填充或镜像扩展来处理。
- 注意畸变中心和图像中心不重合——数学模型里假设畸变中心在图像中心,但实际镜头装配有误差。我习惯把畸变中心 (cx, cy) 也作为参数一起优化,精度能提升不少。
小技巧:如果你用的是 OpenCV,cv::initUndistortRectifyMap 和 cv::remap 这对组合能帮你搞定大部分工作。但记得先做一次 cv::calibrateCamera 拿到内参和畸变系数。
嗯,径向畸变这部分就讲到这里。记住那个多项式公式,理解 k1 正负的意义,校正流程别搞反——你就能处理 90% 的镜头畸变问题了。