3. 相机模型与标定

视觉惯导VIO系统的前端依赖相机提供的图像信息,而相机如何将三维世界投影到二维像素平面,直接决定了后续特征提取、三角化、位姿估计的精度。本章从针孔模型出发,逐步引入透镜畸变模型,并系统讲解基于棋盘格与Kalibr工具的内外参标定方法。理解相机模型是搭建VIO系统的基础,标定精度则直接影响系统鲁棒性。

相机模型与标定知识架构 三维世界点 P(X,Y,Z) 相机坐标系 Pc(Xc,Yc,Zc) 归一化平面 (x,y,1) 畸变校正 径向+切向 像素坐标系 (u,v) 内参矩阵K fx,fy,cx,cy 外参 Tcw R,t 标定方法 棋盘格 / Kalibr / 自标定 标定流程:采集图像 → 角点检测 → 求解内参/畸变 → 优化重投影误差 → 输出标定文件 VIO中还需联合标定相机-IMU外参(Kalibr支持)

3.1 针孔相机模型:从三维世界到像素平面

针孔模型是相机成像的理想化近似,它假设光线通过一个无限小的针孔投影到成像平面。设三维空间点 P(X,Y,Z) 在相机坐标系下的坐标为 Pc(Xc,Yc,Zc),根据相似三角形原理,其在归一化平面上的投影为 (x,y) = (Xc/Zc, Yc/Zc)。随后通过内参矩阵将归一化坐标转换为像素坐标:

[u]   [fx  0  cx] [x]
[v] = [ 0 fy  cy] [y]
[1]   [ 0  0   1] [1]

其中 fx = f/dx,fy = f/dy 分别为x、y方向以像素为单位的焦距,cx、cy 为主点坐标。内参矩阵K描述了相机坐标系到像素坐标系的映射关系,是标定需要求解的核心参数。

参数符号物理含义典型值范围对VIO的影响
fx, fy归一化焦距(像素)300~2000影响深度估计尺度
cx, cy主点坐标图像中心附近影响特征点反投影精度
k1, k2, k3径向畸变系数-0.5~0.5畸变校正不准确导致特征匹配失败
p1, p2切向畸变系数-0.05~0.05影响边缘区域特征精度
经验提示:在VIO系统中,内参标定误差超过0.5像素就会显著影响视觉惯性对齐精度。建议使用高分辨率标定板(如10×7棋盘格,方格边长30mm),并采集20张以上不同姿态的图像进行标定。

3.2 畸变模型:径向与切向畸变校正

实际相机镜头存在透镜畸变,主要包括径向畸变和切向畸变。径向畸变由透镜形状引起,表现为图像边缘的桶形或枕形变形;切向畸变由透镜与成像平面不平行引起。畸变模型通常用多项式描述:

x_distorted = x * (1 + k1*r² + k2*r⁴ + k3*r⁶) + 2*p1*x*y + p2*(r² + 2*x²)
y_distorted = y * (1 + k1*r² + k2*r⁴ + k3*r⁶) + p1*(r² + 2*y²) + 2*p2*x*y

其中 r² = x² + y² 为归一化坐标到中心的距离平方。标定过程需要同时估计内参和畸变系数,通常采用张正友标定法,通过多视角棋盘格图像建立约束方程,使用Levenberg-Marquardt算法优化重投影误差。

常见误区:不要忽略切向畸变。虽然切向畸变通常较小(p1、p2约10⁻³量级),但在VIO长时间运行中,未校正的切向畸变会累积为位置漂移。建议在标定时同时估计所有畸变参数,而不是只估计径向畸变。

3.3 棋盘格标定:张正友法与操作流程

棋盘格标定是最经典的内参标定方法,其核心思想是利用棋盘格的平面约束,通过单应性矩阵求解内参。具体操作流程如下:

  1. 准备标定板:打印高精度棋盘格(建议A3纸,方格边长20-30mm),粘贴在平整硬板上。
  2. 采集图像:固定相机,移动标定板,采集15-25张不同角度、距离的图像。确保棋盘格占图像面积的1/4以上,且覆盖图像各个区域。
  3. 角点检测:使用OpenCV的 findChessboardCorners 函数检测内角点,亚像素细化提高精度。
  4. 求解内参:调用 calibrateCamera 函数,输入角点坐标和棋盘格物理尺寸,输出内参矩阵K和畸变系数。
  5. 评估结果:检查重投影误差(RMS),通常应小于0.3像素。
