简介:OpenCvSharp棋盘格图像下的相机标定助手,面向C#开发者与计算机视觉初学者,演示在Visual Studio中通过OpenCvSharp完成相机标定的完整流程,弥补C#调用OpenCV示例稀缺的痛点。压缩包共71个文件,大小21.15MB,主要包含12个C#源文件、VS项目配置与编译产物,如可执行exe和动态库dll,另有26张棋盘格JPG测试图及ini配置文件,既可直接运行查看效果,也便于对照源码学习。已有2512人学习/下载。资源提供WinForms标定界面、标定计算类、棋盘格生成逻辑等模块,目录覆盖Debug/Release输出,结构清晰。通过研读代码,可理解相机内参、畸变系数的标定步骤,获得工程组织思路,还可借鉴其扩展至SFM三维重建等更复杂的视觉任务,适合课程设计、课题预研或工业视觉标定参考,也有助于加深对OpenCvSharp底层封装的理解。
1. OpenCvSharp 棋盘格图像下的相机标定助手:为什么还要自己写个助手
第一次做视觉测量项目时,我拿着一块打印出来的棋盘格在摄像头前翻来覆去地拍,以为只要拍几十张图丢给 OpenCV 就能拿到内参。结果花了一晚上,得到的相机内参矩阵主点 cx 跑到图像外面去了,畸变系数大得离谱,整条流水线的尺寸测量全偏。后来才明白:相机标定不是“把图丢进去就出结果”的黑匣子,棋盘格怎么放、角点怎么提、参数怎么设、结果怎么验,每一步都直接决定后续测量、定位、拼接的精度。
OpenCvSharp 棋盘格图像下的相机标定助手,就是用 C# 在 .NET 环境下,基于 OpenCvSharp 的棋盘格角点检测与相机标定接口,把“拍棋盘格 -> 检测角点 -> 标定内参 -> 验证结果”这个流程封装成可复用工具。它解决的是工业相机、USB 摄像头在尺寸测量、机器人抓取、双目定位前的相机内参标定问题,适合刚接触视觉标定的新手,也适合想把标定流程沉淀成内部工具的 C# 工程师。
2. 棋盘格相机标定在算什么:内参、畸变模型与数据准备
2.1 角点从世界坐标到像素坐标:棋盘格提供了什么
相机标定要回答的核心问题是:三维空间里的一个点,到底是怎么落到二维图像上的?这个过程在几何上是一条固定链路——世界坐标系里的点先通过外参(旋转矩阵 R 和平移向量 t)变换到相机坐标系,再经过透视投影落到归一化成像平面,最后通过内参矩阵映射到像素坐标系。
棋盘格在这里的用处很巧妙。它是一块平面板,所有角点都满足 z=0,而且角点之间的物理间距是已知且均匀的。这意味着不需要额外测距,就能为每个角点生成一组精确的世界坐标。棋盘格角点又具备极强的图像特征——黑白方块交界处是天然的角点,检测算法稳定,亚像素精度也容易做上去。
// 以 9x6 内角点棋盘格为例,物理格子边长 25mm var patternSize = new Size(9, 6); float squareSize = 25f; var objectPoints = new List<Point3f>(); for (int j = 0; j < patternSize.Height; j++) { for (int i = 0; i < patternSize.Width; i++) { objectPoints.Add(new Point3f(i * squareSize, j * squareSize, 0)); } }这段代码生成了一组以棋盘格左上角第一个内角点为原点的世界坐标。注意循环顺序是先按行再按列,这样坐标的 x、y 方向和棋盘格图像上的行、列方向一致。每一张标定图都使用同一组 objectPoints,因为棋盘格本身就是一个局部坐标系,相机在哪个位置拍摄属于外参要拟合的事情,内参计算不关心标定板在空间中的绝对位置。
2.2 内参矩阵、径向畸变和切向畸变:标定输出的参数含义
标定结束后拿到的东西,绝大多数场景下只有两项:一个 3x3 的内参矩阵和一组畸变系数。
内参矩阵的形态是 [fx, 0, cx; 0, fy, cy; 0, 0, 1],fx 和 fy 分别是 x、y 方向以像素为单位的等效焦距,cx 和 cy 是主点坐标,理论上接近图像中心。对工业面阵相机来说,fx 和 fy 通常在图像宽高这个数量级附近,比如 1280x1024 的图,fx 在 1000 上下是合理的。如果标定出来的 fx 只有几十或者上万,多半是数据集或参数出了问题。
畸变系数是另一组要读懂的数据。OpenCV 默认模型输出的是 k1、k2、p1、p2,以及可选的 k3,其中 k1、k2 是径向畸变系数,控制图像从中心向外扩张或收缩的程度;p1、p2 是切向畸变,主要来源于镜头和成像芯片不严格平行。在同一套标定结果里,k1、k2 的量级在 0.1 到 1 之间是常见情况,如果超过这个范围,要警惕是不是只有一两张图参与了计算。
2.3 棋盘格标定板、内角点数与图像数量:开拍前的准备
很多人第一次做棋盘格标定,会在“格子数”和“内角点数”上翻车。一张 10 列 7 行的黑白棋盘格,内角点是 9x6,而不是 10x7。FindChessboardCorners 要的是内部角点数量,也就是黑白方块交界处那个点的数量。画标定板的时候,建议直接在网上下载标准棋盘格图案,或者用代码生成,不要手工在 PPT 里排方块,否则黑色方块大小不一致、行距不均匀,角点检测会随机失败。
标定板物理尺寸的选取也要讲究。A4 纸打印 25mm 格子在普通场景够用,但如果有微距镜头或者大视野镜头,要考虑单个角点在图像里至少要占 10 到 20 个像素,格子太小会导致角点信息糊成一团。打印之后最好贴在平整的硬板上,普通纸的褶皱和弯曲会让角点坐标产生亚像素级别的偏移,近距离标定时误差会被明显放大。
图像数量没有绝对下限,但一个能稳定出结果的数据集通常在 15 到 25 张之间。这些图像要覆盖画面的中心和四个角落,还要包含相机在正对、左右旋转、上下倾斜、远近变化下的拍摄结果。只有正对棋盘格的图,无论拍多少张,标定出的畸变模型都对边缘区域没有约束力。
3. 用 OpenCvSharp 跑通棋盘格标定:最小可运行代码
3.1 NuGet 包准备与图片来源:本地图片和 RTSP 取图的差异
在 C# 项目里使用 OpenCvSharp 只需要在 NuGet 中安装 OpenCvSharp4 和 OpenCvSharp4.runtime.win 两个包。前者提供 API,后者带原生运行库。安装完成后 using OpenCvSharp 就能开始写代码。如果项目要发布到 Linux 服务器,需要替换对应的 runtime 包,Windows 上开发的程序不能直接拿过去跑。
标定图像有两个来源。一个是直接读取本地保存好的图片文件,适合前期调通流程;另一个是直接从相机实时取流,适合把标定助手做成一个带采集功能的工具。对 RTSP 协议的网络相机,OpenCvSharp 的 VideoCapture 可以直接打开 URL,但默认传输方式在某些设备上不稳定。网络环境差时,画面会出现撕裂和花屏,直接影响角点检测。常见做法是把 RTSP 流强制切到 TCP 传输:
using var cap = new VideoCapture("rtsp://192.168.1.64:554/stream1"); cap.Set(VideoCaptureProperties.RtspTransport, 1); // 1 为 TCP,0 为 UDPTCP 传输相比 UDP 更可靠,但延迟会稍高一点。对采集标定图这种离线场景,稳定优先于低延迟,TCP 是更省心的选择。
3.2 角点检测与亚像素细化:FindChessboardCorners + CornerSubPix
棋盘格角点检测是整个标定流程里最直观的一步,也是失败率最高的一步。核心接口是 Cv2.FindChessboardCorners,它把一张灰度图、内角点数量和输出参数传进去,返回是否找到。检测到的是整数像素坐标,精度不够,需要再做一次亚像素细化。
using var gray = new Mat(); Cv2.CvtColor(image, gray, ColorConversionCodes.BGR2GRAY); bool found = Cv2.FindChessboardCorners(gray, patternSize, out var corners); if (!found) { Console.WriteLine("跳过当前图像:未找到棋盘格"); return; } var criteria = new TermCriteria(CriteriaTypes.Eps | CriteriaTypes.Count, 30, 0.001); Cv2.CornerSubPix(gray, corners, new Size(11, 11), new Size(-1, -1), criteria); using var view = image.Clone(); Cv2.DrawChessboardCorners(view, patternSize, corners, found); Cv2.ImWrite("last_detected.jpg", view);亚像素细化的原理是在角点附近的灰度梯度方向上做迭代搜索,让角点坐标收敛到浮点精度。windowsSize 参数设得越大,参与计算的邻域越广,对噪声越不敏感,但角点定位也越容易被周围梯度干扰。日常标定用 11x11 是个稳妥起点,图像特别模糊时可以加大到 15x15,高分辨率工业相机上 5x5 也够用。zeroZone 传 Size(-1, -1) 即可,表示不设置零区域。打印一张带检测结果的图出来确认角点位置,比只看布尔返回值要可靠得多。
3.3 CalibrateCamera 标定主流程:从角点到内参与畸变系数
检测完所有图像、收集好角点之后,调用 CalibrateCamera 就进入核心求解环节。这里要把所有图的角点坐标按顺序组织成数组,并结合每张图对应的世界坐标一起传入。
var objectPointsList = new List<Point3f[]>(); // 每张图一组世界坐标 var imagePointsList = new List<Point2f[]>(); // 每张图一组像素坐标 // 对每张检测成功的图: // objectPointsList.Add(objectPoints.ToArray()); // imagePointsList.Add(corners); var imageSize = new Size(gray.Width, gray.Height); double rms = Cv2.CalibrateCamera( objectPointsList.ToArray(), imagePointsList.ToArray(), imageSize, out var cameraMatrix, out var distCoeffs, out var rvecs, out var tvecs, CalibrationFlags.ZeroTangentDist | CalibrationFlags.FixK3); Console.WriteLine($"RMS 误差: {rms:F4}"); Console.WriteLine($"内参矩阵:\n{cameraMatrix.Dump()}"); Console.WriteLine($"畸变系数:\n{distCoeffs.Dump()}"); using var fs = new FileStorage("camera_params.xml", FileStorage.Modes.Write); fs.Write("cameraMatrix", cameraMatrix); fs.Write("distCoeffs", distCoeffs); fs.Write("imageWidth", imageSize.Width); fs.Write("imageHeight", imageSize.Height);这里有两个参数值得展开。ZeroTangentDist 和 FixK3 组合是普通镜头标定的常见配置:把切向畸变固定为零,把第三个径向系数 k3 固定为 0,只估计 k1、k2。普通工业镜头的切向畸变很小,强行估计反而容易在图像数量不足时产生错误漂移。如果镜头畸变很大,比如广角镜头或低端网络摄像头,就需要去掉这两个标志位,让五个畸变参数全部参与优化。
3.4 用 Undistort 和重投影误差验证标定质量
拿到内参后千万不要直接存起来就完事,必须做两个验证。第一个是所有 OpenCV 文档里都提到的重投影误差,第二个是更直观的——直接对一张原始图像做去畸变,看看画面里的直线是否变直。
double totalErr = 0; int totalPoints = 0; for (int i = 0; i < objectPointsList.Count; i++) { Cv2.ProjectPoints(objectPointsList[i], rvecs[i], tvecs[i], cameraMatrix, distCoeffs, out var projected); double err = Cv2.Norm(imagePointsList[i], projected, NormTypes.L2); totalErr += err * err; totalPoints += objectPointsList[i].Length; } double meanErr = Math.Sqrt(totalErr / totalPoints); Console.WriteLine($"平均重投影误差: {meanErr:F4} 像素"); using var dst = new Mat(); Cv2.Undistort(image, dst, cameraMatrix, distCoeffs); Cv2.ImWrite("undistorted.jpg", dst);重投影误差的含义是把世界坐标投影回图像平面,和检测到的像素坐标比差距有多大。这个值受角点检测精度和标定模型拟合程度的共同影响。Undistort 验证则更直观:找一面贴了瓷砖的墙或者一根笔直的线材,拍一张再校正,看边缘是否还歪着。两边都过了,标定结果才敢往项目里用。
4. 标定参数怎么调:棋盘格尺寸、图像数量与标志位配置
4.1 棋盘格参数配置:一张可打印标定板的生成方式
手头没有现成标定板时,用 OpenCvSharp 画一张非常快。关键是格子数、物理尺寸和像素尺寸要匹配打印媒介。下面这段代码可以生成一张适合 A4 纸打印的 10x7 棋盘格,对应内角点 9x6,单格边长 25mm。
int cols = 10, rows = 7; float squareSizeMm = 25f; float mmPerPixel = 2f; // 打印分辨率约 127 DPI 时的估算值 int imgWidth = (int)(cols * squareSizeMm / mmPerPixel); int imgHeight = (int)(rows * squareSizeMm / mmPerPixel); using var board = new Mat(imgHeight, imgWidth, MatType.CV_8UC3, Scalar.White); for (int j = 0; j < rows; j++) { for (int i = 0; i < cols; i++) { if ((i + j) % 2 == 0) { var rect = new Rect( (int)(i * squareSizeMm / mmPerPixel), (int)(j * squareSizeMm / mmPerPixel), (int)(squareSizeMm / mmPerPixel), (int)(squareSizeMm / mmPerPixel)); Cv2.Rectangle(board, rect, Scalar.Black, -1); } } } Cv2.ImWrite("checkerboard_10x7.png", board);这里的 mmPerPixel 是一个容易被忽略的参数。不同的执行环境、不同的屏幕分辨率下,直接按像素生成的 PNG 打印出来的物理尺寸会有很大偏差。打印前最好用尺子量一下生成的图上单格边长,再微调 mmPerPixel。标定板生成后要在同一张光线下拍摄,不要一半贴了哑膜另一半反光,反光区域的角点检测稳定性会明显下降。
4.2 图像数量、姿态覆盖和清晰度的自检方法
数据集的姿态覆盖是影响内参精度的头号因素。拿一块棋盘格只放在画面正中拍 20 张,和分散在画面四角拍 15 张,标定结果的质量可能差一倍。一个容易执行的方法是七组拍法:正对中心拍一组,向左右各平移一组,向上下各平移一组,然后分别在 15 度左右倾斜、上下俯仰的姿态下各补一组。
每组拍摄时,棋盘格在画面里要占三分之一以上面积,太小的话角点像素密度不够,亚像素细化的优势就发挥不出来。图像模糊是另一个常见问题,手持拍摄时按快门的瞬间手抖会造成轻微运动模糊,角点检测可能侥幸通过,但亚像素坐标已经偏了。有三角架尽量用,没有的话提高快门速度,ISO 高一点可以接受,运动模糊比噪点更致命。
每拍完一组,把检测结果可视化出来看一眼。不要批量拍完再去检测,如果发现某组图角点全乱,重新布置拍摄比事后补救容易得多。
4.3 亚像素窗口和 CalibrationFlags:精度调节的空间
亚像素细化环节里,CornerSubPix 的 windowSize 和迭代次数是可调项。windowSize 是单边尺寸,11x11 意味着以初始角点为中心,上下左右各取 5 个像素参与计算。图像信噪比低时把窗口加大,角点附近有其他边缘干扰时适当减小。迭代次数 30 次一般足够,TermCriteria 里的 epsilon 设为 0.001 已经能达到浮点亚像素精度,调得更小对精度没有实际帮助,只是增加耗时。
标定标志位 CalibrationFlags 是新手最容易忽略的部分。默认情况下五个畸变参数以及内参矩阵全部自由优化,理论上最灵活,但数据不足时会过拟合。通常的调整思路如下:
| 参数情况 | 推荐标志位 |
|---|---|
| 普通镜头,图像 15 张以上 | ZeroTangentDist + FixK3 |
| 大畸变镜头,广角 | 默认全量估计,不固定任何参数 |
| 主点明显偏移但数据量少 | FixPrincipalPoint 保底 |
| 已有粗略内参,想进一步优化 | UseIntrinsicGuess |
FixK3 不等于把 k3 设成 0 就能省略,它只是让优化器不更新 k3。如果后续换用大畸变镜头,记得把标志位改回默认配置,否则结果会与真实模型不匹配。
4.4 重投影误差多少算合格:经验参考值
重投影误差是标定质量最容易量化的指标,但它不是万能的。经验数据是:0.1 像素以下属于优秀,0.1 到 0.3 像素对普通测量项目完全够用,0.3 到 0.5 像素需要检查数据集质量,0.5 像素以上基本不能用于精密测量。
要注意的是,重投影误差低不代表标定结果一定正确,它只说明检测到的角点和投影模型自洽。如果 20 张图全部集中在画面中心,模型把中心区域拟合得再好,边缘畸变可能依然无人约束。所以最终的裁量标准要结合去畸变后的图像效果来判断。对标 Matlab 相机标定工具箱的可视化结果,OpenCV 的 RMS 误差数值和它计算的是同一个东西,可以直接互相参考。
5. 棋盘格标定避坑指南:现象、原因与处理
5.1 内角点数写错:FindChessboardCorners 永远找不到角点
现象:换了不同棋盘格图片,检测结果一直是 false。偶尔棋盘格正对镜头能检测到,稍微偏一点就失败。
原因:patternSize 传入的是内角点数,不是格子数。很多人数了棋盘格的行列数,比如 10x7 的格子,直接写 new Size(10, 7),但 OpenCV 要找的是黑白方块交界处的角点数量,应该传 Size(9, 6)。内角点数量写错的情况下,检测算法在图像里按错误的数量去找角点,匹配的评价值始终不过阈值。
解决:先固定板子的行列数,然后分别减一,作为 patternSize。检测成功后用 DrawChessboardCorners 画一次检测结果,确认角点位置是否正确。这个验证步骤只需要做一次,但能省掉后面一整轮重新标定的时间。
5.2 倾斜和暗光下角点检测失败:曝光和分辨率的坑
现象:棋盘格摆在画面正中央、光照充足时,检测成功率很高。一旦倾斜 15 度以上,或者环境光偏暗,FindChessboardCorners 频繁返回 false。
原因:角点检测依赖黑白方块之间的灰度梯度。倾斜导致透视压缩,角点在某个方向上的梯度宽度变窄;暗光下噪声变大,梯度方向变得不稳定。亚像素细化也有同样的问题,它在梯度方向上迭代,梯度信息弱时迭代结果会在几个像素范围内抖动。
解决:优先处理曝光,手动设置相机曝光参数,确保棋盘格白色区域不溢出、黑色区域不发灰。对 RGB 相机可以用 V4L2 或厂商 SDK 把曝光时间调到固定值,不要用自动曝光。其次是调整棋盘格在画面中的占比,让单个角点附近的黑白过渡区域至少占据 30 个像素。硬要检测时,可以先将图像高斯模糊再检测,偶尔能救回模糊图,但标定精度没有保证。
5.3 标定出的内参矩阵离谱:fx、fy 异常和主点漂移
现象:标定完成,RMS 误差看起来正常,但 cameraMatrix 里 fx 是 10000,cx 是 2000,图像分辨率才 1280x1024。畸变系数 k1 是 8.5,一看就不对。
原因:最有可能的是有效图像太少或者覆盖单一,只有两三张图参与了标定。优化器会尝试用外参去拟合错误的数据,导致内参被推离合理范围。另一个常见原因是混入了角点检测不准确但仍返回 found 的图,比如棋盘格部分被遮挡,OpenCV 找到了一些误匹配角点。
解决:检查参与标定的图像数量,少于 10 张就补拍。对每张图的角点可视化结果做一遍检查,有误检的直接剔除。主点 cx、cy 与图像中心偏差超过图像宽度或高度的 10% 时,建议在标志位中临时开启 FixPrincipalPoint,先把主点固定在图像中心,再观察 RMS 是否有明显上升。如果固定主点后误差暴涨,说明数据集本身有问题,不是主点的锅。
5.4 重投影误差漂亮但校正效果差:数据集不自洽的坑
现象:RMS 误差 0.12 像素,自我感觉良好,结果去畸变后画面边缘的直线仍然弯成弧线。
原因:所有标定图都集中在画面中心区域。畸变模型在画面中心附近拟合得很好,但中心区域几乎没有径向畸变的约束信息,模型对边缘畸变的估计完全靠外推。边缘的真实畸变和模型外推的畸变不一致,校正后自然还是弯的。
解决:重新组织数据集,每张图让棋盘格分别贴近画面的四角和四条边。不要担心边缘畸变大的地方检测失败,检测失败的图往往恰恰是畸变约束最强的图。对畸变明显的镜头,可以考虑分两张拍摄:一张让棋盘格在左上角,一张在右下角,通过旋转标定板角度来解决边缘角点被压缩的问题。
5.5 更换镜头或分辨率后继续用旧内参:尺寸变了就重标
现象:同一个相机的镜头从 6mm 换成 12mm,或者把采集分辨率从 1920x1080 改成 1280x720,去畸变结果变得很奇怪,测量精度明显下降。
原因:内参矩阵里的 fx、fy 是焦距除以像元尺寸后的像素单位值,镜头焦距变化、图像分辨率变化都会改变这个值。畸变系数同样和镜头光学设计强相关。换镜头、换分辨率、换相机的裁剪模式,都必须重新标定。
解决:在标定程序里把图像宽高和相机型号一并写入参数文件,使用参数时先比对当前图像尺寸和参数文件里的尺寸,不一致就警告。参数文件的命名也包含分辨率,比如 camera_left_1920x1080_20241101.xml,找参数的时候一眼就能看出哪份对应哪套配置。
6. 把标定助手做成能复用的工具:自动采集与结果验证
6.1 实时采集与自动筛选:把标定做成真正的助手
批量处理本地图片的标定程序只能算半成品。真正好用的是一个能接相机实时取流、自动检测、自动筛选、自动标定的工具。这样现场人员只需要举着棋盘格在镜头前摆几个姿势,程序自己判断哪些角度合格,检测合格的帧自动存入数据集。
using var cap = new VideoCapture(0); cap.Set(VideoCaptureProperties.RtspTransport, 1); // 网络相机强制 TCP int savedCount = 0; while (savedCount < 20) { using var frame = new Mat(); cap.Read(frame); if (frame.Empty()) continue; using var gray = new Mat(); Cv2.CvtColor(frame, gray, ColorConversionCodes.BGR2GRAY); bool found = Cv2.FindChessboardCorners(gray, new Size(9, 6), out var corners); if (found) { Cv2.DrawChessboardCorners(frame, new Size(9, 6), corners, found); Cv2.ImWrite($"calib_{savedCount:00}.jpg", frame); savedCount++; Console.WriteLine($"已采集 {savedCount}/20 张"); } Cv2.ImShow("preview", frame); if (Cv2.WaitKey(30) == 'q') break; }这段代码的核心逻辑是:每一帧先做棋盘格检测,找到角点才保存,保存时把检测结果画上去方便肉眼确认。角点检测成功的帧才进入数据集,从源头避免无效数据。采集完成后,再跑第二节和第三节里的批量标定逻辑。这个自动筛选思路在工业现场特别好用,操作人员不需要理解内参与畸变的区别,只知道“绿灯亮就换一个角度”就够了。
6.2 鱼眼相机标定和双目相机标定怎么延伸
普通 CalibrateCamera 的针孔模型加上五个畸变参数,适合视角在 60 到 90 度之间的常规镜头。如果项目里用的是鱼眼镜头,或者视角超过 120 度的广角镜头,同一个接口标出来的结果会非常差。OpenCvSharp 里鱼眼相机标定要走 Cv2.Fisheye.Calibrate,它使用完整的鱼眼畸变模型,径向畸变系数有四个(k1 到 k4),没有切向畸变项。鱼眼相机的标定数据要求也更高,图像数量通常要 20 张以上,且需要更多贴近画面边缘的姿态。
双目相机标定是在单目内参的基础上做立体标定,调用 Cv2.StereoCalibrate 得到左右相机之间的旋转矩阵和平移向量,再通过 StereoRectify 生成重投影矩阵 Q。这个矩阵是后续双目视差测距的基础。做双目之前,左右两个相机必须单独先用棋盘格标定内参,并且左右图像的分辨率不能不一致。
6.3 用一把尺子验证内参准确性:最后一步的习惯
重投影误差和去畸变图像都验证通过之后,我还会做一个物理验证。拿一把已知长度的直尺,放在相机前方固定距离处,拍一张去畸变后的图像,量尺子两端在图像中的像素距离。相机到尺子的距离 Z 已知,理论上两端点距离应该等于物理长度乘以 fx / Z。如果测量值和理论值偏差在 2% 以内,标定结果就可以放心投给测量项目;偏差超过 5%,就要检查厚度或图像数量了。
这个习惯帮我避免过不止一次“参数看着对、实测偏一截”的返工。标定工作的最后一件事,是把参数文件重命名为带相机型号、镜头焦距、分辨率和日期的格式再归档。我吃过亏:一次现场调试换了个同型号相机,以为参数通用,结果对焦差异让测量直接超差。从那以后,每一份内参都记录设备信息,换设备就重新标定。
希望这些流程和踩坑记录能帮你少走一段弯路。棋盘格标定这件事本身不难,但每一步都可能有反直觉的细节在等着。把数据拍扎实、把参数写明白,标定助手才能真正成为你项目里的可靠环节,希望帮到你。
本文还有配套的精品资源,点击获取