ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

OpenCV+MATLAB+C++双目视觉测量:从标定到三维变形量计算

OpenCV+MATLAB+C++双目视觉测量:从标定到三维变形量计算

简介:面向计算机视觉与机器视觉方向的毕业设计、课程设计及项目开发,这份资源基于OpenCV、Matlab与C++实现双目视觉测量,完整覆盖相机标定、立体校正、立体匹配、三维坐标重建和工件变形量计算。压缩包为ZIP格式,共33个文件,约2.01MB,内含C++源码(.cpp/.h)、Visual Studio工程文件(.sln/.vcxproj)、Matlab标定结果(.xml/.txt)、工件图像样本(.jpg)及三维模型(.obj)等,打开解决方案即可编译调试。该资源已有305人学习下载,源码经过严格测试,可在其基础上扩展应用。项目按图像预处理与特征点提取、Matlab相机标定、OpenCV立体校正与立体匹配、三维坐标重建等模块逐步展开,从原始图像、相机参数获取到工件变形量计算形成完整技术链路。配合示例图片和标定数据,可直接复现测量流程并观察每一步输出效果,帮助快速掌握双目视觉工程实现的关键细节。

1. 一套OpenCV+MATLAB+C++组成的双目视觉测量方案,究竟解决什么问题

工件放到双目测量台上,左右相机各拍一张图,程序就能告诉你某个特征点相对设计基准偏了多少毫米。这套需求在形变检测、夹具定位和自动化装配里非常常见,也是毕设、课设题目里曝光率最高的方向之一。这篇文章要拆解的就是基于OpenCV、MATLAB和C++三种工具链开发的双目视觉测量项目:用MATLAB完成相机标定和参数验证,用OpenCV完成立体校正、三维坐标重建与坐标数据重载,最后回到C++或MATLAB计算工件变形量。对新手来说,坑主要分布在标定参数、坐标系约定和精度验证三个环节;对希望快速上线的工程师,关键是把流程固定成可复现的模块。下文按开发顺序展开,每一步都尽量给出能复现的代码和参数。

2. 相机标定:先把内参、畸变和双目外参锁定,后续重建才有依据

2.1 标定在双目视觉测量里的角色:从张正友棋盘格说起

我先讲一个暴论:双目测量项目里,90%的三维坐标误差不是来自三角测量代码,而是来自标定参数本身。相机标定的本质,是用一组标定板图像去解相机的针孔投影模型和畸变模型。最常见的落地做法是张正友棋盘格标定法——拍摄不同姿态的棋盘格,提取角点,然后通过最小化重投影误差求解内参、畸变系数和每张图对应的外参。

单目系统里,参数主要是内参矩阵K,也就是fx、fy、cx、cy,加上径向畸变k1、k2、k3和切向畸变p1、p2。fx、fy是焦距在像素上的比例,cx、cy是光心像素坐标;畸变负责纠正透镜边缘的桶形、枕形变形和装配偏差。双目系统在此基础上还要解左右相机坐标系之间的旋转R和平移T,以及由它们派生出的本质矩阵E和基础矩阵F。把这套参数拿到手,后面的立体校正和三维重建才有数学基础。早期我总觉得标定是“拍几张棋盘格就完事”的体力活,后来发现参数差一丁点,重建出来的坐标就差得离谱,那段时间我把精度问题当玄学处理,最后才意识到是标定和外参没有收敛。

2.2 用MATLAB标定相机:从拍摄标定板到导出cameraParams

MATLAB在标定环节的优势是可视化好、交互简单,特别适合毕设和课设展示。常见做法是用棋盘格拍一组照片,用Camera Calibrator或脚本自动检测角点并计算参数。准备标定板时我用9x6的棋盘格,也就是内角点为9列6行,每格边长30mm,打印后贴到光学平板或玻璃板上;拍摄时让相机从不同高度和姿态采集20张以上,注意每张图里棋盘格的姿态要差异明显,不能只是左右平移。如果各图几乎都在同一个角度,后面畸变参数会拟合得很差。

boardSize = [9 6]; % 棋盘格内角点数:列x行 squareSize = 30; % 方格的边长,单位mm imds = imageDatastore('calib_imgs'); % 把拍摄图片放在这个文件夹 [imagePoints, boardSizeOut] = detectCheckerboardPoints(imds.Files); worldPoints = generateCheckerboardPoints(boardSizeOut, squareSize); cameraParams = estimateCameraParameters(imagePoints, worldPoints, ... 'NumRadialDistortionCoefficients', 2); showExtrinsics(cameraParams); fprintf('Mean reprojection error: %.4f px\n', cameraParams.MeanReprojectionError);

