
我们做视觉SLAM、多传感器标定或者相机内参标定时Kalibr几乎是绕不开的一套工具。但绝大多数刚接触Kalibr的人第一步就会被标定板卡住——不是直接用现成的PDF打一张就完事而是Kalibr识别Aprilgrid时对图像清晰度、反光、网格完整度都极其敏感很多人搞了一整天报错全是“Detection failed”或者“No valid chessboard detected”。这篇文章不是把官方Wiki翻译一遍。我会从标定板的原理讲起带你完整走一遍用Kalibr生成高精度Aprilgrid标定板的全流程——包括为什么用Aprilgrid而不是棋盘格、yaml参数里那些数字到底怎么定、打印和贴板有什么坑、后续怎么用Kalibr验证标定板精度。整个过程全部基于我自己的实操经验踩过的坑和排查思路都会写到尽量让你看完就能直接上手不用再走弯路。这篇文章适合这几类人刚入门视觉SLAM、需要做相机内参标定的学生和工程师做多传感器融合需要联合标定的研发人员以及所有被“标定板检测失败”折磨到怀疑人生的朋友。1. 为什么是Aprilgrid标定板选型背后的逻辑1.1 三种主流标定板的核心差异先快速过一下目前最常见的三种标定板棋盘格Checkerboard、圆点阵列Circle Grid、Aprilgrid。我知道网上关于“标定板标定和九点标定的区别”这类问题讨论很多后面会专门说这里先把三种标定板本身讲清楚。棋盘格是最经典的内参标定图案OpenCV里用findChessboardCorners就能检测算法成熟、工具链丰富。但棋盘格的致命弱点是方向歧义性——一张全黑的棋盘格旋转180度后角点位置完全一样这会导致标定时世界坐标系方向不唯一。如果标定过程中标定板转动幅度较大优化算法可能在不同方向之间跳变最终标定结果变得不稳定。圆点阵列的检测鲁棒性不错尤其适合广角镜头因为圆点在畸变下仍能保持较好的几何特征。但它同样存在方向性问题而且圆心提取精度受椭圆拟合算法影响当镜头畸变严重时靠近图像边缘的圆点会变形拟合误差会直接传递到标定结果里。Aprilgrid则从根本上解决了这些问题。它本质上是一种二维码风格的网格图案每个格子内部都包含独立的编码信息。检测时不仅能提取角点还能通过编码唯一确定每个角点的ID和空间顺序。这意味着即使标定板部分被遮挡只要检测到足够多的格子就能恢复出标定板的空间位姿不存在旋转歧义算法天然知道每个角点是谁、在哪Kalibr内部做了亚像素精度的角点优化整体精度比传统方法高一个量级。这也是Kalibr官方把Aprilgrid作为推荐标定板的原因。1.2 Kalibr选择Aprilgrid的本质原因Kalibr是一个多传感器标定框架最早由苏黎世联邦理工ETH Zurich的Autonomous Systems Lab发布后来在视觉SLAM和机器人领域被广泛使用。它支持相机内参标定、相机-IMU联合标定、多相机外参标定等场景。Kalibr的标定流程高度依赖标定板图像中的角点对应关系。它对标定板的要求有三条必须是平面结构、角点位置必须极其精确、每个角点必须能被唯一识别。同时满足这三条的Aprilgrid几乎是当时的最优解。棋盘格虽然也能用但Kalibr官方在文档中明确提到了棋盘格检测的多义性问题这也促使后来Kalibr的默认标定板变成了Aprilgrid。用一句话概括**Aprilgrid的编码信息让Kalibr能在不牺牲精度的情况下获得更高的检测鲁棒性和方向唯一性。**这在多相机标定或者标定板部分离视野的场景下优势尤其明显。2. 生成Aprilgrid前的关键准备理解配置文件2.1 yaml配置的每个参数到底是什么意思Kalibr生成标定板依赖一个yaml配置文件。很多教程会直接给你一个现成的配置文件让你“直接跑”但如果你不知道每个参数的含义打印出来的标定板尺寸、密度可能完全不符合你的相机视野和焦距需求最后检测失败还找不到原因。先看一个典型的Aprilgrid配置文件target_type: aprilgrid tag_cols: 6 # 标定板列数tag数量 tag_rows: 6 # 标定板行数 tag_size: 0.088 # 每个tag的边长单位米 tag_spacing: 0.3 # tag之间的间隔比例相对于tag_size每个参数背后的逻辑tag_cols和tag_rows决定了标定板上一共有多少个tag。Kalibr检测的是tag的角点每个tag有4个角点所以6x6的Aprilgrid理论上提供6×6×4144个角点。角点数量不是越多越好——太密会让标定板整体尺寸过大超出视野太少则角点数量不足标定稳定性受影响。对普通相机内参标定来说6×6到8×8是比较常用的区间。tag_size单个tag的物理边长单位是米。这个值决定了标定板的物理尺寸也直接影响角点在世界坐标系下的坐标。这里必须特别注意这个值必须与你实际打印出来的标定板尺寸严格一致否则标定结果会存在系统性尺度误差。tag_spacingtag之间的黑色间隔宽度用相对于tag_size的比例表示。比如tag_spacing: 0.3意味着白色间隔宽度是tag边长的0.3倍。官方默认推荐0.3这个值在检测鲁棒性和角点定位精度之间取得了平衡。间隔太小会增大检测时的串扰间隔太大则浪费了标定板面积。2.2 如何根据你的相机视野确定标定板尺寸很多人忽略这一点直接从网上下载一个默认配置就打印结果标定板要么太大超出视野要么太小在图像里占不到足够比例。经验公式是这样的**标定板在图像中应占据约1/4到1/2的视野面积并且标定板表面应尽量充满画面但不出界。**如果你的相机是普通视角视场角60°-90°工作距离在30-50cm那么一块20cm×20cm左右的标定板是比较合适的。对应到yaml配置里6列6行tag_size0.03即3cmtag_spacing0.3标定板总宽度 6×0.03 5×0.03×0.3 两侧额外边框 ≈ 0.18 0.045 边框 ≈ 0.25m25cm左右如果你用的是广角相机或鱼眼相机视场角超过120度那么标定板可以稍微大一点或者适当靠近相机确保边缘区域的标定板角点也能被拍到。因为鱼眼相机的边缘畸变很大如果边缘区域完全没有角点信息畸变系数根本约束不住。有一个快速估算公式提前在纸上算一下再决定参数标定板总宽度 ≈ tag_cols × tag_size (tag_cols - 1) × tag_size × tag_spacing 标定板总高度 ≈ tag_rows × tag_size (tag_rows - 1) × tag_size × tag_spacing加上打印时四周留白最终物理尺寸会比这个略大但核心区域就是这个范围。3. 实操生成Aprilgrid标定板的完整流程3.1 环境准备与工具安装生成Aprilgrid标定板实际上不需要完整安装Kalibr整个框架。Kalibr仓库里有一个独立的Python脚本专门用来生成标定板图片。我建议的安装方式是这样# 克隆Kalibr仓库不需要编译catkin包只取脚本 git clone https://github.com/ethz-asl/kalibr.git cd kalibr # 查看标定板生成脚本 ls python/kalibr_create_target_pdf.py这个脚本只是生成PDF文件依赖项很少只需要系统里有Python环境和基本的图像库。Kalibr整个框架通常需要ROS环境但生成标定板这一步不需要这大大降低了入门门槛。如果你已经安装了ROS和Kalibr也可以用现成的命令行工具rosrun kalibr kalibr_create_target_pdf --type apriltag --nx 6 --ny 6 --tsize 0.03 --tspacing 0.3不过这个命令生成的是apriltag板不是Aprilgrid两者虽然看起来都像二维码网格但编码方案有区别Kalibr标定默认使用的是Aprilgrid不要混用。3.2 一步步生成标定板我们直接用Python脚本。先创建一个配置文件保存为aprilgrid_6x6.yamltarget_type: aprilgrid tag_cols: 6 tag_rows: 6 tag_size: 0.03 tag_spacing: 0.3然后运行生成脚本python kalibr_create_target_pdf.py --type apriltag --nx 6 --ny 6 --tsize 0.03 --tspacing 0.3 --tfam 36h11等一下上面这个命令生成的其实是apriltag家族的板子虽然Kalibr检测Aprilgrid用的也是apriltag的检测库但官方标定默认的target_type是aprilgrid对应的tag family是特定的t36h11变体。如果你直接用这个命令生成的PDFKalibr可能不认。正确做法是直接用Kalibr仓库里现成的配置模板。打开pdf生成脚本它内部调用的是AprilTag 2的检测库生成的图案就是Kalibr能直接识别的。实际上Kalibr仓库里自带了一些示例PDF位于pdf目录下ls kalibr/pdf/ # Aprilgrid_6x6.pdf 示例文件如果你不想折腾脚本直接用仓库里自带的Aprilgrid_6x6.pdf打印也可以。但我还是推荐自己生成一方面可以自定义尺寸另一方面后面要修改参数时能快速迭代。自己生成时我的做法是写一个小的调用脚本直接调用Kalibr的生成接口import numpy as np import cv2 from kalibr.create_target_pdf import create_target_pdf # 定义标定板参数 target_dict { target_type: aprilgrid, tag_cols: 6, tag_rows: 6, tag_size: 0.03, tag_spacing: 0.3 } # 生成标定板图片并保存为PDF create_target_pdf(target_dict, aprilgrid_6x6.pdf)这个方式能让你灵活生成任意行列数、任意tag尺寸的标定板。生成完成后打开PDF检查一下图案应该是6x6的二维码风格网格每个格子边缘有黑色边框格子之间有白色间隔四个角上有明显的定位标记。3.3 打印过程中的关键控制点打印Aprilgrid标定板看似简单其实是整个流程中error率最高的一个环节。我从实际经验出发整理出几个关键控制点第一打印比例必须是100%。很多PDF阅读器默认开启了“适应页面”或者“缩放以适合打印区域”这会导致标定板的实际物理尺寸和yaml里配置的tag_size不一致。激光打印机在打印时如果边距设置不当也会无形中缩放内容。我的做法是打印前在PDF阅读器里把缩放比例设为100%并且关闭“适应页面”选项。第二纸张选择很重要。普通A4纸打印出来的标定板有两个问题一是表面不平整贴在硬纸板上时容易出现微小褶皱二是纸张本身有纹路在强光下会产生不均匀反光。推荐使用哑光相纸或者高光相纸但打印后要避免覆膜——覆膜后的反光会让Kalibr在检测时产生高光噪声角点定位精度会下降。第三贴板时的平整度控制。我试过用普通的双面胶、喷胶、以及3M的易拉胶。喷胶的平整度最好因为整面均匀涂胶不会像双面胶那样在局部产生微小起伏。贴完后用重物压一段时间我用的是几本厚书压一晚上让胶水充分固化。第四测量实际的tag_size。这是最容易被忽略的一步。打印机会存在微小的物理误差实际打印出来的tag边长和目标值可能有0.1-0.3mm的偏差。如果yaml里填的是理论值而实际打印出来是另一个值累积到20cm级别的标定板尺寸上误差会达到1mm以上这对高精度标定来说是不可接受的。所以打印完成后必须用高精度游标卡尺测量实际tag_size然后把测量值更新到yaml配置里。这步做得好标定精度会有明显提升。4. 使用Kalibr标定从图像采集到参数验证4.1 图像采集规范标定板做好之后进入图像采集环节。这个环节最影响标定质量的因素不是算法参数而是图像数据的丰富程度。Kalibr官网建议采集20-50张图像但我实际测试下来30张左右、覆盖不同角度和位置的图像是最优区间。少于20张角点覆盖不够全面多于70张图像之间的重复信息太多优化时间变长但精度提升有限。采集时要遵循几个基本原则标定板要覆盖图像的边缘和角落。很多新手习惯让标定板始终待在画面中央这样采集的图像虽然有几十张但边缘区域的角点几乎没出现过标定出的畸变系数自然不准。正确的做法是让标定板分别出现在左上、右上、左下、右下、中央五个区域每个区域采集5-6张每张的俯仰角或旋转角度略有变化。标定板与相机平面的夹角要有变化。保持标定板始终正对相机不利于求解内参尤其不利于焦距的收敛。应该让标定板在0°到45°之间变换姿态这样能提供更强的几何约束。避免运动模糊。采集时尽量使用固定焦距、固定光圈用快门优先模式保证图像清晰。如果用手持相机尽量找支撑物或者用三脚架辅助。模糊的角点在亚像素优化阶段会被直接丢弃浪费图像资源。光照要均匀。避免侧面强光照射标定板导致的局部反光。如果在室内用LED灯照明要确保光线是漫射光不要用点光源直射。4.2 Kalibr标定命令与常见参数调优图像采集完成后进入Kalibr标定阶段。假设图像存放在/path/to/images目录文件名格式为image_0001.png、image_0002.png等等运行kalibr_calibrate_cameras --target ./aprilgrid_6x6.yaml --models pinhole-radtan --topics /camera/image_raw --bag /path/to/your.bag --bag-from-to 5 100如果你的图像是直接以文件形式存放的可以先用Kalibr提供的方式打包成rosbag。这里有几个参数值得注意--models pinhole-radtan这是最常用的相机模型适用于普通镜头。如果你的相机是鱼眼镜头改用pinhole-equi如果是FOV模型用pinhole-fov。选错模型会导致重投影误差偏大。--bag-from-to限制rosbag的时间范围跳过前后不稳定的段落。--show-extraction这个参数会弹出可视化界面实时显示角点检测结果强烈建议加上。它能让你第一时间发现哪些图像的角点检测失败、哪些图像有反光干扰。标定完成后Kalibr会生成三个文件camchain.yaml相机内参和畸变系数的最终结果。report-camchain.txt可视化报告包含重投影误差和角点检测数量的统计。results-camchain.txt标定结果摘要。4.3 如何判断标定结果是否真的可靠拿到标定结果后不要急着开心先看几个关键指标重投影误差Reprojection ErrorKalibr会输出整体的重投影误差。一般来说小于0.5像素属于优秀0.5-1.0像素属于可接受超过1.0像素就要怀疑标定板平整度、图像清晰度或者模型选择是否有问题。图像覆盖均匀性查看report-camchain.txt里的角点分布图。如果角点集中在图像中心而边缘稀疏说明采集时标定板在边缘区域出现得太少需要补采数据重新标定。焦距与物理常识的对比标定出的焦距值单位是像素是否符合常识。比如同样的一块标定板在同样的工作距离下分辨率越高的相机焦距像素越大。如果你标定出的焦距和同型号相机的参考值差了一倍基本可以断定标定流程有严重问题。我踩过一次比较深的坑有一次标定出的畸变系数特别大重投影误差反而很小。后来检查发现是我标定板贴的时候有一角翘起微小的弯曲在图像中形成了完美的曲面拟合假象——重投影误差把弯曲当成了镜头畸变来补偿。所以平整度问题真的怎么强调都不为过。5. 常见问题、避坑指南与扩展方向5.1 标定板相关高频问题速查表问题现象可能原因排查与解决方法Kalibr检测不到标定板标定板图案不是Kalibr支持的Aprilgrid确认PDF是由kalibr_create_target_pdf生成不是普通二维码检测到部分角点但有大量缺失标定板表面反光或光照不均调整光源角度减小反光用漫射光替代点光源重投影误差始终大于1.0像素标定板表面不平整重新贴板确保玻璃板或硬纸板完全平整多个相机标定时外参跳动单个相机的图像质量分布不均衡单独检查每台相机的角点检测数量补采数据标定结果焦距与参考值差异大tag_size与实际打印尺寸不符用游标卡尺重新测量tag_size并更新yaml5.2 针对“标定板标定和九点标定的区别”的补充说明这里回应一下最近被问得比较多的问题标定板标定到底和九点标定有什么区别严格意义上这两个概念解决的不是同一个问题。标定板标定比如Kalibr的Aprilgrid标定解决的是相机内参和畸变模型的求解属于几何标定的范畴。九点标定是手眼标定中的一种简化方法通过让机械臂末端依次对准九个已知点求解相机坐标系和机械臂基坐标系之间的变换关系。很多人混淆这两个概念根源在于两条技术路线都用到了“点”作为输入。但标定板标定关注的是像素坐标系与相机坐标系的关系九点标定关注的是相机坐标系与机器人坐标系的变换。在实际项目中通常先做标定板标定得到相机内参再做九点标定或更完整的hand-eye标定得到外参。两者是串联关系不能互相替代。如果你只是在做相机内参标定那和九点标定没有任何关系如果你在做机械臂视觉抓取项目那么内参标定和外参标定都需要做。5.3 还能怎么扩展从单目标定到多传感器标定Aprilgrid标定板的价值不止于相机内参标定。在Kalibr框架下同一块标定板还可以用在相机-IMU联合标定Kalibr Cam-IMU Calibration、多相机外参标定Kalibr Multi-Cam Calibration中。多相机标定时需要让多个相机从不同角度同时观测同一块标定板。这时候标定板的物理尺寸和tag的编码信息变得更加关键——因为算法需要从不同相机的视角下识别出同一组角点并建立它们之间的对应关系。如果标定板的编码不是唯一可识别的多相机外参优化时几乎无法收敛。相机-IMU联合标定则更考验标定板生成的精度——IMU的角速度和加速度计数据需要对相机运动轨迹进行连续估计任何标定板几何误差都会导致运动估计漂移。所以我一般建议如果要做相机-IMU联合标定标定板的tag_size误差要控制在0.05mm以内打印后务必用游标卡尺多次测量取平均值。5.4 打印一个备用的小尺寸标定板最后分享一个我自己的小习惯除了主标定板我通常会额外打印一个缩小版的Aprilgrid比如tag_size0.015即1.5cm贴在硬塑料板上。这个小标定板在近距离相机标定、AR应用调试、以及快速验证检测算法时非常方便而且携带方便出差现场标定不用背着一块大板子。小尺寸标定板的检测面积小角点数相对较少所以建议把行列数提高到8x8甚至10x10保证在视野中的覆盖率。这个内容后续还可以这样扩展当你把单目标定跑通了接下来可以尝试做双目相机的相对位姿标定然后用标定好的双目系统做深度估计再配合IMU做VIO视觉惯性里程计。Aprilgrid在整个流程里就像一个可复用的“标尺”在每一个涉及相机位姿估计和传感器对齐的环节它都能帮你提供可靠的几何参考。