从针孔到鱼眼:主流相机投影模型与畸变校正全解析
1. 相机投影模型入门从针孔到鱼眼的视觉世界第一次接触相机标定时我被各种投影模型搞得晕头转向。为什么同样的场景用不同镜头拍出来的照片差异这么大后来才发现这背后藏着三种完全不同的数学描述方式。就像用不同的眼镜看世界——普通眼镜、广角镜和鱼眼镜看到的画面自然不同。最基础的针孔模型就像小时候做的小孔成像实验。光线通过一个小孔在暗箱内形成倒像数学描述极其简洁u f * X / Z cx v f * Y / Z cy其中(f, cx, cy)就是我们需要标定的内参。这个模型在手机摄像头和普通单反上表现良好但当视场角超过70度时边缘畸变就会变得非常明显。广角模型像是针孔模型的升级版通过引入畸变参数来补偿现实镜头的缺陷。我在做无人机视觉导航时就深有体会——普通针孔模型处理广角镜头图像时边缘直线都变成了曲线必须用径向畸变系数k1,k2和切向畸变系数p1,p2来校正。而鱼眼模型则是完全不同的设计哲学。它追求的是超大的视场角甚至达到180度以上代价是严重的桶形畸变。就像通过门上的猫眼看世界中心区域被放大边缘严重压缩。这种模型在VR全景拍摄和车载环视系统中特别常见。2. 针孔模型简洁背后的数学之美2.1 理想模型的现实局限针孔模型的优雅之处在于它只需要4个基本参数(f, cx, cy)就能描述成像过程。我在教学生做视觉SLAM时总是让他们先用这个模型练手。OpenCV的标定函数cv2.calibrateCamera()默认就是基于此模型。但现实很骨感——去年用普通监控摄像头做人员检测时我发现靠近画面边缘的人脸都变成了外星人。这就是典型的径向畸变表现为桶形或枕形失真。解决方法是在模型中加入非线性项x x(1 k1*r² k2*r⁴ k3*r⁶) y y(1 k1*r² k2*r⁴ k3*r⁶)其中r² x² y²。实测发现对大多数镜头来说k1和k2就足够用了更高阶项反而可能引入过拟合。2.2 标定实战中的坑与技巧用棋盘格标定时我总结了几条实用经验棋盘格要占画面至少1/3面积不同角度拍摄15-20张避免纯平面运动让棋盘格在三维空间中有充分旋转边缘区域必须覆盖到这是标定精度的关键使用OpenCV的CALIB_USE_LU分解选项可以提高数值稳定性标定完成后一定要做重投影误差检查。我遇到过标定误差0.3像素但实际使用时校正效果却不理想的情况——后来发现是标定板不够平整导致的。现在我都改用陶瓷基板的标定板了温度稳定性更好。3. 广角模型的折中之道3.1 平衡的艺术广角镜头通常指视场角60-120度在设计上就是在针孔的简洁性和鱼眼的宽广性之间找平衡。我的运动相机改装项目就深有体会想要捕捉更多场景信息又不希望画面扭曲得太夸张。这类模型通常采用多项式畸变模型除了径向畸变外还要考虑切向畸变x x [ 2p1xy p2(r²2x²) ] y y [ p1(r²2y²) 2p2xy ]切向畸变通常比径向畸变小一个数量级但在工业相机特别是线扫相机中就不能忽略了。3.2 标定参数的可解释性有个很有意思的现象同样的镜头用不同软件标定出来的参数可能差异很大但校正效果却差不多。这是因为畸变参数之间存在耦合。我做过一个实验固定k3标定和放开k3标定得到的k1,k2值可以相差数倍但用这两组参数做图像校正结果肉眼几乎看不出区别。这给我们的启示是不要过度追求参数本身的数值而应该关注它们在具体任务中的实际表现。在视觉里程计中我甚至会故意固定某些高阶项来提高系统稳定性。4. 鱼眼镜头的魔法世界4.1 超越180度的视野鱼眼镜头通过故意引入极大的畸变来换取超广视角。在无人机航拍时单个鱼眼镜头就能实现半球覆盖省去了多相机拼接的麻烦。但这种便利的代价是复杂的投影模型。目前主流的鱼眼模型有几种等距投影r f*θ等立体角投影r 2f*sin(θ/2)正交投影r f*sinθ体视投影r 2f*tan(θ/2)我在做全景拼接时发现不同厂商的鱼眼镜头可能采用不同的投影方式。有个取巧的方法用OpenCV的fisheye模块标定后可以通过projection_error指标来判断实际符合哪种模型。4.2 鱼眼标定的特殊技巧鱼眼镜头的标定需要特别注意棋盘格必须足够小确保在极端畸变下仍能检测到角点建议使用cv2.fisheye.calibrate专用函数初始参数猜测很重要可以用approximate_fov先估算标定后一定要检查天顶区域的校正效果有个容易忽略的点鱼眼镜头的有效成像区域通常不是完整的圆形。我在处理某款安防鱼眼相机时就发现边缘有约5%的死区强行校正这部分区域会导致严重artifact。后来在代码中加入了mask处理问题才解决。5. 模型选择与实战建议5.1 根据应用场景做选择经过多个项目实践我总结出这样的选择策略SLAM/VIO优先考虑针孔畸变模型计算量小精度足够全景拼接鱼眼模型是首选但要考虑接缝处的平滑过渡三维重建广角模型更适合需要在精度和视野间平衡测量检测必须用针孔模型且要严格控制畸变去年做仓储机器人导航时我对比过三种方案最终选择了165度广角镜头因为鱼眼镜头的边缘分辨率太低而普通广角又覆盖不了足够大的区域。5.2 校正算法的实现细节在工程实现上有几个优化点值得分享使用查找表(LUT)存储校正映射比实时计算快20倍对于4K视频可以只计算1/4分辨率的映射然后双线性插值在FPGA上实现校正时采用定点数运算能大幅节省资源对于实时性要求高的场景可以考虑GPU加速的remap函数有个坑我踩过两次校正后的图像边界会出现黑边。正确的处理方式是在标定时就记录有效区域ROI或者用inpainting算法智能填充。