逻辑说明:detectCheckerboardPoints会返回每张图中棋盘格角点的亚像素坐标,generateCheckerboardPoints负责生成这些角点对应的世界坐标;estimateCameraParameters随后最小化重投影误差,解出内参、畸变和每张图的姿态外参。这套脚本和Camera Calibrator内置算法一致,但脚本方式更适合批量更换图片集和记录参数。

参数说明:boardSize顺序是列x行,不是行x列,写反了角点网格匹配不上;squareSize单位要和后面三维重建时的物理单位保持一致,建议全程用mm。NumRadialDistortionCoefficients我一般先用2,也就是k1、k2;如果误差明显偏大,再改成3把k3也纳入拟合。误差超过0.3px时,不要急着调算法,先检查标定板是否平整、图像是否有运动模糊和严重反光。如果拍的是同步双目图像,MATLAB里还有stereoCameraCalibrator,可以直接引入左右图序列,得到双目外参R、T,并和OpenCV结果对照。单目标定只能各自给内参和畸变,真正决定“左右关系”的外参必须在双目标定里求解。

2.3 用OpenCV(C++)做一遍等价标定,并和MATLAB结果互相验证

放到C++/OpenCV工程里,我会把标定代码写成独立模块,产出一个YAML文件,项目运行时直接加载。这里先讲单目标定,因为双目标定是在它基础上扩展的。经常有人问Halcon和OpenCV哪个更好用,我的经验是Halcon的标定和测量算子确实顺手,但OpenCV胜在源码开放、和C++工程集成没有授权负担,适合二次开发和课程设计。

cv::Size patternSize(9, 6); // 内角点:列x行 float squareSize = 30.0f; std::vector<cv::Point3f> objectPts; for (int r = 0; r < patternSize.height; r++) { for (int c = 0; c < patternSize.width; c++) { objectPts.emplace_back(c * squareSize, r * squareSize, 0.0f); } } std::vector<std::vector<cv::Point3f>> objectPoints; std::vector<std::vector<cv::Point2f>> imagePoints; for (const auto& file : imageFiles) { cv::Mat gray = cv::imread(file, cv::IMREAD_GRAYSCALE); std::vector<cv::Point2f> corners; bool ok = cv::findChessboardCorners(gray, patternSize, corners, cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_NORMALIZE_IMAGE); if (!ok) { std::cerr << "skip: " << file << std::endl; continue; } cv::cornerSubPix(gray, corners, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 30, 0.001)); imagePoints.push_back(corners); objectPoints.push_back(objectPts); } cv::Mat K, distCoeffs; std::vector<cv::Mat> rvecs, tvecs; double rms = cv::calibrateCamera(objectPoints, imagePoints, gray.size(), K, distCoeffs, rvecs, tvecs); std::cout << "RMS = " << rms << std::endl;

逻辑说明:objectPoints里的世界坐标按每个方格的边长生成,Z轴固定为0,所以标定板平面就是世界坐标系的XY平面;findChessboardCorners返回角点初始位置,cornerSubPix把它迭代到亚像素精度,这一步直接决定标定结果的好坏。calibrateCamera通过透镜投影模型重新投影这些角点,反复优化内参、畸变和外参,返回的RMS就是重投影误差。

参数说明:cv::Size(11, 11)是亚像素搜索窗口,窗口太小在低分辨率图上收敛慢,太大又容易把细节抹掉;TermCriteria用EPS + COUNT组合,我通常给30次迭代和0.001的精度。CALIB_CB_NORMALIZE_IMAGE能改善光照不均,但对局部反光无能为力,所以我还会在拍摄时避免把标定板摆在强光直射的位置。

双目标定则在此基础上做一次cv::stereoCalibrate:

cv::Mat R, T, E, F; double stereoRMS = cv::stereoCalibrate(objectPoints, leftImagePoints, rightImagePoints, K1, dist1, K2, dist2, cv::Size(width, height), R, T, E, F);

