3. 相机模型与内参标定:针孔相机模型、畸变模型、使用 ROS camera_calibration 包进行内参标定

相机内参标定是手眼标定流程中不可或缺的前置步骤。只有准确获取了相机的内参矩阵和畸变系数,才能将像素坐标可靠地映射到归一化相机坐标系,进而与机器人坐标系建立关联。本节从针孔相机模型出发,逐步引入畸变模型,并给出基于 ROS camera_calibration 包的完整标定流程。

3.1 针孔相机模型

针孔相机模型是计算机视觉中最基础的投影模型。它假设光线通过一个无限小的孔径(光心)在成像平面上形成倒立的像。为简化数学表达,通常将成像平面对称到光心前方,形成虚拟成像平面。

设空间点 P = (X, Y, Z) 在相机坐标系下的坐标为 (Xc, Yc, Zc),其投影到像素平面上的坐标为 (u, v)。投影过程分为两步:

  1. 归一化平面投影:将三维点投影到归一化平面 (Z=1) 上,得到归一化坐标 (x, y) = (Xc/Zc, Yc/Zc)。
  2. 像素坐标映射:通过内参矩阵 K 将归一化坐标转换为像素坐标。

内参矩阵 K 的标准形式为:

K = [fx   0   cx
     0   fy   cy
     0    0    1 ]

其中:

  • fx, fy:分别为 x 和 y 方向上的归一化焦距(单位:像素),fx = f / dx,fy = f / dy,f 为物理焦距,dx、dy 为像元尺寸。
  • cx, cy:主点坐标,即光轴与成像平面的交点(单位:像素)。

完整的投影方程可写为:

s * [u, v, 1]^T = K * [Xc, Yc, Zc, 1]^T

其中 s 为尺度因子(即 Zc)。

针孔相机投影模型 光心 O 虚拟成像平面 (Z=1) 主点 (cx, cy) P (Xc, Yc, Zc) p (u, v) 光轴 投影线 焦距 f 说明:空间点 P 通过光心 O 投影到虚拟成像平面上,形成像点 p。内参矩阵 K 描述了从归一化坐标 (x,y) 到像素坐标 (u,v) 的仿射变换。 主点 (cx,cy) 通常不在图像正中心,fx 与 fy 的差异反映了像元的非正方形特性。

3.2 畸变模型

实际相机镜头并非理想针孔,光线通过透镜时会发生折射,导致图像产生畸变。畸变主要分为两类:径向畸变和切向畸变。

畸变类型 产生原因 数学模型 典型参数
径向畸变 透镜形状不完美,光线在透镜边缘弯曲更严重 xdist = x(1 + k1r² + k2r⁴ + k3r⁶) k1, k2, k3
切向畸变 透镜与成像平面不平行(安装误差) xdist = x + [2p1xy + p2(r² + 2x²)] p1, p2

其中 r² = x² + y²,(x, y) 为归一化平面上的理想坐标。畸变校正的目标是找到从畸变坐标到理想坐标的映射关系。在 ROS 中,畸变参数通常以 5 维向量形式存储:[k1, k2, p1, p2, k3]。

经验提示:对于大多数工业相机和网络摄像头,仅使用 k1、k2、p1、p2 四个参数即可获得足够精度。k3 主要用于鱼眼镜头或大畸变镜头。

3.3 使用 ROS camera_calibration 包进行内参标定

ROS 提供了 camera_calibration 包,基于 OpenCV 的棋盘格标定算法,实现了半自动化的内参标定流程。该包以节点形式运行,订阅相机图像话题,通过交互式界面引导用户采集不同位姿的棋盘格图像,最终生成相机内参和畸变系数。

3.3.1 标定前准备

  1. 打印棋盘格标定板:推荐使用 7×9 或 8×6 的内角点棋盘格,方格边长需精确测量(如 25mm 或 30mm)。
  2. 启动相机驱动:确保相机节点已启动,并发布 /camera/image_raw 话题(或类似话题)。
  3. 安装 camera_calibration 包:
sudo apt install ros-noetic-camera-calibration

3.3.2 启动标定节点

运行以下命令启动标定节点:

