1. 为什么需要图像去畸变当你用手机拍一张照片时有没有发现边缘的直线会变弯这就是镜头畸变在作怪。镜头畸变主要分为两种径向畸变和切向畸变。径向畸变会让图像边缘的直线向内凹桶形畸变或向外凸枕形畸变而切向畸变则是因为镜头和成像平面不平行导致的。在实际应用中比如自动驾驶、无人机导航或者AR/VR准确的图像信息至关重要。如果直接使用畸变的图像计算机视觉算法的精度会大打折扣。这就是为什么我们需要对图像进行去畸变处理。2. 十四讲中的去畸变方法解析《视觉SLAM十四讲》中介绍的去畸变方法非常经典它主要针对针孔相机模型。这个方法使用4个畸变参数[k1, k2, p1, p2]其中k1、k2用于校正径向畸变p1、p2用于校正切向畸变。具体公式是这样的x_corrected x(1 k1*r² k2*r⁴) 2*p1*x*y p2*(r² 2x²) y_corrected y(1 k1*r² k2*r⁴) p1*(r² 2y²) 2*p2*x*y其中r² x² y²x和y是归一化图像坐标。这个方法简单直接计算量小适合大多数普通相机的畸变校正。我在实际项目中使用这个方法处理普通广角镜头的畸变效果就很不错边缘的直线都能很好地恢复笔直。3. OpenCV的去畸变实现详解OpenCV提供了更全面的去畸变方案主要通过initUndistortRectifyMap()和remap()两个函数配合使用。这个方法的强大之处在于它支持多种参数组合4个参数k1,k2,p1,p2、5个参数增加k3或者8个参数k1-k6,p1,p2。函数原型是这样的cv.initUndistortRectifyMap(cameraMatrix, distCoeffs, R, newCameraMatrix, size, m1type, map1, map2) cv.remap(src, dst, map1, map2, interpolation)关键参数说明distCoeffs畸变系数可以是4、5或8个参数R可选的旋转矩阵newCameraMatrix新的相机内参矩阵map1/map2输出的映射表OpenCV的去畸变公式比十四讲的更复杂x_corrected x * (1 k1*r² k2*r⁴ k3*r⁶)/(1 k4*r² k5*r⁴ k6*r⁶) 2*p1*x*y p2*(r² 2x²) y_corrected y * (1 k1*r² k2*r⁴ k3*r⁶)/(1 k4*r² k5*r⁴ k6*r⁶) p1*(r² 2y²) 2*p2*x*y这个公式的分子分母都是多项式可以更好地处理大畸变的情况特别是鱼眼镜头的强径向畸变。4. 参数数量的实际影响对比4.1 4参数 vs 5参数 vs 8参数我做过一个对比实验使用同一组鱼眼图像分别用不同数量的参数进行去畸变参数数量适用场景计算速度边缘校正效果中心区域效果4参数普通镜头最快一般优秀5参数广角镜头中等较好优秀8参数鱼眼镜头最慢优秀优秀实测发现对于普通相机4个参数就足够了。但鱼眼相机必须使用8个参数才能获得理想效果特别是图像边缘部分。如果强行用4个参数处理鱼眼图像边缘会出现明显的扭曲和拉伸。4.2 实际应用中的选择建议根据我的经验普通相机使用4个参数(k1,k2,p1,p2)即可速度快效果好广角相机建议使用5个参数(增加k3)能更好地校正边缘鱼眼相机必须使用完整的8个参数否则边缘校正会很差这里有个坑要注意有些相机标定工具输出的畸变参数顺序可能和OpenCV要求的不一致使用时需要仔细检查参数顺序。5. 源码级差异分析深入OpenCV源码会发现initUndistortRectifyMap()函数内部会根据输入的参数数量自动选择计算方式double k1 ((double*)distCoeffs.data)[0]; double k2 ((double*)distCoeffs.data)[1]; double p1 ((double*)distCoeffs.data)[2]; double p2 ((double*)distCoeffs.data)[3]; double k3 distCoeffs.cols distCoeffs.rows - 1 5 ? ((double*)distCoeffs.data)[4] : 0.; double k4 distCoeffs.cols distCoeffs.rows - 1 8 ? ((double*)distCoeffs.data)[5] : 0.; //...其他参数类似关键的计算部分double kr (1 ((k3*r2 k2)*r2 k1)*r2)/(1 ((k6*r2 k5)*r2 k4)*r2); double u fx*(x*kr p1*_2xy p2*(r2 2*x2)) u0; double v fy*(y*kr p1*(r2 2*y2) p2*_2xy) v0;当只有4个参数时k3-k6都为0公式就简化为十四讲中的形式。这就是为什么在处理普通相机时两种方法效果相当。6. 性能优化技巧在实际工程中去畸变往往是实时性要求很高的操作。这里分享几个优化经验预计算映射表initUndistortRectifyMap()的计算开销较大但映射表对于固定相机是不变的。可以在初始化时计算一次后续帧都复用这个映射表。使用CV_16SC2类型映射表有几种数据类型可选实测CV_16SC2在大多数硬件上速度最快。GPU加速对于高分辨率图像可以考虑使用CUDA版本的remap函数。ROI处理如果只关心图像某区域可以只计算该区域的映射减少计算量。我在处理4K鱼眼视频时通过这几种优化将处理速度从30ms/帧提升到了8ms/帧效果非常明显。7. 常见问题排查遇到过最头疼的问题是去畸变后图像出现黑边或者严重变形。经过多次踩坑总结出以下排查步骤检查参数顺序确认k1,k2,p1,p2的顺序是否正确验证相机内参特别是fx,fy,cx,cy的值是否合理尝试不同参数数量有时候标定工具输出的参数数量可能不符合预期检查图像尺寸确保size参数与实际图像尺寸一致验证畸变中心默认是图像中心但某些相机可能需要调整有一次项目中出现边缘校正不良的问题最后发现是标定时的棋盘格没有覆盖足够大的视场导致标定的畸变参数不准确。重新标定后就解决了。8. 不同场景下的选择建议根据相机类型和用途我的推荐方案是普通监控相机方法十四讲4参数法原因简单高效完全够用无人机航拍镜头方法OpenCV 5参数法原因广角镜头需要更好的边缘校正全景鱼眼相机方法OpenCV 8参数法原因必须使用完整模型才能处理强畸变实时SLAM系统方法预计算映射表CV_16SC2原因性能至关重要在实际部署时建议先用标定板获取准确的畸变参数然后做充分的测试验证。不同厂商的镜头特性可能差异很大最好能针对具体硬件调优参数。