ARTICLE DETAIL

资讯详情

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

相机标定与图像校正助手:OpenCV+Qt实现全流程指南

相机标定与图像校正助手:OpenCV+Qt实现全流程指南 简介面向C与OpenCV学习者的相机标定及图像校正助手基于VSOpenCVQt实现可交互的界面化标定与畸变校正流程特别适合课程设计大作业场景。压缩包共一百四十七个文件内含标定图像与畸变样张八十一张bmp/jpg图片以及cpp/h源码、Qt界面ui与qrc资源、Visual Studio工程、编译中间文件和可直接运行的程序整体约36.32MB。软件针对多种异常跳出条件做了处理鲁棒性强运行后能完成相机参数解算并查看校正输出覆盖图像读取、标定计算、畸变校正与结果展示等环节。配套博客提供原理讲解与使用说明购买后可联系作者答疑也便于在源码基础上二次开发或整理成课设报告。目前已有两千零八十六人学习下载值得计算机视觉方向初学者参考。1. 相机标定图像校正助手为什么视觉人手里都要留一个这样的桌面工具有同行问我相机标定和图像校正助手这种工具OpenCV 官方例程里有现成的calibrateCamera为什么还要用 VSOpenCVQt 再包一层我的回答是官方例程只给你一个黑匣子似的控制台窗口而实际生产里需要的是“标定→校样→存参数→以后随时调出来用”这一整条闭环。这个标题做的就是把这两件事接起来前一半解决“相机内参和畸变系数是多少”后一半解决“怎么让图像立刻变直”。适合做视觉测量、三维重建和机器人抓取定位的人尤其适合手里有一堆摄像头、每次换镜头都要重新标定内参的现场工程师。2. 相机标定的数学模型内参矩阵、畸变系数与标定板选择依据2.1 针孔模型与内参矩阵fx、fy 和 cx、cy 到底在描述什么一个像素在图像上的位置本质上是三维空间点经过光心投影到成像平面再经过像素采样得到的。针孔模型把这条链路压缩成一个 3×3 内参矩阵 KK [fx 0 cx 0 fy cy 0 0 1]fx、fy 是焦距换算到像素单位的数值。如果感光元件的像元尺寸是正方形fx 和 fy 应该很接近但不完全相等因为 CMOS 的装配误差和像素时钟采样都会引入微小差异。cx、cy 是主点即光轴与成像平面的交点理论上应该在图像正中心实际上会偏几个到几十个像素。这个偏差如果不校正做测距时会产生系统性偏移。配合内参的还有每张标定图独立的外参——旋转矩阵 R 和平移向量 t。图像校正助手只需要内参和畸变但calibrateCamera在计算内参时必须同时估计外参没有这些外参约束内参方程解不出来。所以后面代码里rvecs、tvecs必须接住不能省。这里要提一个 MATLAB 相机标定工具箱的对比。很多习惯用 MATLAB Camera Calibrator 导出参数的人转到 OpenCV 时发现图像校正出来是弯的原因有两个畸变系数顺序不同以及部分导出脚本把主点顺序搞混。所以我在助手实现里只认自己代码存储的 XML 格式参数外部导入必须做格式校验。标定完成后这套 K 和 D 最直接的消费方有两个一个是图像校正另一个是solvePnP位姿估计。后者只需要把棋盘格的三维点与二维点对应关系传给solvePnP内参矩阵直接复用标定结果不需要重新标定。2.2 畸变模型径向畸变与切向畸变对图像校正的影响镜头畸变主要分两类。径向畸变来自透镜曲面形状表现为直线向中心弯曲桶形畸变或向外弯枕形畸变用一个多项式近似x_distorted x * (1 k1 * r^2 k2 * r^4 k3 * r^6) y_distorted y * (1 k1 * r^2 k2 * r^4 k3 * r^6)其中 r 是像素点到主点的距离。切向畸变来自镜头与感光元件不平行公式里引入 p1、p2 两个参数。OpenCV 的畸变系数向量默认顺序是 (k1, k2, p1, p2, k3)注意不是 (k1, p1, k2, p2, k3)新手最容易在这栽跟头。k3 要不要参与标定是个值得讨论的问题。对普通手机镜头或工业镜头k3 值本身很小参与标定反而可能和 k1、k2 产生耦合让参数不稳定。常见做法是标定时先用完整 5 参数看重投影误差如果在 0.3 像素以内就不动它如果误差压不下去再考虑是否固定 k3。calibrateCamera支持通过 flags 组合控制哪些参数自由、哪些固定比如CALIB_FIX_K3就是把三阶径向畸变钉死在 0。这是调参里最容易被忽略的自由度。2.3 标定板、角点数量与图像姿态决定标定上限的几张表棋盘格是默认标定板因为角点提取稳定、制作成本低。但 patternSize 的坑很大一个打印出来 10 列 7 行的黑白网格图内角点是 9×6不是 10×7。findChessboardCorners返回的是棋盘格内部交点外边界的格子交点不算。填错这个参数角点检测要么直接失败要么在人眼看来都正常但坐标偏一格。标定板最好是硬质平面。打印到普通纸上再贴到玻璃或铝板上因为弯曲的标定板会把曲面误差带进内参。纸张受潮、边缘翘起都会让角点亚像素坐标偏移最后表现在重投影误差上就是压不进去。需要多少张图我说一个实际标准1525 张。低于 10 张内参和外参的耦合度太高标出来的主点会随图像选择漂移超过 30 张收益递减而且某几张模糊图的角点反而会拉低整体精度。图像的姿态要覆盖整个画面——中心、四个角、上下左右边缘标定板平面与相机光轴夹角在 15° 到 30° 之间变化。全部平放在正前方、只做小角度旋转的图数学上退化成同一组约束数量再多也没用。项目建议值说明标定图像数量1525 张少于 10 张约束不足多于 30 张收益递减棋盘格内角点9×6 或 12×9角点越多每张图的约束越强边距留白标定板外圈留 10mm 白边防止角点检测到纸张边缘伪角点拍摄姿态中心 1 张 四角 4 张 多角度倾斜覆盖视野避免共面退化解光照均匀漫反射避免反光反光会让 cornerSubPix 收敛偏移从这个表能看出来标定质量首先由采集决定标定算法只是把采集的信息提取出来。很多人以为代码写对了就能标准实际上多一半的翻车现场是图像采集没按这个表来细节留到第五章展开。3. VSOpenCVQt工程搭建环境配置与最小标定代码跑通3.1 版本搭配VS、OpenCV 与 Qt 怎么选先澄清一个容易找错门的事标题里的 VS 是 Visual Studio不是 VS Code。不少新手用 VS Code 配好了 OpenCV然后去跑 Qt 项目最后卡在 MSBuild 和 CMake 的选择上。这个项目按 Visual Studio 工程体系来做插件用 Qt VS Tools编译走 MSBuild省事很多。版本搭配有一个我长期使用的组合覆盖绝大多数 Windows 下的相机标定和图像处理需求组件建议版本说明Visual Studio2019 或 2022工具集 v142 / v143兼容 vc15 预编译库OpenCV4.5 或 4.8官方 Windows 预编译包自带头文件、lib、dllQt5.15.2 msvc2019_64开源版最后稳定的 MSVC 预编译包Qt VS Tools 支持成熟构建方式MSBuild不需要手动写 CMakeLists.txt为什么强调 Qt 5.15.2 而不是 Qt 6因为 Qt 6 推荐 CMake 构建和 VS 的 MSBuild 集成没有 5.15 那么顺滑而且大量现成的 OpenCV 示例还是按 Qt 5 写的。如果你已经装了 Qt 6也能跑但要把信号槽语法和模块名重新过一遍新手不建议从 Qt 6 起步。3.2 工程属性配置包含目录、附加依赖项与 Debug/Release 的对应关系新建一个 Qt Widgets Application 项目后打开项目属性有四样东西必须配齐。我给出一份可抄的配置清单VC 目录 - 包含目录: D:\opencv\build\include D:\Qt\5.15.2\msvc2019_64\include VC 目录 - 库目录: D:\opencv\build\x64\vc15\lib D:\Qt\5.15.2\msvc2019_64\lib 链接器 - 附加依赖项 (Debug): opencv_world4xxd.lib Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib 链接器 - 附加依赖项 (Release): opencv_world4xx.lib Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib这里的4xx按你实际下载的 OpenCV 版本写比如 4.8 就写opencv_world480d.lib。Debug 和 Release 必须分开配OpenCV 的 debug 库自带 d 后缀混用会在链接期报出一堆无法解析的外部符号或者运行期直接崩。还有一个很多人忽略的点C/C - 代码生成 - 运行库Debug 用MDdRelease 用MD。Qt 的预编译库是用动态运行时编的如果你开了静态链接或改成MTd轻则链接警告重则出现cannot mix incompatible Qt library这类运行时崩溃。这是 VS 下 Qt 项目最经典的坑后面避坑章专门说。配完之后记得把D:\opencv\build\x64\vc15\bin和D:\Qt\5.15.2\msvc2019_64\bin加进系统 PATH或者拷贝到 exe 同目录否则程序启动时报找不到 DLL。3.3 最小标定程序从 findChessboardCorners 到 calibrateCamera工程能跑起来之后先写一个不依赖界面的控制台版标定验证相机内参标定主链路通不通。这个最小程序是后面所有功能的地基。#include opencv2/opencv.hpp #include iostream #include vector int main() { const cv::Size patternSize(9, 6); // 内角点数量列 x 行不是格子数 const float squareSize 24.0f; // 棋盘格单个格子边长单位 mm std::vectorcv::String images; cv::glob(calib/*.jpg, images, false); std::vectorstd::vectorcv::Point3f objectPoints; std::vectorstd::vectorcv::Point2f imagePoints; cv::Size imageSize; for (const auto path : images) { cv::Mat img cv::imread(path); cv::Mat gray; cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY); imageSize img.size(); std::vectorcv::Point2f corners; bool ok cv::findChessboardCorners(gray, patternSize, corners, cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_NORMALIZE_IMAGE); if (!ok) { std::cerr 角点检测失败: path std::endl; continue; } // 亚像素精化把角点坐标从整数像素推到亚像素级 cv::cornerSubPix(gray, corners, cv::Size(5, 5), cv::Size(-1, -1), cv::TermCriteria(cv::TermCriteria::EPS cv::TermCriteria::COUNT, 30, 0.01)); // 每张图对应同一组三维点z 坐标固定为 0边长用真实毫米值 std::vectorcv::Point3f obj; for (int r 0; r patternSize.height; r) for (int c 0; c patternSize.width; c) obj.push_back(cv::Point3f(c * squareSize, r * squareSize, 0.0f)); objectPoints.push_back(obj); imagePoints.push_back(corners); } cv::Mat K, D; std::vectorcv::Mat rvecs, tvecs; double rms cv::calibrateCamera(objectPoints, imagePoints, imageSize, K, D, rvecs, tvecs); std::cout RMS rms std::endl; std::cout K K std::endl; std::cout D D std::endl; return 0; }这段代码做了几件事用cv::glob把 calib 目录下的 jpg 文件一次性加载然后逐张做角点检测CALIB_CB_ADAPTIVE_THRESH让算法在光照不均匀时改用自适应阈值CALIB_CB_NORMALIZE_IMAGE在检测前做图像归一化这两个 flag 对手机拍的标定图几乎必须开。cornerSubPix的窗口设成 5×5迭代 30 次精度 0.01 像素太小找不到邻域太大把细节抹掉。注意squareSize我写的是真实毫米值。如果只做畸变校正不求绝对尺度把它设成 1.0 问题也不大但后面如果想用 fx 做实际距离测量就必须给真实尺寸否则换算到毫米时乘出来的比例全是错的。calibrateCamera返回的 RMS 是重投影误差单位是像素判断标准后面单独讲。控制台打印出来的 K 和 D 会被后面 Qt 界面读取这一步先确认数值不是极端值比如 fx 不可能小于图像宽度的一半cx 不会跑到几千以外。4. 图像校正助手的Qt界面实现Mat转QImage、校正映射与参数存取4.1 界面骨架用 Qt Designer 画出来的五个区域和信号槽助手类界面不需要花哨核心是把操作路径缩短。我一般用 Qt Designer 画一个主窗口布局分五块左上角原图显示QLabel右上角校正预览QLabel中间一列参数表fx、fy、cx、cy、k1、k2、p1、p2、k3、RMS下方一排按钮——打开图像、检测角点、运行标定、保存参数、加载参数、校正当前图、启动实时校正。按钮对应的槽函数在 Qt 5 里用connect(ui-btnOpen, QPushButton::clicked, this, MainWindow::onOpenImage)连接逻辑清晰。真正需要写代码的部分是图像读取和显示以及调用 OpenCV 算法链。界面本身不用写太多东西Qt Designer 拖好控件命名规范一点后面就顺了。打开图像槽函数里有一个核心问题OpenCV 读进来的是cv::MatQt 显示需要QImage。这个转换不处理好出来的图要么颜色通道反了变成红蓝互换要么显示花屏。4.2 cv::Mat 与 QImage 的转换避开内存不连续和通道乱序OpenCV 的Mat默认是 BGR 三通道Qt 的QImage常见格式是 RGB888 和 ARGB32。直接cv::cvtColor(mat, mat, cv::COLOR_BGR2RGB)之后构造 QImage 是常见做法但很多人在这一步忘了处理mat.step。如果图像的 ROI 是子矩阵行的字节数不等于 cols×channels必须把bytesPerLine参数传进去。QImage MatToQImage(const cv::Mat mat) { switch (mat.type()) { case CV_8UC3: { QImage img(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888); return img.copy(); } case CV_8UC4: { QImage img(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32); return img.copy(); } case CV_8UC1: { QImage img(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8); return img.copy(); } default: { // 16位或浮点图像先归一化到8位再递归转换 cv::Mat temp; double minVal, maxVal; cv::minMaxLoc(mat, minVal, maxVal); mat.convertTo(temp, CV_8U, 255.0 / (maxVal - minVal)); return MatToQImage(temp); } } }这个函数里最关键的是mat.step作为bytesPerLine传入 QImage 构造函数保证子矩阵和 ROI 图像不花屏。其次是用.copy()返回新 QImage因为QImage构造时只是引用了Mat的数据指针如果Mat在函数结束后被释放界面上显示的图像就会变成随机内存垃圾。在默认分支里16 位深度和浮点图像的minMaxLocconvertTo映射是保证不同深度都能显示的处理路径。实际使用中相机标定的中间结果比如视差图、深度图都会走到这里。4.3 校正核心逻辑initUndistortRectifyMap 与 remap 的组合用法图像校正的地基函数是remap但新手常用的是cv::undistort。区别在于undistort每次调用内部都会重新计算映射表实时视频流里每帧都算一遍映射CPU 消耗大正确做法是标定后先算一次映射表然后视频循环里直接查表重映射。cv::Mat newK cv::getOptimalNewCameraMatrix( K, D, imageSize, 0.0, imageSize); cv::Mat map1, map2; cv::initUndistortRectifyMap( K, D, cv::Mat(), newK, imageSize, CV_32FC1, map1, map2); // 静态图校正 cv::Mat corrected; cv::remap(distorted, corrected, map1, map2, cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0)); // 视频流循环里复用 map1、map2每帧只执行 remap这里有个关键参数getOptimalNewCameraMatrix的 alpha。alpha 取 0 时返回的新内参矩阵会把校正后图像中所有无效黑色边缘裁掉视野损失一部分alpha 取 1 时保留原始图像所有像素但图像四周会出现大片黑色无效区。对测量类项目我通常取 0.5 左右视野和裁剪平衡后续手动裁剪 ROI 也方便。initUndistortRectifyMap的映射类型我用CV_32FC1这是单精度浮点映射比CV_16SC2精度高。虽然浮点映射内存占用大一倍但校正后的边缘细节更稳定。如果是在嵌入式设备上跑实时流再换回CV_16SC2也不迟。静态图校正走一次remap视频流校正走循环remap这两条路径在助手界面上用一个枚举变量区分。实时预览我一般不开因为工业相机采集线程和 UI 刷新线程一旦共用同一个 Mat会出现数据竞争界面卡顿。4.4 参数存档用 FileStorage 把相机矩阵和畸变系数存成 XML标定参数不能每次关程序都丢必须落盘。OpenCV 自带的FileStorage是最省事的方案读写直接是Mat类型不需要自己做字符串解析。// 保存标定结果 cv::FileStorage fs(camera.xml, cv::FileStorage::WRITE); fs imageSize imageSize; fs cameraMatrix K; fs distCoeffs D; fs rms rms; fs.release(); // 加载标定结果 cv::FileStorage fr(camera.xml, cv::FileStorage::READ); if (!fr.isOpened()) { // 找不到参数文件时提示重新标定 return false; } fr[cameraMatrix] K; fr[distCoeffs] D; fr.release();保存格式用 XML 还是 YAML 取决于个人习惯。XML 在 Windows 下可以用文本编辑器打开检查YAML 更紧凑JSON 也能写但老版本 OpenCV 支持不稳。我用 XML 的原因是方便和 MATLAB 导出的参数做人工比对。参数文件里必须记录imageSize。很多人标定完换一个分辨率用同一份内参结果校正后图像比例失调原因就是内参矩阵里的 fx、fy 和 cx、cy 全都和分辨率强相关。加载参数后第一件事就校验当前图像尺寸和imageSize是否一致不一致直接打警告不让用户稀里糊涂用错参数。5. 相机标定与图像校正避坑清单cannot mix Qt 版本冲突、角点检测失败与校正翻车现场5.1 启动崩溃cannot mix incompatible Qt library 与 Qt 平台插件缺失现象程序编译通过双击运行时弹窗报fatal: cannot mix incompatible Qt library (version 0x50601) with this library或者命令行出现qt.qpa.plugin: could not find the Qt platform plugin windows。原因前者是 Qt 库版本混用。最常见的是 Debug 配置里链接了不带 d 后缀的 Qt 库或者 OpenCV 库用opencv_world480d.lib编译出的程序链接了非 debug 版 Qt 库导致 Qt 内部版本字符串和加载库的版本对不上。后者是 Qt 的 platforms 插件目录找不到。程序运行时需要platforms/qwindows.dll这个文件在 Qt 安装目录的plugins下编译器不会自动把它复制到 exe 目录。如果 PATH 里没有 Qt 的 bin 目录插件加载就失败。解决先检查配置表Debug 全用带 d 的库Release 全用不带 d 的库运行库统一/MDd和/MD。然后确认QTDIR环境变量指向D:\Qt\5.15.2\msvc2019_64或者直接在项目属性里把$(QTDIR)\plugins加进 PATH。最后在main函数开头设置qputenv(QT_QPA_PLATFORM_PLUGIN_PATH, D:/Qt/5.15.2/msvc2019_64/plugins/platforms);这个错误十有八九是环境变量和库版本混搭造成的不用怀疑 OpenCV 和 Qt 本身不兼容。5.2 角点检测失败棋盘格明明清晰findChessboardCorners 却返回 false现象拍摄的棋盘格图像从肉眼看不反光、不缺角但findChessboardCorners返回 false或者偶尔检测成功、偶尔失败用同一组图像第二次跑结果不一样。原因一是 patternSize 填错。比如 10×7 的格子内角点是 9×6填成 10×7 时算法在行列方向多找一个角点导致边缘不闭合。二是图像里有反光白色格子的高光区域在灰度图上呈白色块自适应阈值把格子边界吃掉了。三是CALIB_CB_FAST_CHECKflag 在某些低分辨率图像上会因为快速预扫描不通过而主动放弃检测这个 flag 本来是用来提速的但牺牲了检出率。解决先确认 patternSize 是内角点数不是格子数。然后用CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE关掉FAST_CHECK试一次。如果图像是手机拍的先转灰度再检测。我把这个检测写成了带重试的函数第一次失败后降低阈值、关掉FAST_CHECK再跑一次成功率从 80% 提到 99%。5.3 校正后图像怪怪的棋盘格尺寸单位与重投影误差的双重陷阱现象标定程序 RMS 显示只有 0.2 像素看起来精度很高但校正后的图像边缘直线还是弯的或者把照片放大了看有四角拉伸变形。原因RMS 只衡量角点在标定板平面上的重投影误差它反映的是“标定模型和用来标定的图像拟合得好不好”不代表“校正到真实世界准不准”。如果标定图像全部集中在画面中心、角度变化小RMS 可能很低但主点和畸变系数被外参不充分约束拖累校正后视野边缘的直线弯曲依旧。另一个原因是棋盘格尺寸传了归一化值校正本身不依赖真实尺寸但如果你用标定出来的 fx、fy 做距离换算量出来的值全部差一个比例系数。解决增加覆盖四角和大角度倾斜的标定图重标定后再看 RMS。RMS 低于 0.3 像素只是基础门槛关键看校正后画面边缘的直线是不是直的这个验证方法最后一章详细讲。棋盘格尺寸尽量用游标卡尺量一下再填进代码毫米误差哪怕只有 1mm对 f1000px 级别的相机来说影响不大但对于做毫米级测量的系统就必须严谨。5.4 边缘黑边与视野丢失alpha 与 getOptimalNewCameraMatrix 的参数玄学现象校正后的图像四角出现大块黑色或者图像内容被裁剪掉一圈看起来视野明显变小。原因没有调用getOptimalNewCameraMatrix直接用原始 K 传给initUndistortRectifyMap。原始 K 假设的是理想无畸变成像平面而畸变校正后有效像素区域是弯曲的原始内参会把大量无效像素映射到视野外围黑边就是这么来的。反过来alpha 取 0 时getOptimalNewCameraMatrix会把所有黑边裁掉但视野损失也最大如果镜头本身视场角不够宽裁剪后目标容易出画。解决alpha 参数不要走极端。静态图像测量用 0.5实时视频流用 0.8 以上既保留足够视野又避免黑边干扰。如果后续还要接solvePnP测位姿记得把getOptimalNewCameraMatrix返回的newK存下来因为后续所有像素坐标换算都要用它原始 K 只用于标定和查看。5.5 换分辨率后内参失效标定参数不是一次管终身的现象今天用 1920×1080 标定的参数明天相机分辨率切成 1280×720加载 XML 后校正的图像比例不对测距结果偏得离谱。原因fx、fy、cx、cy 全部是基于像素坐标的分辨率一变主点和等效焦距都要按比例缩放。很多相机驱动允许切分辨率但内参矩阵不会自动跟着变。解决在参数文件里记录imageSize加载时校验。如果分辨率不一致提供两种处理一种是用比例缩放内参公式是fx_new fx * new_width / old_width但这种做法只在裁剪中心区域时近似成立另一种是直接重新标定。我在助手界面上做了禁止按钮逻辑参数文件与当前图像尺寸不一致时校正按钮直接置灰强制用户重新标定。别嫌麻烦换分辨率是最容易让标定成果报废的操作没有后悔药。6. 用重投影误差和直线校验标定质量三个实用技巧6.1 逐图重投影误差不要只看均值异常图才是拉低精度的元凶calibrateCamera返回的 RMS 是所有图像误差的均值但它掩盖了一个事实某一张图角点检测偏了其余十几张都正常RMS 可能只从 0.15 涨到 0.2表面上看还能用实际上那张异常图正在扭曲整组内参。我习惯标定后把每张图的逐图误差打印出来for (size_t i 0; i objectPoints.size(); i) { std::vectorcv::Point2f reprojected; cv::projectPoints(objectPoints[i], rvecs[i], tvecs[i], K, D, reprojected); double err cv::norm(imagePoints[i], reprojected, cv::NORM_L2) / (double)imagePoints[i].size(); std::cout image[ i ] per-view error: err std::endl; }这里的err是 L2 范数除以角点总数得到的是平均欧氏距离偏差单位像素。如果某张图的误差超过其他图的 3 倍以上直接剔除后重新标定通常 RMS 能再降一个档次。6.2 直线校验法在真实场景里判断校正是否打直算法指标再漂亮不如拿一张真实场景图看直线直不直。找一面贴了瓷砖的墙或笔直的门框拍照后走一遍校正流程然后拉一条直线对比边缘。量化做法是用 Canny 提取边缘再用HoughLinesP找长线段计算线段各点到拟合直线的最大偏移量。偏移量小于 2 个像素就说明校正到位大于 5 个像素基本可以认定畸变系数不准或者用的是旧分辨率参数。这个验证对鱼眼镜头和广角镜头尤其重要因为这类镜头的径向畸变在画面边缘最严重中心区域即使参数错一点也看不出来。6.3 鱼眼镜头该换模型了什么时候切换到 cv::fisheye 标定流程普通针孔模型的畸变多项式对视角超过 100° 的超广角镜头拟合能力有限重投影误差很难压到 0.5 像素以下。如果标定图像里棋盘格在画面边缘时明显成弧形说明径向畸变已经超出多项式模型的表达能力。这时要换cv::fisheye::calibrate和cv::fisheye::initUndistortRectifyMap。鱼眼模型只需要 4 个畸变系数 k1、k2、k3、k4但对大畸变的拟合效果比标准模型好得多。判断标准很朴素标准模型 RMS 压不进 0.5 像素且畸变明显是径向主导时直接切到 fisheye 流程不要再跟标准模型较劲。我做标定有个习惯每次标定完把原始标定图像、棋盘格尺寸、内参 XML、逐图误差按日期归档成独立文件夹文件名里带上相机型号。因为同一颗镜头在不同焦距下内参完全不同没有归档习惯的人三个月后回来看旧参数根本想不起来这是哪颗镜头、哪个分辨率下标的只能重新拍一遍。下次你把相机架好、棋盘格举起来的时候会感谢这个习惯的。希望帮到你。本文还有配套的精品资源点击获取
返回列表