3. 相机模型与标定
视觉惯导VIO系统的前端依赖相机提供的图像信息,而相机如何将三维世界投影到二维像素平面,直接决定了后续特征提取、三角化、位姿估计的精度。本章从针孔模型出发,逐步引入透镜畸变模型,并系统讲解基于棋盘格与Kalibr工具的内外参标定方法。理解相机模型是搭建VIO系统的基础,标定精度则直接影响系统鲁棒性。
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 | 影响边缘区域特征精度 |
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算法优化重投影误差。
3.3 棋盘格标定:张正友法与操作流程
棋盘格标定是最经典的内参标定方法,其核心思想是利用棋盘格的平面约束,通过单应性矩阵求解内参。具体操作流程如下:
- 准备标定板:打印高精度棋盘格(建议A3纸,方格边长20-30mm),粘贴在平整硬板上。
- 采集图像:固定相机,移动标定板,采集15-25张不同角度、距离的图像。确保棋盘格占图像面积的1/4以上,且覆盖图像各个区域。
- 角点检测:使用OpenCV的
findChessboardCorners函数检测内角点,亚像素细化提高精度。 - 求解内参:调用
calibrateCamera函数,输入角点坐标和棋盘格物理尺寸,输出内参矩阵K和畸变系数。 - 评估结果:检查重投影误差(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命令,输出标定结果和重投影误差报告。
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个月或更换镜头后重新标定。