注意:stereoCalibrate的入参是已经标定好的单目参数,但它内部还会继续优化这些参数,所以最终应以双目标定输出的K1/dist1/R/T作为现场参数,而不是再把单目标定结果拿回去拼。R、T描述的是左相机相对右相机的刚体变换,坐标关系是X_R = R * X_L + T;这里的坐标系顺序不同,后续立体校正和三维重建的错误会非常难查。因此我习惯在标定完成后打印R和T,先做一次手算验证,再进下一步。

3. 立体校正与极线约束:让左右图像行对齐,把匹配从二维降成一维

3.1 立体校正在做什么:极线约束、行对齐与Q矩阵

立体校正的目的,是把双目图像重新投影到一个“虚拟的共同平面”上,让左右相机的光轴平行,对应点落在同一水平线上。这样做的好处是:匹配搜索从二维降到一维,且三角测量公式变成简单的三角形相似关系。如果没有校正,同一物体的两个成像点可能在任意方向偏移,哪怕你用特征匹配,也要为“不允许的偏移”付出额外代价,输出坐标会抖动。

OpenCV中这一阶段的核心函数是stereoRectify。它根据上一步的R和T计算出左、右相机各自的新投影矩阵P1、P2和一个视差转深度矩阵Q。P1、P2是3x4矩阵,把校正后的三维点投影到新图像坐标;Q则是把[u, v, disparity, 1]这段齐次坐标换算成[X, Y, Z, W]的4x4矩阵。有了它们,后面用triangulatePoints或reprojectImageTo3D都能直接输出三维坐标。很多初学者把stereoRectify和remap当成一个函数,实际前者只负责算矩阵,后者才真正重采样像素。

3.2 stereoCalibrate + stereoRectify在OpenCV里的完整调用链

在工程代码里,我会把这一串固定流程放在一个模块里,输入是上一章生成的标定参数,输出是两张校正好的图像和重投影矩阵:

// 输入:K1,D1,K2,D2,R,T,图像尺寸 cv::Mat R1, R2, P1, P2, Q; cv::stereoRectify(K1, D1, K2, D2, imageSize, R, T, R1, R2, P1, P2, Q, cv::CALIB_ZERO_DISPARITY, 0); cv::Mat map1L, map2L, map1R, map2R; cv::initUndistortRectifyMap(K1, D1, R1, P1, imageSize, CV_32FC1, map1L, map2L); cv::initUndistortRectifyMap(K2, D2, R2, P2, imageSize, CV_32FC1, map1R, map2R); cv::Mat leftRect, rightRect; cv::remap(left, leftRect, map1L, map2L, cv::INTER_LINEAR); cv::remap(right, rightRect, map1R, map2R, cv::INTER_LINEAR);

逻辑说明:stereoRectify不会自己去校正图像,它只输出能让图像被校正的旋转矩阵R1、R2和投影矩阵P1、P2、Q;真正的像素映射由initUndistortRectifyMap生成查找表,再由remap执行。查找表是一次性计算,但每次采集新图像都要用同一对映射表执行remap。我第一次做的时候以为每次循环都要重新算一遍查找表,结果帧率被拖到个位数。

参数说明:传给stereoRectify的最后一个参数alpha,我在这里写0,意思是校正后只保留最大有效像素区域,丢弃可能出现的黑边。如果想让图像边缘信息尽量完整,可以把alpha设为1,但代价是图像两侧会出现明显黑边。用在测量场景时,我会以“尽量不丢失被测区域”为准去调整alpha,而不是靠肉眼裁ROI。CALIB_ZERO_DISPARITY强制左右视图在无穷远处的视差为0;对于固定工作距离的测量平台,我建议带上这个标志,因为所有被测物都在有限距离范围内,不影响有限距离的三维重建,还能让后处理一致。

3.3 校正质量检查:画出极线和视差图,确认没有残余错位

校正到底成没成,光看一张图“好像对齐了”远远不够。我通常在调试阶段写一个极线检查函数:在左图上画几条水平线,然后看右图的对应特征点是否落在同一条水平线上。

for (int y = 50; y < leftRect.rows; y += 100) { cv::line(leftRect, cv::Point(0, y), cv::Point(leftRect.cols, y), cv::Scalar(0, 255, 0), 2); cv::line(rightRect, cv::Point(0, y), cv::Point(rightRect.cols, y), cv::Scalar(0, 255, 0), 2); } cv::imwrite("epipolar_check_left.png", leftRect); cv::imwrite("epipolar_check_right.png", rightRect);

如果校正正确,同一个物体的边缘、角点在左右图里与这些水平线没有明显上下偏差。对于畸变较大的镜头,还要重点观察图像边缘处是否有残余垂直错位,那是畸变模型或alpha设置没完全收敛的信号。

