4. 相机内参标定:HALCON相机标定流程、内参矩阵与畸变系数、标定结果评价

相机内参标定,说白了就是搞清楚你的相机到底长什么样。焦距多少?像素中心在哪?镜头畸变有多严重?这些参数如果不准,后面的手眼标定全是白搭。我见过太多项目,标定误差大得离谱,最后查来查去,根子就在内参没标好。

这一节,我们就把HALCON的标定流程掰开揉碎,讲清楚每一步该怎么做,以及怎么判断标定结果到底行不行。

4.1 HALCON标定流程:从拍照到出参

HALCON的标定流程其实不复杂,但细节很多。我个人习惯把流程分成四个阶段:准备、采集、计算、验证。

核心流程速览

  1. 准备标定板——生成描述文件,打印或购买高精度板
  2. 采集图像——不同位姿拍15-20张
  3. 提取角点——用find_caltab和find_marks_and_pose
  4. 计算内参——调用camera_calibration
  5. 验证结果——看重投影误差,做残差分析

嗯,这里要注意:标定板的质量直接决定标定上限。我曾经用打印的标定板做过实验,结果重投影误差死活下不去0.5像素。换成陶瓷基板的高精度标定板,同样的流程,误差直接降到0.1像素以内。

4.2 内参矩阵:相机内部的"坐标系"

内参矩阵,就是描述相机内部几何关系的3x3矩阵。HALCON里用campar这个数组来表示,包含以下参数:

参数 符号 含义 典型值范围
焦距 f 镜头焦距(像素单位) 1000-5000
主点x cx 图像中心x坐标 图像宽度/2
主点y cy 图像中心y坐标 图像高度/2
像素宽高比 sx 像素的宽高比 1.0(方形像素)
倾斜因子 skew 像素轴倾斜度 0.0(理想情况)

你想想看,如果主点偏差了10个像素,那在图像边缘的测量误差会被放大多少倍?这就是为什么内参标定不能马虎。

HALCON里获取内参矩阵的代码很简单:

* 从标定结果中提取内参
get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam)

* 查看内参
disp_message (WindowHandle, '焦距: ' + CamParam[0] + ' 像素', 'window', 12, 12, 'black', 'true')
disp_message (WindowHandle, '主点: (' + CamParam[1] + ', ' + CamParam[2] + ')', 'window', 36, 12, 'black', 'true')

4.3 畸变系数:镜头不是完美的

没有镜头是完美的。畸变主要分两类:径向畸变和切向畸变。HALCON支持多种畸变模型,最常用的是多项式模型和除法模型。

我的经验:对于普通工业镜头,用多项式模型(k1, k2, k3三个径向系数)就够了。鱼眼镜头才需要除法模型。别一上来就选高阶模型,参数多了反而容易过拟合。

畸变系数在HALCON的campar数组里排在后面:

  • k1, k2, k3:径向畸变系数(k1主导桶形/枕形畸变)
  • p1, p2:切向畸变系数(镜头与传感器不平行导致)

我曾经遇到过一个案例:标定出来的k1是负值,而且值很大。一开始以为是标定错了,后来检查发现——镜头装歪了。重新安装后,k1恢复正常。所以,畸变系数不只是数学参数,它还能帮你诊断硬件问题。

4.4 标定结果评价:别只看重投影误差

标定完了,怎么知道结果好不好?很多人只看重投影误差(RMS),觉得小于0.3像素就万事大吉。其实不然。

我个人习惯从三个维度评价标定结果:

  1. 重投影误差——每个角点的检测位置和投影位置的偏差
  2. 参数稳定性——换一组标定图像,参数变化大不大
  3. 物理合理性——焦距、主点、畸变系数是否在合理范围内

避坑指南:我曾经只盯着重投影误差看,标定结果RMS只有0.08像素,觉得完美了。结果换到实际场景,测量误差直接飙到0.5毫米。后来才发现,标定板只拍了中心区域,边缘畸变根本没标出来。所以,标定图像的位姿分布比RMS值更重要。

HALCON里查看重投影误差的方法:

* 获取所有标定图像的误差
get_calib_data_observ_contours (CalibDataID, 'caltab', 0, 'all', Contours)
get_calib_data_observ_points (CalibDataID, 'caltab', 0, 'all', Row, Column, Index, Pose)

* 计算每个角点的重投影误差
for I := 0 to |Row| - 1 by 1
    project_3d_point (X[I], Y[I], Z[I], CamParam, Pose[I], RowProj, ColProj)
    Error := sqrt((Row[I] - RowProj)^2 + (Column[I] - ColProj)^2)
    * 记录误差
endfor

4.5 标定流程的SVG框架图

下面这张图把整个标定流程串起来了,你可以对照着看:

HALCON相机内参标定流程 1. 准备标定板 2. 采集标定图像 3. 提取角点 4. 计算内参 5. 验证结果 不满足精度 → 重新采集或调整流程 输出:内参 + 畸变系数 关键要点 • 标定板位姿要覆盖图像各个区域(中心、边缘、倾斜) • 至少15张图像,位姿差异要大 • 重投影误差 < 0.3 像素为合格,< 0.1 像素为优秀 • 检查畸变系数是否在合理范围(k1通常在 -0.5 ~ 0.5)

4.6 标定结果评价的量化指标

光说"好"或"不好"不够,得有数据说话。我整理了一个评价表格,你可以对标自查:

评价指标 优秀 合格 不合格 检查方法
重投影误差RMS < 0.1 像素 0.1 - 0.3 像素 > 0.3 像素 get_calib_data
最大单点误差 < 0.3 像素 0.3 - 0.8 像素 > 0.8 像素 逐点计算
焦距稳定性 变化 < 1% 变化 1% - 3% 变化 > 3% 多次标定对比
主点偏移 < 5 像素 5 - 15 像素 > 15 像素 与图像中心对比
畸变系数k1 -0.1 ~ 0.1 -0.3 ~ 0.3 超出范围 查看campar[5]

小技巧:标定完成后,我习惯把标定板放在视场中心拍一张,然后用rectify_image做畸变校正。如果校正后的标定板边缘还是弯的,说明畸变模型没选对,或者标定图像不够覆盖边缘区域。

最后说一句:内参标定不是一次性工作。镜头松动、温度变化、焦距调整,都会导致内参漂移。我建议每次做手眼标定之前,都重新标定一次内参。别嫌麻烦,这点时间省不得。