# Python示例:棋盘格标定核心代码
import cv2
import numpy as np

# 棋盘格尺寸
pattern_size = (9, 6)  # 内角点数
square_size = 0.025    # 方格边长(米)

# 准备对象点
objp = np.zeros((pattern_size[0]*pattern_size[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 2)
objp *= square_size

# 检测角点并收集数据
obj_points = []
img_points = []
for img_path in image_paths:
    img = cv2.imread(img_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, corners = cv2.findChessboardCorners(gray, pattern_size, None)
    if ret:
        corners_sub = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1),
                                       (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001))
        obj_points.append(objp)
        img_points.append(corners_sub)

# 标定
ret, K, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, gray.shape[::-1], None, None)
print("内参矩阵:\n", K)
print("畸变系数:", dist.ravel())

3.4 Kalibr标定:相机-IMU联合标定

Kalibr是ETH Zurich开发的多传感器标定工具,支持相机内参标定、相机-相机外参标定以及相机-IMU联合标定。在VIO系统中,相机与IMU之间的外参(旋转和平移)至关重要,Kalibr通过优化方法同时估计所有参数。

标定类型输入数据输出参数适用场景
相机内参棋盘格图像序列K, 畸变系数单目/双目相机
相机-相机外参双目图像序列R, t双目VIO
相机-IMU外参图像+IMU数据T_cam_imu, 时间延迟VIO系统核心标定

Kalibr联合标定的关键步骤包括:

  • 数据采集:使用rosbag录制图像和IMU数据,标定板保持静止,相机做充分激励运动(旋转+平移)。
  • 时间同步:确保图像时间戳与IMU时间戳对齐,Kalibr可估计时间偏移。
  • 参数配置:在yaml文件中指定相机模型(pinhole-equi或pinhole-radtan)、IMU噪声密度和随机游走。
  • 运行标定:执行 kalibr_calibrate_imu_camera 命令,输出标定结果和重投影误差报告。
实战案例:某无人机VIO系统使用Kalibr标定,初始重投影误差为1.2像素,IMU陀螺仪零偏估计偏差较大。通过以下优化措施:1)增加标定板照明,减少反光;2)延长采集时间至90秒,包含更多旋转激励;3)调整IMU噪声参数(加速度计噪声密度设为0.02 m/s²/√Hz)。重新标定后,重投影误差降至0.3像素,VIO轨迹漂移减少40%。

3.5 标定质量评估与常见误区

标定完成后,必须进行质量验证。常用的评估指标包括:

  • 重投影误差(RMS):所有角点的平均重投影误差,应小于0.3像素。
  • 内参稳定性:多次标定结果的一致性,fx、fy变化应小于1%。
  • 外参验证:将标定板放置在已知位置,投影三维点验证精度。
常见误区与风险:
1. 标定板不平整:使用弯曲的标定板会导致内参偏差,建议使用玻璃或铝板基底。
2. 图像数量不足:少于15张图像无法覆盖视场,导致畸变参数估计不准。
3. 忽略时间同步:相机与IMU时间戳偏差超过5ms会显著影响外参标定精度。
4. 过度依赖自动标定:Kalibr等工具虽然自动化程度高,但仍需人工检查标定板检测结果和优化收敛情况。

3.6 标定在VIO系统中的应用与复盘

在VIO系统中,标定参数直接参与前端特征点去畸变、后端优化中的投影误差计算。内参误差会导致特征点位置偏差,进而影响三角化精度和位姿估计。外参误差则会导致视觉与惯性数据融合时的坐标系不一致,产生尺度漂移。

案例复盘:某室内机器人VIO系统在运行10分钟后出现明显漂移,经排查发现是相机内参标定不准确导致。原始标定使用手机拍摄的棋盘格图像,图像分辨率低且存在运动模糊。重新使用高分辨率工业相机和标准标定板标定后,内参fx从520.3变为518.7(变化0.3%),重投影误差从0.8像素降至0.2像素。系统漂移从每10分钟1.2米降至0.3米。复盘经验:标定质量直接影响VIO长期稳定性,建议每3个月或更换镜头后重新标定。

最佳实践:在VIO系统启动时,增加标定参数自检模块。通过对比当前帧特征点去畸变前后的位置偏差,判断标定参数是否仍然有效。若偏差超过阈值,提示用户重新标定。