除了肉眼检查,更可量化的一步是跑一遍SGBM立体匹配,看视差图:无效像素占比高不高,物体边缘是否出现大面积断裂。cv::StereoSGBM是OpenCV里常用的半全局匹配器,参数中的numDisparities和blockSize决定匹配范围和窗口大小。如果视差图里物体边界断裂严重,多数不是SGBM参数问题,而是校正后的行对齐误差太大。遇到这种情况,我会回到stereoCalibrate重新检查标定图片集质量,而不是盲目调SGBM。

4. 三维坐标重载:从标定文件到三角测距的C++落地路径

4.1 三角测量原理:为什么有了P1、P2矩阵就能算出三维坐标

校正后两个相机等效为光轴平行、焦距相同的理想相机,同一个物理点在左右图里的像素横坐标分别为u_l和u_r,视差d=u_l-u_r,深度Z满足:Z = f * baseline / d。这里的baseline是左右光心之间在X方向的距离,f是焦距像素单位。实际OpenCV里不要求每次都手动套这个公式,cv::triangulatePoints会直接用P1、P2做两条投影射线的交汇。

P1、P2是3x4投影矩阵,把三维齐次点[X Y Z 1]投影到像素坐标[u v 1]。三角测量本质上是已知两个相机的投影矩阵和一对匹配像素坐标,反向求解三维点,让它在两个相机下的重投影误差之和最小。OpenCV用奇异值分解求解这个线性系统,因此比直接用视差公式更鲁棒,尤其适用于镜头不完全共面的系统。理解这一点对后续排错很有用:如果三角化出来的点有系统性漂移,先查P1、P2用的是不是stereoRectify输出,而不是自己拼凑的矩阵。

4.2 在C++里“重载”标定数据:用FileStorage读写YAML/XML

标定一次之后,项目启动时应当直接从参数文件读取,而不是每次启动都重新标定。标题里的“三维坐标重载”,实操上就是把标定结果持久化到文件,然后在测量程序里加载出来。C++这边最稳定的做法是用cv::FileStorage读写YAML或XML。

保存:

cv::FileStorage fs("stereo_calib.yaml", cv::FileStorage::WRITE); fs << "imageSize" << imageSize; fs << "cameraMatrixL" << K1; fs << "distCoeffsL" << D1; fs << "cameraMatrixR" << K2; fs << "distCoeffsR" << D2; fs << "R" << R; fs << "T" << T; fs << "P1" << P1; fs << "P2" << P2; fs << "Q" << Q; fs.release();

加载:

cv::FileStorage fs("stereo_calib.yaml", cv::FileStorage::READ); if (!fs.isOpened()) { std::cerr << "calib file open failed" << std::endl; return -1; } fs["cameraMatrixL"] >> K1; fs["cameraMatrixR"] >> K2; fs["R"] >> R; fs["T"] >> T; fs["P1"] >> P1; fs["P2"] >> P2; fs["Q"] >> Q;

逻辑说明:YAML和XML可以同时保存矩阵、向量和标量,读取顺序不要求与写入顺序一致,但键名必须唯一且不能拼错。正因为文件加载和查找Key太容易手误,我会在读取后立即打印矩阵尺寸来校验,R必须是3x3、T必须是3x1、P1和P2必须是3x4、Q必须是4x4。

参数说明:FileStorage的默认矩阵类型在标定场景下是CV_64F,和stereoCalibrate输出一致。如果为了省空间把矩阵转成CV_32F保存,读取后做矩阵乘法可能遇到类型不匹配的断言错误。另一个容易踩的是图像尺寸:remap要求查找表尺寸和原图一致,如果保存的imageSize和当前图像不一致,图像会被拉伸或裁切,坐标也跟着整体偏移。

4.3 从左右匹配点到三维坐标:triangulatePoints与Q矩阵两种算法

拿到匹配点后,既可以用上面的P1、P2调用triangulatePoints,也可以在校正后的图像上直接用Q矩阵换算。匹配点既可以是手动点选的特征,也可以是SIFT、ORB特征匹配,或者SGBM视差图转出来的点对。这里给出手动指定或特征点集的三角化代码:

