2. HALCON标定基础与算子体系

在HALCON中做多相机标定,第一步不是急着写代码,而是把“相机模型—内外参—畸变—标定板”这条概念链理顺。HALCON的标定算子体系正是围绕这条链设计的:find_calib_object负责从图像中提取标定板标记点,calibrate_cameras负责把多组观测点解算成相机参数,camera_calibration则把标定结果固化为可复用的相机参数对象。理解这些算子的输入输出关系,比死记算子名更重要。

相机模型:从世界点到像素的映射

HALCON默认使用针孔相机模型(pinhole camera model),并可选叠加畸变模型。其核心是把三维世界点 Pw = (Xw, Yw, Zw) 依次经过外参、内参投影到像素坐标 (u, v)。外参描述相机在世界坐标系中的位姿,由旋转矩阵 R 和平移向量 t 组成;内参描述相机自身的成像特性,包括焦距 f、像元尺寸 sx, sy、主点 (cx, cy) 以及图像宽高。HALCON把内参和外参统一封装在相机参数元组中,顺序为:[Focus, Kappa, Sx, Sy, Cx, Cy, ImageWidth, ImageHeight],其中 Kappa 是径向畸变系数,若为0表示无畸变。

需要特别注意的是坐标系约定:HALCON图像坐标系原点在左上角,u向右、v向下;相机坐标系中Z轴指向观察方向,X向右、Y向下。世界坐标系由标定板定义,标定板平面通常取Zw = 0。全文及图示均遵循这一约定,切换参照系时必须显式说明。

内参与外参:谁决定什么

内参决定“投影形状”,外参决定“相机在哪、朝哪”。在多相机系统中,每个相机有独立的内参,而外参有两种常见表达:一是各相机相对于同一世界坐标系的外参,二是相机之间的相对位姿。HALCON的calibrate_cameras默认输出每个相机相对于第一个相机(或指定参考相机)的外参,便于后续做立体校正和三维重建。

内参标定的质量主要取决于标定板在视场中的覆盖范围:标定板应出现在图像的不同位置、不同倾角、不同距离,且尽量覆盖图像四角。若只在图像中心拍几张,主点和畸变系数会解算不准。外参标定则要求所有相机同时看到同一标定板,或通过固定标定板、移动相机的方式获得足够约束。

畸变模型:径向为主,切向可选

HALCON标准标定主要处理径向畸变,用Kappa一个参数描述,适用于大多数工业镜头。若镜头畸变复杂,可启用change_radial_distortion_cam_par或使用扩展畸变模型(如Division模型、多项式模型)。畸变校正的调用逻辑是:先用calibrate_cameras得到含Kappa的相机参数,再用change_radial_distortion_image对图像做去畸变,或用change_radial_distortion_points对点坐标做校正。判断畸变是否可接受,可观察标定板直线在图像边缘是否明显弯曲;若弯曲超过1~2像素,应重新标定或更换模型。

标定板类型与算子调用逻辑

HALCON支持多种标定板:标准圆点阵列板、棋盘格板、Halcon自带的calplate描述文件,以及自定义标定板。圆点板通过find_calib_object提取圆心,棋盘格通过find_calib_object的Chessboard模式提取角点。标定板描述文件(.descr)记录了标记点数量、间距、行列数,必须与实物一致,否则解算出的内参会有系统偏差。

典型调用链为:gen_cam_par_area_scan_division生成初始相机参数 → 循环读取图像并find_calib_object提取标定板姿态 → calibrate_cameras解算 → get_calib_data取出内外参 → camera_calibration生成可复用参数对象。多相机时,把各相机的标定数据放入同一个CalibDataID,一次calibrate_cameras即可同时优化所有相机参数和相对外参。

HALCON标定算子调用逻辑与数据流 标定板 圆点/棋盘格 .descr描述文件 多相机图像 不同位姿/倾角 覆盖视场四角 find_calib_object 提取标记点/角点 输出观测点坐标 CalibDataID 累积多相机观测 统一标定数据容器 calibrate_cameras 非线性优化:内参+外参+畸变 多相机联合解算 内参 CamPar Focus, Kappa Sx, Sy, Cx, Cy ImageWidth/Height 外参 Pose 相机相对世界位姿 相机间相对位姿 旋转R + 平移t 畸变参数 Kappa 径向畸变 可选切向/多项式 去畸变校正依据 调用顺序:gen_cam_par_area_scan_division → find_calib_object → calibrate_cameras → get_calib_data → camera_calibration

实操示例:双相机标定的参数配置

假设使用两台Basler acA1920-40gm相机,镜头焦距12mm,像元尺寸3.45μm,图像分辨率1920×1200,标定板为7×7圆点阵列、间距5mm。初始相机参数可写为:

gen_cam_par_area_scan_division (0.012, 0.0, 3.45e-6, 3.45e-6, 960, 600, 1920, 1200, CamPar)
create_calib_data ('calibration_object', 2, 1, CalibDataID)
set_calib_data_cam_param (CalibDataID, 0, 'area_scan_division', CamPar)
set_calib_data_cam_param (CalibDataID, 1, 'area_scan_division', CamPar)
set_calib_data_calib_object (CalibDataID, 0, 'calplate_5mm.descr')

随后对每台相机、每个位姿调用find_calib_object,把结果写入CalibDataID。当所有观测点录入后,执行calibrate_cameras (CalibDataID, Errors),Errors返回每幅图像的重投影误差。判断标准:平均重投影误差应小于0.1像素,若某幅图像误差明显偏大,说明该位姿下标定板提取失败或标定板未完整入镜,应剔除后重新解算。

标定板描述文件必须与实物严格一致。若实际圆点间距为5mm而描述文件写成4mm,解算出的焦距和主点会按比例偏移,后续三维重建会出现系统性尺度误差。

多相机集成的关键约束

多相机标定与单相机标定的最大区别在于:所有相机必须共享同一标定板坐标系,或至少存在公共观测。HALCON通过CalibDataID中的CalibObjectID和相机索引来组织数据,calibrate_cameras会同时优化所有相机的内参和它们之间的相对外参。若某台相机从未与其它相机同时看到标定板,则它只能得到独立内参,无法建立相机间外参,此时需要额外拍摄一组“共视”图像来补全约束。

标定完成后,用get_calib_data取出'camera'、'pose'、'params'等结果,再用camera_calibration生成CamCalib对象,供后续rectify_image、reconstruct_3d等算子直接使用。整个算子体系的调用逻辑可以概括为:数据容器贯穿始终,提取算子负责观测,解算算子负责优化,参数对象负责复用。掌握这条主线,多相机标定的代码组织就不会乱。