标定前必须确认棋盘格完整无反光、采集15–20张多角度图像、图像分辨率与使用场景一致、相机固定不动;OpenCV的calibrateCamera对输入数据质量极度敏感,绝大多数单目标定失败源于图像不达标而非代码问题。

标定前必须确认的硬件与图像条件
单目标定失败绝大多数源于输入数据不达标,不是代码问题。OpenCV 的 calibrateCamera 对图像质量极其敏感,必须满足:
• 棋盘格图案完整、无反光、无遮挡,且在每张图中至少可见 10×7 个内角点(OpenCV 默认要求)
• 至少采集 15–20 张不同角度、不同距离的图像(倾斜、旋转、远近都要覆盖)
• 图像分辨率需与后续使用场景一致(标定参数和畸变模型与分辨率强绑定)
• 相机需固定不动,仅移动标定板——手抖或相机微移会导致 calibrateCamera 返回低置信度的 ret 值(通常应 > 0.1,低于 0.05 基本不可用)
cv::calibrateCamera 的关键参数与常见报错
调用 calibrateCamera 时最常踩的坑是传错参数类型或顺序。它要求:
• objectPoints:vector
• imagePoints:vectorfindChessboardCorners + cornerSubPix 精确化)
• imageSize:Size(width, height),必须与输入图像的 Mat.cols/Mat.rows 完全一致
• cameraMatrix 和 distCoeffs:输出参数,需预先声明为 Mat(非 cv::Mat 别名),且初始化为空(Mat cameraMatrix, distCoeffs;)
• 常见错误:CV_StsAssert 报错多因 objectPoints 和 imagePoints 数量不匹配;Assertion failed (nimages > 0) 是传了空 vector;返回 ret == 0 表示未收敛,应检查角点检测是否全失败(可用 drawChessboardCorners 可视化验证)
矫正畸变时 cv::undistort 与 initUndistortRectifyMap 的取舍
undistort 简单直接,适合单帧实时矫正(如调试显示),但每次调用都重新计算映射,开销大;initUndistortRectifyMap + remap 分两步:先预生成映射表(map1, map2),再用 remap 快速查表。实际部署必须用后者:
• initUndistortRectifyMap 的 newCameraMatrix 参数若传 Mat::eye(3,3,CV_64F) 或空 Mat,会自动计算最优校正后内参(推荐);若传原 cameraMatrix,则只去畸变、不调整视场
• 注意 map1 类型必须为 CV_32FC1,map2 为 CV_32FC1,否则 remap 报错 Unsupported depth of map
• 若矫正后图像边缘严重裁剪,说明 newCameraMatrix 过于保守,可设 alpha=1.0(保留全部原始像素,允许黑边):getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1.0, imageSize, &validROI)
标定结果保存与跨平台复用注意事项
标定参数不能硬编码进程序。OpenCV 推荐用 XML/YAML 保存:
• 用 FileStorage fs("calib.yml", FileStorage::WRITE) 写入 cameraMatrix、distCoeffs、imageSize
• 读取时务必检查 fs.isOpened() 和各 Mat 是否非空,YAML 文件路径错误或格式损坏会导致 distCoeffs 读成单列 0 矩阵,后续 undistort 完全失效但不报错
• 不同 OpenCV 版本对 distCoeffs 的系数顺序兼容(k1,k2,p1,p2,k3),但 4.8+ 新增的 k4/k5/k6 需显式指定 flags(如 CALIB_RATIONAL_MODEL),旧版本读取含 k4 的文件会静默截断
• 最容易被忽略的是:同一台相机换 USB 线、换主机 USB 端口、甚至换系统重启后,有时采集的图像尺寸会从 1920×1080 变成 1920×1082(驱动微小差异),此时沿用旧标定参数会导致严重畸变残留——必须用当前实际 Mat.size() 重新标定或至少重算 newCameraMatrix
立即学习“C++免费学习笔记(深入)”;


