std::vector<cv::Point2f> leftPts = { cv::Point2f(560.3f, 260.1f) }; std::vector<cv::Point2f> rightPts = { cv::Point2f(508.7f, 260.2f) }; cv::Mat pts4D; cv::triangulatePoints(P1, P2, leftPts, rightPts, pts4D); std::vector<cv::Point3f> pts3D; for (int i = 0; i < pts4D.cols; i++) { const cv::Mat col = pts4D.col(i); double w = col.at<double>(3, 0); pts3D.emplace_back( col.at<double>(0, 0) / w, col.at<double>(1, 0) / w, col.at<double>(2, 0) / w); }

逻辑说明:triangulatePoints输出的pts4D是4xN的齐次坐标矩阵,每列对应一个三维点的齐次坐标[X, Y, Z, W],除以W后才能得到非齐次的X、Y、Z。最终坐标是在校正后的左相机坐标系下表达的,单位与标定时的squareSize一致,我用mm那就全是mm。

参数说明:这里输入的P1、P2必须是stereoRectify输出的3x4投影矩阵,不能用原始内参矩阵补齐。用错的话,三维坐标会整体偏移或绕某根轴旋转。还有一点,校正后的左右匹配点纵坐标理论上相等;如果匹配点纵坐标相差好几像素,三角化出来的点会在Z方向出现很大噪声。

当图像已经校正且极线对准,还可以用视差公式直接从Q矩阵还原,OpenCV把这一步封装成了reprojectImageTo3D:

cv::Mat disparity, depth; cv::reprojectImageTo3D(disparity, depth, Q, true, CV_32F);

它把整张视差图一次性映射成三维点云,大小和原图一致,每个像素存的是该点的X、Y、Z坐标。测量工件变形时,我倾向先用reprojectImageTo3D得到密集点云,再取ROI做平面拟合,这比只取稀疏特征点更稳,而且批量矩阵运算比逐点循环快很多。视差图里无效像素对应的三维点要做掩膜剔除,否则拟合平面时会把黑边和空洞点一起算进去。

5. 双目测量开发避坑:5个让标定结果和坐标精度翻车的典型问题

5.1 角点检测漏检或错检导致标定结果明显异常

现象:findChessboardCorners对同一张标定板图片有时成功、有时失败,或者返回的角点网格错位,stereoCalibrate输出R、T数值异常大。

原因:棋盘格图案是对称的,当拍摄角度太刁钻或图像分辨率不够时,算法无法判断左上角的方位;标定板表面反光、阴影也会让角点周围灰度不满足二阶导条件。

解决:给棋盘格周围留出白边并在打印时保持平整;调用findChessboardCorners时加上cv::CALIB_CB_EXHAUSTIVE_SEARCH,让它多做一轮全图搜索;如果仍然漏检,把这张图从数据集里剔除,而不是硬编进去。对于反光严重的场景,我宁可用低反光哑光纸,也不要指望后处理能把反光完全去掉。

5.2 标定图像覆盖不全,重投影误差“假及格”

现象:重投影误差只有0.1像素,但实测工件上的距离偏差却有2毫米以上。

原因:所有照片几乎都在画面中心、姿态变化很小,畸变参数特别是切向畸变拟合不出来,内参虽然能在这些图上重投影得很好,但外推到真实工作距离时严重失真。

解决:拍照时尽量覆盖画面的四个角和中心,并且让标定板处于不同的成像深度;每张图姿态至少有一点点旋转或俯仰变化。检查失败的简单方法是可视化标定板姿态:如果showExtrinsics里标定板的位姿包络看起来像一个方向集中,就要补拍图像。标定板姿态足够离散,比单纯增加张数更有效。

5.3 MATLAB和OpenCV标定结果对不上

现象:拿MATLAB标出的内参放到OpenCV做立体校正,图像看起来被放大或缩小,或者Z坐标整体偏大、偏小。

原因:两套软件对角点提取的亚像素位置、畸变模型定义和坐标轴方向有细微差别。在双目里更常见的是用两个独立的单目标定结果组合,而没有做一次统一的立体标定,R、T自然对不上。

解决:把所有标定流程固定在同一套工具链里。如果项目主体是C++/OpenCV,就把标定也放在OpenCV完成,MATLAB只做结果可视化;如果毕设要求MATLAB展示,就用MATLAB的stereoCameraCalibrator,然后把R、T转成OpenCV的约定。不要混着用,除非你明确知道两者的坐标轴正方向和畸变多项式顺序是等价的。跨工具验证可以保留,但不能把两边的参数直接交叉带进同一个工程。

