ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenCV图像去畸变实战指南:原理、标定与参数调优

OpenCV图像去畸变实战指南:原理、标定与参数调优 做计算机视觉项目这些年我最深的体会之一就是OpenCV图像去畸变这件事看起来只是几个函数的事实际上坑比想象中多得多。第一次做相机标定时我拿到标定板拍了一堆图片跑完cv2.calibrateCamera拿到内参就直接调cv2.undistort结果画面边缘的直线依旧弯曲后来折腾了好几天才发现是畸变模型和参数调优都没搞清楚。这篇实战指南就是把我从原理到参数调优的完整过程整理出来包含可直接复现的Python代码、三种去畸变方法的效果对比以及实际项目中总结的避坑清单适合刚接触OpenCV的初学者也适合正在做相机标定、需要把去畸变效果做到产品级的开发者。1. 项目概述先搞清图像去畸变要解决什么问题1.1 畸变不修正后面全白做用手机对着一条直线拍张照片你会发现画面边缘的直线会有弯曲感尤其是广角镜头更明显。这不是对焦问题而是镜头的光学系统带来的几何畸变。在实际项目里畸变的影响非常直接工业视觉中待测工件的边缘坐标会测不准后续做尺寸测量就会偏差好几个像素AR场景中虚拟物体和实际画面叠加会对不齐做三维重建或机器人导航时像素坐标需要反算真实世界位置畸变不纠正后面的特征匹配、位姿估计都会把误差一步步放大。图像去畸变简单说就是把拍摄到的畸变图像重映射回“理想图像”让直线恢复笔直恢复像素坐标和真实世界之间的对应关系。但要强调一点去畸变不是万能的镜头模糊、色差这类光学缺陷不在它的处理范围内别指望一个undistort解决所有图像质量问题。OpenCV主要针对两类畸变做校正径向畸变和切向畸变。径向畸变由镜头透镜形状导致表现为直线向外凸桶形或向内凹枕形距离画面中心越远越明显切向畸变由镜头与感光芯片装配不完全平行导致表现为图像在某个方向上有拉伸倾斜感。这两类畸变都可以用多项式模型描述也是相机标定要估计的核心对象。1.2 为什么不能直接套用现成的OpenCV接口我经常在社区里看到有人问“能不能直接调cv2.undistort去畸变参数随便填”答案是绝对不能。因为去畸变需要两个关键输入相机内参矩阵和畸变系数而每一颗镜头的光学参数都不同同一型号不同批次也会有细微差异。更关键的是这两个参数和图像分辨率、对焦距离都有关系直接拿别人相机标定出来的参数套在自己的相机上去畸变之后图像大概率会更扭曲。所以完整的去畸变链路是先拍摄标定板照片用cv2.findChessboardCorners检测棋盘格角点再用cv2.calibrateCamera计算出内参和畸变系数最后调用undistort或者initUndistortRectifyMap加remap完成去畸变。后面所有代码都围绕这条链路展开只要走完一遍你就能拿到属于自己相机的一组可靠参数。2. 畸变原理拆解从针孔模型到OpenCV的参数含义2.1 针孔相机模型与内参矩阵要理解去畸变先得理解相机为什么会产生畸变。理想情况下相机成像可以简化为针孔模型——三维空间点通过光心投影到传感器平面上。这个模型对应的数学关系是相机坐标系下的一点 $X_c, Y_c, Z_c$ 先投影到归一化平面得到 $x X_c / Z_c$$y Y_c / Z_c$再经过缩放和平移变成像素坐标 $(u, v)$。用矩阵表示就是其中K就是内参矩阵fx和fy是焦距与像素尺寸的比值cx和cy是光心在像素坐标系中的位置。正常情况下图像中心应该就是光心但实际装配时会有偏移所以cx、cy通常不等于图像宽高的一半。这里想强调一个很容易踩的坑OpenCV里内参矩阵的坐标原点在图像左上角不是图像中心。很多人把cx、cy理解成图像中心坐标后面计算投影误差时怎么都对不上就是这个细节搞错了。2.2 径向畸变和切向畸变的数学表达实际镜头不是完美针孔模型畸变就体现在归一化坐标上。设理想归一化坐标为 $(x, y)$畸变后的归一化坐标为 $(x_{dist}, y_{dist})$。OpenCV采用Brown-Conrady模型公式如下径向畸变$$x_{dist} x \times (1 k_1 r^2 k_2 r^4 k_3 r^6)$$$$y_{dist} y \times (1 k_1 r^2 k_2 r^4 k_3 r^6)$$其中 $r^2 x^2 y^2$也就是点到主点的距离。k1、k2、k3是径向畸变系数大多数情况下k1贡献最大k2修正二次残差k3只在鱼眼镜头或强畸变镜头中才明显。切向畸变$$x_{dist} x 2 p_1 x y p_2 (r^2 2x^2)$$$$y_{dist} y p_1 (r^2 2y^2) 2 p_2 x y$$p1、p2是切向畸变系数由镜头与传感器平面之间微小的倾斜造成。最终把径向和切向畸变项叠加到原始归一化坐标上就得到实际的畸变坐标。这些系数在OpenCV里被放进一个向量distCoeffs中普通相机模型的顺序是 [k1, k2, p1, p2, k3]注意这个顺序很关键k1、k2在前p1、p2在中间k3在最后。如果按 k1、p1、k2、p2、k3 的顺序赋值畸变恢复出来会完全不对。2.3 OpenCV普通相机模型与鱼眼相机模型的差异OpenCV里有两个不兼容的畸变模型。普通相机模型就是上面讲的Brown-Conrady模型通过cv2.calibrateCamera标定畸变系数通常是4到5个参数即k1、k2、p1、p2、k3。鱼眼相机模型则要复杂得多通过cv2.fisheye.calibrate标定畸变系数是k1、k2、k3、k4四个参数它采用等距投影模型来近似大视场角镜头比如超过180度视场角的鱼眼镜头的投影特性。调用时要特别注意如果用普通相机的思路去处理鱼眼镜头拍出来的图即使能跑通去畸变后边缘区域也会出现严重的拉伸扭曲画面几乎不能用反之用鱼眼模型处理普通镜头参数求解会不稳定。我的建议是先搞清楚镜头的视场角。日常手机、监控摄像头、工业相机的视场角一般在60到90度以内用普通模型运动相机、倒车影像、全景相机这类明显广角的镜头优先尝试鱼眼模型。3. 环境准备与标定规范OpenCV安装、标定板选择与拍摄技巧3.1 为什么我推荐用OpenCV Python做标定图像去畸变的备选方案其实不少有OpenCV、MATLAB标定工具箱也有商业软件。我日常项目里大多数场景选OpenCV Python原因很实在迭代速度快改一个参数跑一遍脚本几秒钟就能看到结果社区资料丰富遇到问题搜一圈就能找到参考资料更关键的是后面要接人脸识别、目标检测、三维重建这些任务时OpenCV Python跟其他库的生态衔接很顺畅。如果你最终项目要部署到嵌入式设备或者移动端也不用担心Python代码白写。OpenCV C版本的API和Python版本几乎一一对应标定和去畸变的思路可以直接迁移。我一般先用Python把算法参数调试到位再翻译成C版本上线。3.2 OpenCV安装与版本避坑安装推荐直接装contrib版本pip install opencv-contrib-python这个包包含了主模块和扩展模块比如鱼眼镜头标定要用的cv2.fisheye模块就在里面。如果只安装了opencv-python调用cv2.fisheye会直接报AttributeError这是非常常见的新手问题。版本方面我个人建议装4.5.5以上版本新版本的findChessboardCornersSB等函数对低纹理图片的支持更好对棋盘格角点检测的鲁棒性也有明显提升。Python版本推荐3.8到3.11之间太老的Python版本在安装新版OpenCV时可能找不到匹配的wheel包。还有一个小坑如果项目里同时需要GUI显示建议用pip安装而不是系统包管理器因为系统包管理器的OpenCV版本通常比较老API和文档对不上会浪费不少时间。3.3 标定板规格与拍摄规范标定板一般用棋盘格或圆点阵列。棋盘格最常见因为角点检测成熟、稳定性高。建议使用10×7内角点规格的棋盘格也就是内部交叉点有70个最外层小方格数量是11×8。打印出来后贴在平整硬板上尺寸不要太小要在画面中占据足够比例。拍摄时有个关键规范标定板要在视野的不同位置、不同角度、不同距离出现。简单来说就是让它“动起来”——左右移动、上下移动、倾斜、旋转每个区域都要覆盖到。数量上10到20张足够但角度变化要足够大尤其是画面边缘位置的标定板图像一定要拍因为畸变的主要特征就集中在边缘。拍摄环境的光照要均匀避免标定板表面反光。反光会造成角点检测失败或检测偏差标定出来的参数自然不准。我一般选择自然光环境如果不行就垫一张哑光打印纸。4. 核心代码实战用OpenCV Python完成标定与去畸变4.1 标定全流程拆解整个标定过程可以拆成三步第一步读入标定板图像检测棋盘格内角点并做亚像素细化第二步把所有图像的角点坐标和对应的世界坐标以棋盘格平面建立坐标系z都等于0交给cv2.calibrateCamera第三步根据输出的内参、畸变系数和每张图的旋转平移向量先看标定误差再保存参数用于后续去畸变。一个容易忽略的点是标定使用的世界坐标只需要相对尺寸不需要实际物理尺寸因为单目相机标定解算出的尺度是不确定的。如果你只是做去畸变单位无所谓但如果后续要做三维重建或者单目测距就一定要在标定前量好棋盘格每个格的物理边长单位mm并在构建世界坐标时把格数乘以物理边长否则fx、fy不能用于像素坐标和毫米坐标的转换。4.2 相机标定脚本与输出解读下面给出我用于工业相机标定的脚本做了精简可以直接运行import cv2 import numpy as np import glob # 棋盘格内角点数量10列7行 CHECKERBOARD (10, 7) SUB_PIX_WIN (11, 11) # 亚像素角点终止条件 criteria (cv2.TERM_CRITERIA_EPS cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) # 世界坐标系中的棋盘格点坐标以格为单位z0 objp np.zeros((CHECKERBOARD[0] * CHECKERBOARD[1], 3), np.float32) objp[:, :2] np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2) objpoints [] # 世界坐标 imgpoints [] # 图像坐标 # 读入所有标定图像 images sorted(glob.glob(calib_imgs/*.jpg)) print(f找到 {len(images)} 张标定图像) for fname in images: img cv2.imread(fname) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 检测棋盘格角点 ret, corners cv2.findChessboardCorners(gray, CHECKERBOARD, None) if not ret: print(f未能检测到角点: {fname}) continue # 亚像素细化提升角点精度 corners_refined cv2.cornerSubPix(gray, corners, SUB_PIX_WIN, (-1, -1), criteria) objpoints.append(objp) imgpoints.append(corners_refined) # 可视化角点 vis cv2.drawChessboardCorners(img.copy(), CHECKERBOARD, corners_refined, ret) cv2.imshow(corners, vis) cv2.waitKey(200) cv2.destroyAllWindows() print(f成功标定的图像数量: {len(objpoints)}) if len(objpoints) 5: raise ValueError(有效标定图像太少请重新拍摄) # 相机标定 ret, mtx, dist, rvecs, tvecs cv2.calibrateCamera( objpoints, imgpoints, gray.shape[::-1], None, None ) print(f重投影误差 RMS: {ret:.4f}) print(f内参矩阵:\n{mtx}) print(f畸变系数 (k1, k2, p1, p2, k3):\n{dist.ravel()}) # 保存标定结果 np.savez(camera_calib.npz, mtxmtx, distdist, rmsret)运行后会看到类似这样的输出重投影误差 RMS: 0.2311 内参矩阵: [[1425.0087 0. 643.2241] [ 0. 1427.9643 381.0875] [ 0. 0. 1. ]] 畸变系数 (k1, k2, p1, p2, k3): [-0.3862 0.1440 -0.0008 -0.0003 -0.0345]RMS误差表示标定模型和实际成像之间的平均重投影偏差单位是像素。一般小于0.5像素就算不错小于0.2像素说明标定质量已经非常好。如果RMS明显大于1就需要检查角点检测是否正确、拍的图片是否清晰、角度覆盖是否充分。注意cv2.calibrateCamera返回的dist形状是(1, 5)或(1, 8)使用时直接传整个dist给去畸变函数即可不需要手动拆开。不要按k1、p1、k2、p2的顺序重排OpenCV内部函数都按内置顺序读取只有手动写公式计算时才需要按 [k1, k2, p1, p2, k3] 排好。4.3 三种去畸变方法undistort、remap和最佳内参矩阵拿到内参和畸变系数后去畸变有几种做法我按实际使用频率排一下。第一种直接调用cv2.undistort。代码最少适合快速验证效果import cv2 import numpy as np # 加载之前标定保存的参数 calib_data np.load(camera_calib.npz) mtx calib_data[mtx] dist calib_data[dist] img cv2.imread(raw.jpg) h, w img.shape[:2] # newcameramtx是对去畸变后图像重做的内参alpha控制裁剪比例 newcameramtx, roi cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), alpha0, (w, h)) dst cv2.undistort(img, mtx, dist, None, newcameramtx) # 裁剪掉变形产生的无效区域 x, y, roi_w, roi_h roi dst_crop dst[y:y roi_h, x:x roi_w] cv2.imwrite(undistort_alpha0.jpg, dst_crop)第二种initUndistortRectifyMap加remap。核心思想是提前算好像素映射表之后每帧图像只需要查表重采样非常适合实时视频流处理# 创建映射表 mapx, mapy cv2.initUndistortRectifyMap( mtx, dist, None, newcameramtx, (w, h), cv2.CV_32FC1 ) # 对每一帧做remap frame_undistorted cv2.remap(frame, mapx, mapy, cv2.INTER_LINEAR)第二种方法之所以效率高是因为标定是离线完成的mapx、mapy只需计算一次而remap只做重采样不涉及任何多项式运算。实测下来在1280×960分辨率下同一台笔记本用undistort单帧大约15到20毫秒用remap大约6到8毫秒实时性区别很明显具体数值受机器影响但remap基本稳胜。第三种如果想手动控制更多细节可以先计算映射表再自己写重采样逻辑OpenCV的remap支持多种插值方式和边界处理。工业项目里我一般用前两种就足够了。注意代码里的alpha参数它直接影响输出图像的范围。alpha0时OpenCV自动裁剪掉所有没有像素值的黑边区域输出图像尺寸可能小于原图alpha1时所有原始像素都保留但边缘会出现大量黑边。实际项目中我一般取0到1之间的值或者根据需求裁剪ROI。4.4 参数调优alpha、插值方式与ROI的权衡去畸变更像一次像素重投影不同参数组合下边缘区域的质量差异会很大。下面几个参数我几乎每次都要调。alpha值的选择很有讲究。如果只是做视觉测量物体通常靠近图像中心区域alpha0把边缘裁剪掉既能减少无效数据又能提高处理速度。如果做全景拼接、AR叠加这类需要尽可能保留原始视野的场景alpha1才能保留完整视场角但代价是边缘出现黑边。我的习惯是先alpha1跑一版看视野再alpha0跑一版看清晰度最后根据自己的需求折中。插值方式对去畸变图像质量的影响经常被忽视。默认的INTER_LINEAR在大多数场景够用但在图像边缘畸变比较大的地方线性插值容易出现锯齿。可以试试INTER_CUBIC或者INTER_LANCZOS4边缘细节会平滑一些代价是计算量变大。实时场景下如果CPU很紧张换INTER_NEAREST可以显著提速代价是边缘有块状感一般只在低分辨率监控类场景里用。ROI的取舍也很重要。前面代码里的roi变量是getOptimalNewCameraMatrix根据alpha自动计算出来的有效区域。使用remap时可以只对局部区域做重映射。比如图像尺寸很大而目标检测的区域集中在画面中央那就不需要对整帧图做remap只需要对包含目标的小图块做同样变换就行。不过要注意remap的map是全局的对小图块做时需要加上偏移量否则映射会偏移这个细节我放在后面问题章节详细说。5. 效果对比与方案选择不同参数、不同镜头的去畸变差异5.1 alpha取值对视野和边缘恢复程度的影响为了更直观地展示alpha的作用我在同样的镜头和标定参数下分别跑了alpha0、alpha0.5、alpha1三组图实际感受差异很明显。alpha值黑边情况有效视野边缘直线恢复度适用场景0无黑边自动裁剪最小最好只保留有效区域尺寸测量、OCR识别、工业检测0.5少量黑边或轻微裁剪中等较好通用项目兼顾视野与效果1边缘有明显黑边完整原始视野边缘拉伸明显AR叠加、全景拼接、SLAM拿墙面瓷砖缝来举例alpha0时画面边缘的瓷砖缝几乎完全笔直但四个角被裁掉视野变窄alpha1时所有原始像素都保留边缘能看到明显的黑色弧形区域原来畸变严重的墙角线虽然被修正了但拉伸过度让墙角线条看起来有些扭曲感。这个结论其实很好理解畸变越大的区域为了把它“拉直”重采样时被拉伸的比例就越大像素会被拉得越来越模糊。alpha0只保留畸变修正效果良好的中央区域自然最清晰。5.2 remap与undistort的耗时对比耗时方面我在三台不同配置的机器上大概测过一轮统一用1280×960、RGB三通道图像。结果整理如下方法单帧平均耗时i5-10210U单帧平均耗时树莓派4B特点cv2.undistort约 15~20 ms约 80~100 ms代码简单每次调用重复计算映射initUndistortRectifyMap remap约 6~8 ms约 35~45 ms映射表只算一次实时性好initUndistortRectifyMap remapINTER_NEAREST约 4~5 ms约 20~25 ms最快质量稍降有一定基础后你会发现undistort本质上就是initUndistortRectifyMap加remap的封装。OpenCV源码里cv2.undistort内部会先调用initUndistortRectifyMap生成映射表再执行remap。这就是为什么在实时视频处理里我们总是手动拆开用remap——省去每帧重复生成映射表的开销。精度方面两种方法在像素层面没有本质差异因为都是基于同一套映射关系做重采样。真正影响精度的是插值方式和你选择的alpha值。比如alpha1时边缘区域像素被拉伸多倍即便换更高阶插值清晰度依然不如alpha0裁剪后的效果因为信息量本身被重采样稀释了。5.3 普通镜头与鱼眼镜头的去畸变路径差异如果你的镜头视场角大于120度甚至达到180度以上普通相机模型就不够用了需要走OpenCV的fisheye模块流程和普通镜头有一点差异。标定阶段用的是cv2.fisheye.calibrate而不是cv2.calibrateCamera输入输出类似但dist系数只有4个参数顺序是k1、k2、k3、k4。去畸变阶段对应有cv2.fisheye.initUndistortRectifyMap和cv2.fisheye.undistortImage。这里有一个很多人忽略的坑鱼眼模型去畸变后画面边缘会极度拉伸大片区域被放大得很夸张。这时候不要死磕alpha可以尝试另一个思路——不追求全画面校正而只对感兴趣区域做校正或者结合透视变换来裁剪出一个合适的视野。在一些倒车影像项目中我见过有人把180度鱼眼图校正成普通视角效果还可以但视角损失很大本质上是用视野换清晰度。6. 常见问题排查与避坑技巧实录6.1 标定RMS误差过高怎么办如果你跑完标定发现RMS大于0.5甚至超过1先不要急着调算法。按我踩坑的经验依次排查这几个方向。第一检查有没有模糊图像。标定板抖动、对焦不准会导致角点亚像素定位不准。快速判断方法把检测到的角点画在图上肉眼看到角点位置明显偏出棋盘格交叉点那这张图就删除。第二检查标定板是否“躺平”。如果所有照片里标定板都几乎平行于图像平面没有明显的倾斜角度那么求解出来的内参在z方向上的约束会很弱RMS不一定高但后续用起来很容易出问题。解决方法就是重新采集一批有明显俯仰角、左右倾斜角的数据。第三检查角点数是否配置正确。findChessboardCorners里的CHECKERBOARD是内角点数不是格子总数。10×7代表内部交叉点有70个棋盘格最外层的小方格数量应该是11×8。数量写错轻则检测失败重则检出一半角点导致整体误差失控。排查顺序建议是这样先看有效图像数量够不够再看是否有模糊图像再看角度覆盖情况最后看代码里的规格是否写错。大部分RMS异常问题都出在前三项真正需要调整算法模型的情况很少。6.2 去畸变后边缘出现黑边和拉伸怎么处理拿到新相机后我第一次做去畸变就发现画面四周有一圈黑色弧形区域当时以为代码写错了。后来才明白这是去畸变过程的正常现象——畸变图里的边缘像素被重新映射到更远位置而新位置在原图中没有对应像素自然就是黑色。解决方案就三个一是alpha设为0让OpenCV自动裁剪二是自己设定ROI范围裁剪三是用反向映射填充的思路先算好映射表再对非法像素做邻域插值填充。前两种最常用第三种适合需要把画面填满的场景比如全景图拼接。裁剪时注意别把ROI算错x、y、宽、高都从getOptimalNewCameraMatrix的返回值里拿直接用就行。还有一种边缘拉伸的处理技巧如果拉伸只出现在图像最外圈可以适当放大newcameramtx的fx、fy让校正后的图像做轻微缩放边缘拉伸感会降低很多代价是整体视野略微缩小。这个方法在鱼眼镜头校正时尤其有用。6.3 remap局部区域时的坐标偏移陷阱这个坑我记忆很深。某次项目里为了省事我只想对画面中央一个320×240的区域做去畸变就直接拿了整帧图对应的mapx、mapy去切小图然后对小图做remap结果输出的图像中心和预期完全对不上物体位置整体偏移。原因很简单mapx、mapy是相对于全图坐标的映射切出来的320×240小图它的像素坐标不再对应全图位置。要正确处理必须把映射表也裁剪并减去小图左上角的偏移量x0, y0 400, 300 # 小图在全图中的左上角 patch_w, patch_h 320, 240 mapx_patch mapx[y0:y0 patch_h, x0:x0 patch_w].copy() mapy_patch mapy[y0:y0 patch_h, x0:x0 patch_w].copy() mapx_patch - x0 mapy_patch - y0 patch_undist cv2.remap( frame[y0:y0 patch_h, x0:x0 patch_w], mapx_patch, mapy_patch, cv2.INTER_LINEAR )这里关键是mapx_patch、mapy_patch要减去x0、y0因为remap输入的小图坐标是以小图左上角为原点的。这个细节不处理排查一整天都找不到问题在哪。6.4 鱼眼模型标定失败的原因排查鱼眼标定比普通相机标定更敏感。常见问题有几个其一使用的标定板过小导致检测到的角点数量不够多不足以约束畸变参数其二标定板照片总数不够鱼眼模型的自由度更多10到20张往往不够我一般采集25到40张其三鱼眼镜头视场角很大标定板要更靠近镜头、覆盖到边缘区域否则边缘畸变模型根本没有足够数据去拟合。如果鱼眼标定求解一直不收敛可以试试组合不同的flags参数比如cv2.fisheye.CALIB_RECOMPUTE_EXTRINSIC和cv2.fisheye.CALIB_CHECK_COND。多数情况下重新采集一组覆盖范围更广的图片比调参更有效。6.5 角点检测不稳定的处理技巧新版OpenCV提供了findChessboardCornersSB函数对低曝光、模糊和反光情况下的棋盘格角点检测鲁棒性提升很多。如果你的环境无法保证标定板图像完美优先试试这个函数。还有一个小技巧拍摄前可以微调相机曝光和增益让棋盘格的黑色格子不要死黑、白色格子不要过曝。标定板的打印品质也很重要用哑光纸、激光打印别用反光的铜版纸。另外如果棋盘格角点总是检测不到可以先降采样图片再检测检测到角点后把坐标乘回放大倍数还原这样对模糊图像的容忍度会有提升。7. 实操经验总结先跑通流程再逐个调参最后聊点实际项目里的体会。我第一次做去畸变时最大的失误是跳过了“先看角点检测结果”这一步直接一口气跑到标定完成结果RMS是2.7我还想是不是OpenCV标定算法有问题。后来把角点画出来才发现有些图片上角点完全画错了位置是模糊照片混进去了。所以我的习惯是每拍一组标定图先跑一遍角点检测并保存可视化结果人工快速扫一遍再进入正式标定。拿到一套还不错的标定参数后也不要急着嵌入主流程。先用一张典型的实拍图分别用alpha0、alpha0.5、alpha1三组参数跑一遍肉眼对比边缘直线恢复程度和画面视野范围再决定产品里用哪个参数。这个验证过程只需要几分钟却能避免后期反复改。如果项目要求实时处理视频流一定要提前把mapx、mapy算好并持久化到本地文件每次启动程序直接加载而不是重新计算。我习惯用np.savez保存映射表加载后用astype(np.float32)确保内存布局正确用不对容易出现类型转换bug。去畸变看起来只是OpenCV里几个函数的活儿但牵扯到的原理和工程细节并不少。把原理吃透、参数逐项调明白后面再做三维重建、视觉测量这类对精度要求高的任务就能省下很多返工时间。希望你也能一次跑通、少踩坑。
返回列表