相机标定原理与概念(先搞懂再动手)

📅 发布时间:2026/7/10 10:35:02 👁️ 浏览次数:
相机标定原理与概念(先搞懂再动手)
以下是一份完整的相机标定教程中文版专为工业视觉机器视觉初学者和实际项目开发者设计。内容基于 Halcon、OpenCV 和 MVTec 官方文档 工业产线真实经验涵盖原理、步骤、代码示例、常见问题及解决办法。教程分为三个部分相机标定的原理与概念为什么要做、标定板选择手把手操作步骤推荐两种主流方式代码实现Halcon OpenCVSharp C# 完整示例一、相机标定原理与概念先搞懂再动手1.1 为什么要做相机标定工业相机拍摄的图像是像素坐标系而实际生产需要物理尺寸mm比如测量零件宽度 10.00 ± 0.02 mm计算孔位中心距 15.5 mm机器人抓取偏移量 3.2 mm未经标定的图像存在畸变桶形/枕形和透视畸变直接测量的像素值误差可达 5–20%标定后可将误差降至 0.01–0.05 mm 级别。1.2 标定板选择工业最常用三种类型推荐尺寸格子数建议优点缺点适用场景棋盘格Chessboard8×11 或 9×127×10 或 8×11最常用、精度最高、Halcon/OpenCV原生支持需要足够视场边缘易丢失几乎所有工业测量场景首选圆点阵列Circle Grid直径 3–10 mm7×9 或 9×11对光照不敏感亚像素定位更稳制作成本高边缘点易丢失高精度圆孔/圆形零件测量AprilTag / ArUco边长 20–50 mm4×4 或 6×6支持位姿估计、自动识别精度略低于棋盘格机器人手眼标定、多相机外参工业推荐先用棋盘格标定内参→ 精度要求极高时再用圆点阵列验证。1.3 标定板制作建议工业现场实用材质亚克力 激光蚀刻 / 玻璃基板最稳 亚克力喷漆 打印纸贴亚克力最便宜但精度差平整度误差 0.01 mm用千分表测量格子间距精度±0.005 mm激光切割或光刻黑白对比度要强避免反光亚光喷漆二、手把手标定操作步骤推荐两种方式方式一使用 Halcon Calibration Assistant最简单、最推荐新手打开 Halcon → 启动Calibration Assistant选择标定板类型Chessboard / Circle Grid输入标定板参数Number of circles / rows / columnsCircle / square size实际物理尺寸单位 mmMark size圆点直径或方格边长采集 10–20 张不同角度、不同位置的标定板图像覆盖整个视场尽量让标定板倾斜、旋转、靠近/远离相机确保每个图像至少覆盖 60% 视场点击Calibrate→ Halcon 自动计算内参、外参、畸变系数保存标定参数文件.cal 或 .dat后续测量时加载此文件即可实现像素 → mm 转换方式二使用 OpenCV 标定C# 代码实现usingOpenCvSharp;usingSystem;usingSystem.Collections.Generic;classCameraCalibration{publicstaticvoidCalibrateChessboard(ListMatimages,SizepatternSize,floatsquareSizeMm){varobjectPointsnewListMat();varimagePointsnewListMat();// 生成标定板世界坐标3D点Z0MatobjpnewMat(patternSize.Height*patternSize.Width,1,MatType.CV_32FC3);inti0;for(inty0;ypatternSize.Height;y){for(intx0;xpatternSize.Width;x){objp.AtVec3f(i)newVec3f(x*squareSizeMm,y*squareSizeMm,0);}}foreach(varimginimages){MatgraynewMat();Cv2.CvtColor(img,gray,ColorConversionCodes.BGR2GRAY);boolfoundCv2.FindChessboardCorners(gray,patternSize,outPoint2f[]corners,ChessboardFlags.AdaptiveThresh|ChessboardFlags.NormalizeImage|ChessboardFlags.FastCheck);if(found){Cv2.CornerSubPix(gray,corners,newSize(11,11),newSize(-1,-1),newTermCriteria(CriteriaType.Eps|CriteriaType.MaxIter,30,0.001));objectPoints.Add(objp);imagePoints.Add(Mat.FromArray(corners));}}// 执行标定MatcameraMatrixnewMat();MatdistCoeffsnewMat();Mat[]rvecs,tvecs;doublermsCv2.CalibrateCamera(objectPoints,imagePoints,images[0].Size(),cameraMatrix,distCoeffs,outrvecs,outtvecs);Console.WriteLine($标定完成RMS误差{rms:F4});// 保存结果cameraMatrix.SaveImage(camera_matrix.xml);distCoeffs.SaveImage(dist_coeffs.xml);}}调用示例varimagesnewListMat();// 加载 15–30 张棋盘格图像CalibrateChessboard(images,newSize(9,6),25.0f);// 9×6格子每格25mm三、Halcon 几何测量完整集成示例C#usingHalconDotNet;usingOpenCvSharp;usingOpenCvSharp.Extensions;usingSystem.Windows.Forms;publicpartialclassMeasurementForm:Form{privateHWindowControlhWindowControl1;privateHTuplehvCamParam;// 内参privateHTuplehvPose;// 外参标定板位姿publicMeasurementForm(){InitializeComponent();hWindowControl1newHWindowControl{DockDockStyle.Fill};Controls.Add(hWindowControl1);}privatevoidMeasurePart(stringimagePath){HOperatorSet.ReadImage(outHObjecthoImage,imagePath);// 加载标定参数从 Halcon Calibration Assistant 保存HOperatorSet.ReadCamPar(calibration.campar,outhvCamParam);HOperatorSet.ReadPose(calibration.pose,outhvPose);// 阈值分割 区域选择HOperatorSet.Threshold(hoImage,outHObjecthoRegion,100,255);HOperatorSet.Connection(hoRegion,outhoRegion);HOperatorSet.SelectShape(hoRegion,outhoRegion,area,and,10000,999999);// 亚像素边缘提取HOperatorSet.EdgesSubPix(hoRegion,outHObjecthoContours,canny,1.5,20,40);// 拟合圆HOperatorSet.FitCircleContourXld(hoContours,algebraic,-1,0,0,3,2,outHTuplehvRow,outHTuplehvColumn,outHTuplehvRadius,outHTuplehvStartPhi,outHTuplehvEndPhi,outHTuplehvPointOrder);doublediameterPixelhvRadius.D*2;// 像素 → mm 转换使用标定参数HTuplehvDiameterWorld;HOperatorSet.DistancePpWorld(hvCamParam,hvPose,hvRadius*2,outhvDiameterWorld);doublediameterMmhvDiameterWorld.D;// 显示结果HOperatorSet.SetPart(hWindowControl1.HalconWindow,0,0,-1,-1);HOperatorSet.DispImage(hoImage,hWindowControl1.HalconWindow);HOperatorSet.SetColor(hWindowControl1.HalconWindow,red);HOperatorSet.DispCross(hWindowControl1.HalconWindow,hvRow,hvColumn,20,0);HOperatorSet.DispCircle(hWindowControl1.HalconWindow,hvRow,hvColumn,hvRadius,margin);MessageBox.Show($直径像素{diameterPixel:F3}px\n直径物理{diameterMm:F3}mm);}}四、工业现场最常见避坑清单标定板图像采集不足→ 至少 15–30 张覆盖整个视场、不同角度、不同距离→ 标定板必须完全平整误差 0.01 mm光照不均匀导致边缘提取失败→ 使用环形光/条形光/同轴光调整曝光时间和增益→ 加高斯滤波或中值滤波去噪测量区域选择错误→ 不要全图测量先用 Threshold SelectShape 提取 ROI→ 用 SelectShape(“area”, “and”, min, max) 过滤小噪声区域像素当量错误→ 必须用标定参数转换ImagePointsToWorldPlane不要手动写 0.01 mm/pixel内存泄漏→ 每帧测量后必须 Dispose 所有 HObject尤其是 HImage、HRegion、HXLDCont多线程冲突→ Halcon 非线程安全 → 每个线程独立创建 HDevProcedure 或 HOperatorSet五、总结与一句话铁律一句话记住先标定相机内参外参再用亚像素边缘提取 几何拟合 世界坐标转换才能做到工业级 0.01 mm 精度测量。如果您需要以下任一模块的完整可运行项目或更深入实现请直接告诉我完整 C# Halcon 几何测量 Demo 项目含相机采集 标定 测量 UIHalcon 标定板制作与 Calibration Assistant 详细步骤1D/2D 测量完整代码线宽、间距、角度、圆度等Halcon 与 OpenCVSharp 混合使用完整示例祝您的 Halcon 几何测量项目精度拉满、稳定上线