5.4 校正后出现大面积黑边,或者边缘特征丢失

现象:remap输出图像里左右两侧各有一大块黑色无效区域,被测工件刚好落在黑边里测不到;或者反过来,严重裁切,图像边缘的角点消失。

原因:stereoRectify里alpha参数控制校正后图像的有效区域。alpha=0时裁到最大内接矩形,图像最小;alpha=1保留完整原图视野,但黑边最多。默认值不是“自动最优”,而是根据应用场景选出来的。

解决:测量系统设计阶段就确定好alpha。如果工件可能出现在画面边缘,就把alpha设为1,然后在做视差图时忽略黑边区域;如果图像分辨率冗余,用alpha=0裁剪后依然能覆盖工件,就可以保持默认。可以把alpha从0到1按0.25步长生成几张预览图,快速选择黑边最小同时工件完整的值。

5.5 标定文件加载后数值错乱,或Debug/Release构建翻车

现象:YAML文件用记事本打开看得到数字,代码里加载出来不是全0就是维度错误;或者同一个工程在Debug模式正常、Release模式崩溃。

原因:Windows上OpenCV的预编译库按Debug和Release分开,对应运行时库不同;混合使用就会在API内部出现内存错误。YAML读取错乱,则往往是保存和读取时的键名不一致,或者文件没有成功打开就继续读取。

解决:先检查fs.isOpened(),再用fs["cameraMatrixL"].size()打印矩阵维度,确保和写入一致。构建层面,Debug工程链Debug版的opencv_worldxxxxd.lib,Release工程链Release版的opencv_worldxxxx.lib,不要把两个库混在同一个配置里。如果用的是vcpkg安装OpenCV,注意指定x64-windows三元组,并在项目属性里统一运行库。这条规范我踩过一次后写进了团队的环境配置文档,后续再没因为库版本浪费过时间。

6. 用MATLAB和C++把三维坐标变成变形量:精度验证与验收习惯

6.1 把重建点云与基准面对齐,计算工件变形量

三维坐标算出来后,变形量总是相对一个设计基准而言的。常见做法是:先取工件上未变形区域的三维点做平面拟合,得到基准平面;然后把其他点的法向距离与基准平面作差,得到平面度或位置偏差。在MATLAB里可以这样算:

% pts3D: Nx3,单位mm ptCloud = pointCloud(pts3D); [model, ~] = pcfitplane(ptCloud, 0.5); % 0.5mm内点阈值 planeParams = model.Parameters; % [a b c d] dist = abs(pts3D * planeParams(1:3)' + planeParams(4)) / norm(planeParams(1:3)); [maxDev, idx] = max(dist);

这里不要把所有点都拿去拟合平面。如果把被测变形区域一起拿去拟合,平面会被“平均”掉,变形量就看不出来了。我会手动框选ROI,或者按点云法向聚类来区分基准区和变形区。如果变形量指孔位偏移,则需要在孔边缘取多点拟合圆心,再比较圆心空间坐标。

6.2 精度验证:重投影误差、距离复测和多组标准差

验收一套双目测量系统,最直接的办法是放一个已知尺寸的量块或标准件,多次测量后看测量值与真值的偏移和标准差。我一般按三步走:单目标定重投影误差小于0.2像素、双目标定小于0.3像素,达不到就先补拍标定图像;然后用标定板或标准量块放在工作距离处,测特征点间距并与标称值比较,误差应小于0.1mm;最后在同一位置重复测量20次,标准差应小于0.02mm。

验证内容推荐指标方法
单目重投影误差≤0.2 pxcalibrateCamera返回 RMS
双目重投影误差≤0.3 pxstereoCalibrate返回 RMS
已知距离复测误差≤0.1 mm量块间距对比
重复测量标准差≤0.02 mm同位置测量20次

还要在视场的多个位置复测,因为镜头畸变和校正残差在边缘更明显。如果一个方向的误差明显偏大,优先怀疑标定板和相机之间的平行度,再看左右相机同步曝光有没有时间差。我在做双目测量项目时有个习惯:每次换环境光照、换镜头焦距或挪动相机位置都重新标定一次,并把重投影误差记录到日志里。早期翻车,猛地丢过,就是因为标定做完了就以为可以一直吃老本,结果温度、震动和镜头松动把参数悄悄改了,坐标误差大得离谱。后来我把标定当“一次性消耗品”看待,精度问题反而少了。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进