rosrun camera_calibration cameracalibrator.py \
  --size 7x9 \
  --square 0.025 \
  image:=/camera/image_raw \
  camera:=/camera

参数说明:

  • --size:棋盘格内角点数量(列×行)。
  • --square:方格边长,单位:米。
  • image:=:图像话题名称。
  • camera:=:相机命名空间。

3.3.3 标定操作流程

标定节点启动后会打开一个 GUI 窗口,实时显示相机画面。用户需在视野中移动棋盘格,使标定板覆盖图像的各个区域(左上、右上、左下、右下、中心、倾斜、远近)。GUI 窗口右下角的进度条会显示当前数据采集状态:

进度条 含义 建议操作
X(水平方向覆盖) 棋盘格在图像水平方向上的分布 将棋盘格左右移动
Y(垂直方向覆盖) 棋盘格在图像垂直方向上的分布 将棋盘格上下移动
Size(尺度覆盖) 棋盘格在图像中的大小变化 将棋盘格前后移动(靠近/远离相机)
Skew(倾斜覆盖) 棋盘格相对于成像平面的倾斜角度 将棋盘格绕 X/Y 轴倾斜

当所有进度条变为绿色时,表示数据采集充分。此时 CALIBRATE 按钮变为可用,点击即可开始计算内参。

常见问题:如果 CALIBRATE 按钮始终不可用,通常是因为棋盘格角点检测失败。请确保棋盘格在图像中清晰可见、无反光、无遮挡,且棋盘格平面与相机光轴夹角不要过大(建议小于 45°)。

3.3.4 标定结果与保存

标定完成后,GUI 窗口会显示重投影误差(RMS),通常应小于 0.5 像素。点击 SAVE 按钮,标定结果会以 YAML 格式保存到 /tmp/calibrationdata.tar.gz 中。解压后得到 ost.yaml 和 ost.txt 文件。

ost.yaml 文件内容示例:

image_width: 640
image_height: 480
camera_name: camera
camera_matrix:
  rows: 3
  cols: 3
  data: [532.45, 0.0, 320.12, 0.0, 534.78, 240.56, 0.0, 0.0, 1.0]
distortion_model: plumb_bob
distortion_coefficients:
  rows: 1
  cols: 5
  data: [-0.2834, 0.0735, 0.0012, -0.0008, 0.0]
rectification_matrix:
  rows: 3
  cols: 3
  data: [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]
projection_matrix:
  rows: 3
  cols: 3
  data: [532.45, 0.0, 320.12, 0.0, 534.78, 240.56, 0.0, 0.0, 1.0]

将 ost.yaml 复制到相机驱动的配置目录(如 ~/.ros/camera_info/camera.yaml),相机节点启动后会自动加载内参,实现实时畸变校正。

ROS camera_calibration 标定流程 相机驱动节点 cameracalibrator.py GUI 标定窗口 ost.yaml camera_info_manager /image_raw 显示 & 交互 CALIBRATE → SAVE 加载配置 流程总结:相机驱动发布图像 → 标定节点检测棋盘格角点 → GUI 引导用户采集多姿态数据 → 计算内参与畸变系数 → 保存为 ost.yaml → 由 camera_info_manager 加载使用。 标定完成后,相机节点将自动对每帧图像进行畸变校正,输出无畸变图像。

3.4 标定质量评估

标定完成后,建议从以下维度评估标定质量:

评估指标 合格标准 检查方法
重投影误差 (RMS) < 0.5 像素 标定结果窗口直接显示
主点偏移 cx ≈ 图像宽度/2,cy ≈ 图像高度/2 对比内参矩阵中的 cx、cy
焦距一致性 fx 与 fy 差异 < 5% 计算 |fx - fy| / fx
畸变校正效果 图像边缘直线不再弯曲 在 Rviz 或 image_view 中观察校正后图像
工程建议:标定完成后,建议拍摄一张包含丰富直线特征(如建筑边缘、棋盘格)的图像,在 Rviz 中同时显示原始图像和校正后图像,直观验证畸变校正效果。如果边缘直线仍有明显弯曲,应重新标定,并增加倾斜和边缘位置的样本。