2. 标定板选择与设计

做深度图标定,第一步不是调参数,而是选对板子。我见过不少项目,算法调了大半个月,最后发现是标定板本身就不合适——那种挫败感,嗯,一次就够了。

标定板说白了,就是给相机看的“尺子”。它必须提供高精度的已知特征点。在Halcon里,我们主要跟三种板子打交道:圆点阵、棋盘格、编码点。它们各有脾气,选错了,标定精度直接打折。

核心原则:标定板的精度决定了标定结果的天花板。算法只能逼近这个上限,无法超越。

2.1 三大标定板的核心差异

先看一张对比表,心里有个底:

类型 特征提取方式 亚像素精度 抗遮挡能力 大倾角鲁棒性 制作成本
圆点阵 椭圆拟合 + 中心定位 极高(0.01~0.03 pixel) 弱(遮挡半个圆就废) 强(椭圆模型自适应) 低
棋盘格 角点检测 + 亚像素精化 高(0.05~0.1 pixel) 中(遮挡角点附近受影响) 中(大倾角角点模糊) 低
编码点 圆形识别 + 码值解码 高(0.03~0.05 pixel) 强(部分遮挡仍可解码) 强(单点独立定位) 高

2.2 圆点标定板:精度之王,但娇气

我个人最常用的是圆点板。为什么?因为Halcon对圆点的支持太成熟了。find_calib_object 配合 calibrate_cameras,一套流程走下来非常顺。

圆点的优势在于亚像素精度。它通过拟合整个椭圆边缘来定位中心,而不是只依赖几个像素的梯度。这意味着,在图像质量好的情况下,重复性精度可以做到0.02像素以内。

我的习惯:做高精度3D重建(比如手机中框检测)时,我首选陶瓷基板的圆点阵。玻璃基板反光太严重,容易引入系统误差。

但圆点有个致命弱点:怕遮挡。我在一个机械臂抓取项目里吃过亏——标定板边缘被夹具挡住了一个圆,结果那一帧的标定直接失败。Halcon的 find_calib_object 默认要求所有圆点可见,除非你手动设置 'all_caltab_marks_visible' 为 false。

* Halcon示例:圆点标定板创建与检测
create_calib_data ('calibration_object', 1, 1, CalibDataID)
* 设置圆点板参数:7x7阵列,间距12.5mm,圆点直径6.25mm
set_calib_data_calib_object (CalibDataID, 0, 'caltab_marks_spacing', 0.0125)
set_calib_data_calib_object (CalibDataID, 0, 'caltab_marks_diameter', 0.00625)
set_calib_data_calib_object (CalibDataID, 0, 'caltab_marks_rows', 7)
set_calib_data_calib_object (CalibDataID, 0, 'caltab_marks_columns', 7)

* 检测标定板
find_calib_object (Image, CalibDataID, 0, 0, 0, [])
get_calib_data_observ_contours (Contours, CalibDataID, 'caltab', 0, 0, 0)
避坑指南:圆点板对光照均匀性要求极高。我曾经在环形光源下用圆点板,边缘的圆点因为反光变成了“月牙形”,拟合出的中心偏了0.3像素。后来换成背光照明,问题才解决。

2.3 棋盘格标定板:皮实耐用,但精度有上限

棋盘格是入门首选。它制作简单,用打印机打出来贴在平板上就能用。但你要清楚,它的精度上限不如圆点板。

为什么?角点检测本质上只用了角点附近4个像素区域的梯度信息。而圆点拟合用了整个边缘的几百个像素。信息量不在一个量级。

不过棋盘格有个好处:鲁棒。我在现场调试时,经常遇到光照变化剧烈的情况。圆点板可能因为反光导致边缘断裂,但棋盘格的角点——只要黑白对比还在,就能找到。

场景 推荐板型 理由
实验室高精度标定 圆点阵 亚像素精度最高
现场快速标定 棋盘格 对光照、倾角容忍度高
大视场/多相机 编码点 部分遮挡不影响全局
热成像/低分辨率 棋盘格 角点比圆点更容易识别

2.4 编码点标定板:大场景的救星

编码点是我做多相机拼接时的首选。每个点自带ID,即使视场里只看到3个点,也能唯一确定它们在标定板上的位置。

你想想看,如果用圆点板做1米×1米的大标定板,相机稍微偏一点,边缘的圆点就出画了。但编码点不一样——每个点都是独立的“路标”。

Halcon里编码点的处理流程稍微复杂一点:

* 编码点检测流程
create_calib_data ('calibration_object', 1, 1, CalibDataID)
* 加载编码点描述文件(.cpd文件)
set_calib_data_calib_object (CalibDataID, 0, 'caltab_marks_file', 'coded_pattern.cpd')

* 检测时,Halcon会自动解码每个点的ID
find_calib_object (Image, CalibDataID, 0, 0, 0, [])
* 获取解码后的点坐标和ID
get_calib_data_observ_points (CalibDataID, 0, 0, 0, Row, Col, Index, Pose)
经验之谈:编码点的码值设计很关键。我建议用12位环形码,容错率比二进制码高。另外,编码点的背景最好是哑光黑,反光会导致解码失败。

2.5 选型决策流程

说了这么多,到底怎么选?我画了一张决策图,帮你快速定位:

标定板选型决策流程 开始选型 精度要求 > 0.05 pixel? 是 否 圆点阵(陶瓷基板) 棋盘格(打印即可) 多相机 / 大视场? 是 否 编码点标定板 圆点阵(标准) 现场光照恶劣? 是 否 棋盘格(高对比) 圆点阵 / 棋盘格 提示:编码点成本高,但多相机标定时省下的调试时间远超板子差价

2.6 标定板设计的几个硬指标

不管选哪种板子,设计时这几个参数必须算清楚:

  1. 特征点数量:我建议至少12个点。太少的话,Halcon的 calibrate_cameras 在优化畸变参数时容易陷入局部最优。
  2. 特征点间距:占视场宽度的1/10~1/8。太密了,标定板稍微倾斜点,特征点就糊成一团;太疏了,标定板覆盖区域不够。
  3. 背景与特征对比度:至少1:5。我见过有人用灰色背景配白色圆点,Halcon的阈值分割根本分不开。
  4. 平面度:这是最容易被忽略的。3D打印的标定板,平面度可能只有0.1mm。对于深度图标定来说,这误差直接进了系统。
我曾经踩过的坑:用亚克力板做基材,贴打印的棋盘格。结果亚克力本身有0.3mm的弯曲,标定出来的内参在视场边缘差了2个像素。后来换了5mm厚的碳纤维板,问题才解决。记住:标定板的平面度至少要比你期望的标定精度高一个数量级。

2.7 Halcon中的标定板文件格式

Halcon支持两种描述标定板的方式:

格式 扩展名 适用场景 创建方式
描述文件 .descr 圆点阵、棋盘格 gen_caltab 算子生成
编码点文件 .cpd 编码点标定板 Halcon标定助手导出

我个人习惯用 gen_caltab 生成描述文件,然后交给加工厂制作。这样能保证算法里的参数和实物完全一致。

* 生成圆点标定板描述文件
gen_caltab (7, 7, 0.00625, 0.0125, 'caltab_7x7.descr', 'caltab_7x7.ps')
* 参数说明:7行7列,圆点直径6.25mm,间距12.5mm
* 会同时生成 .descr(Halcon用)和 .ps(打印用)两个文件

嗯,选对板子,标定就成功了一半。下一件重要的事,就是怎么把板子摆好、拍好——这部分我们留到后面细聊。