4、双目标定:立体视觉标定、外参计算与极线校正
双目标定,说白了就是给两个相机做「联姻」。单目标定只关心每个相机自己看得清不清,双目标定要解决的是:两个相机之间到底什么关系?它们能不能配合起来算深度?
我刚开始做双目项目时,以为把两个相机分别标定好就完事了。结果一算三维坐标,误差大得离谱。后来才明白——双目标定的核心,是求两个相机之间的外参,也就是旋转矩阵 R 和平移向量 T。
4.1 双目标定的本质
双目标定要输出三样东西:
- 左相机内参 + 畸变系数
- 右相机内参 + 畸变系数
- 左右相机之间的外参(R, T)
外参描述的是:从右相机坐标系到左相机坐标系的刚体变换。有了它,我们才能把左右两幅图像上的点对应起来,进而计算视差和深度。
其中 P_left 和 P_right 是同一个空间点在左右相机坐标系下的坐标。
4.2 HALCON 中的 binocular_calibration 算子
HALCON 把双目标定封装成了一个算子——binocular_calibration。你不需要手动解方程,也不需要自己算本质矩阵。只要把左右相机的标定数据喂进去,它一次性给你算完。
我个人习惯用这个算子的标准流程:
- 分别对左右相机做单目标定,拿到各自的内参和畸变
- 拍摄一组左右同步的标定板图像(至少 10 对)
- 调用
binocular_calibration,传入左右相机标定数据和图像对 - 输出外参 R, T,以及优化后的内参
* 左相机标定数据
create_calib_data ('calibration_object', 'calibration_plate', 1, CalibDataL)
set_calib_data_cam_param (CalibDataL, 0, 'area_scan_division', StartCamParamL)
set_calib_data_calib_object (CalibDataL, 0, CalibObjDescr)
* 右相机标定数据
create_calib_data ('calibration_object', 'calibration_plate', 1, CalibDataR)
set_calib_data_cam_param (CalibDataR, 0, 'area_scan_division', StartCamParamR)
set_calib_data_calib_object (CalibDataR, 0, CalibObjDescr)
* 双目标定
binocular_calibration (CalibDataL, CalibDataR, NStartCamParamL, NStartCamParamR, \
CalibObjDescr, 'all', 'all', CalibObjFindL, CalibObjFindR, \
NCamParamL, NCamParamR, NCalibObjPoseL, NCalibObjPoseR, \
RelPose, Errors)
4.3 外参计算:R 和 T 的物理意义
外参 RelPose 输出的是一个 7 元组:[X, Y, Z, Rx, Ry, Rz, Type]。前三个是平移向量 T,后三个是旋转角度(或轴角)。
举个例子:如果 T = [100, 0, 0] mm,说明右相机在左相机右边 100mm。如果 Rx = 0.5°,说明右相机绕 X 轴转了半度。
| 参数 | 含义 | 典型值范围 |
|---|---|---|
| X, Y, Z | 右相机原点在左相机坐标系下的位置 | 几十到几百 mm |
| Rx, Ry, Rz | 旋转角度(取决于 Type) | 通常小于 5° |
| Type | 旋转表示方式:'gba' 或 'axis_angle' | 常用 'gba' |
你想想看,如果两个相机完全平行,R 应该接近单位矩阵,T 只有 X 方向有值。但实际装配总有误差,所以 R 会有小角度偏移,T 也会有 Y 和 Z 分量。
4.4 极线校正:让图像对齐
极线校正的目的,是把左右图像变换到同一个平面上,让对应点在水平方向上对齐。这样后续的立体匹配只需要搜索同一行,效率翻倍。
HALCON 用 gen_binocular_rectification_map 生成校正映射:
* 生成校正映射
gen_binocular_rectification_map (MapL, MapR, NCamParamL, NCamParamR, RelPose, \
'geometric', 'bilinear', RectL, RectR, CamParamRectL, CamParamRectR)
* 应用校正
map_image (ImageL, MapL, RectifiedL)
map_image (ImageR, MapR, RectifiedR)
校正完成后,你可以用 draw_epipolar_lines 画几条极线验证。如果极线是水平的,说明校正成功。我记得第一次做校正时,极线歪了 3 个像素,找了半天发现是标定板拍得太少了。
4.5 双目标定的避坑指南
- 左右图像必须同步: 如果两个相机不是硬件触发,运动物体在左右图像中的位置会不一致,导致外参计算错误。我曾经用软件触发拍运动工件,结果外参误差 20%。后来换了硬件触发才解决。
- 标定板不能太小: 标定板在图像中至少要占 1/4 面积。太小了角点检测精度不够,外参会飘。
- 不要只用一组姿态: 标定板要倾斜、旋转、远近都拍。只拍正面的外参,在边缘区域会失效。
- 检查重投影误差:
binocular_calibration输出的Errors包含重投影误差。如果大于 0.5 像素,说明标定质量有问题,需要重新拍。
4.6 双目标定知识体系
下面这张图总结了双目标定的核心流程和关键输出:
从流程图可以看出,双目标定不是简单的「1+1=2」。它把左右相机的标定数据融合在一起,通过联合优化得到更精确的内参和外参。校正环节是承上启下的关键——没有好的外参,极线校正就是空中楼阁。
嗯,双目标定就讲到这里。记住一个原则:标定数据质量决定一切。多拍几组、覆盖全视野、检查重投影误差,这三步做到位,你的双目系统就稳了。