1. 传感器标定基础

什么是传感器标定?

传感器标定,说白了就是给传感器做一次「体检」和「校准」。

我刚开始做SLAM那会儿,总觉得标定是个可有可无的步骤。直到有一次,我在一个室内停车场做测试,明明算法写得没问题,地图就是拼不齐,轨迹一直在飘。折腾了两天,最后发现是相机内参出了问题——出厂参数跟实际差了0.3个像素。嗯,从那以后,我再也不敢跳过标定了。

传感器标定的本质,是建立传感器内部测量值与真实物理量之间的映射关系。对于视觉SLAM来说,我们需要知道:

  • 像素坐标(u, v)对应到相机坐标系下的什么方向?
  • 不同传感器之间的相对位置和姿态是怎样的?
  • 镜头畸变造成了多大的图像变形?

这些问题的答案,都藏在标定参数里。

为什么标定对跟踪至关重要?

你想想看,SLAM的核心任务之一就是跟踪——跟踪特征点、跟踪相机位姿、跟踪地图点。如果传感器本身的数据就是「歪」的,那后续所有计算都会跟着跑偏。

标定误差对跟踪的影响,我总结为三个层面:

  • 特征匹配失败:畸变校正不准,同一个角点在左右图像上的位置对不上
  • 三角化精度下降:外参有偏差,深度估计直接崩掉
  • 位姿估计漂移:内参不准,本质矩阵分解出来的旋转和平移全是错的

我记得有个项目,用双目相机做AGV导航。标定的时候偷了个懒,用了厂家给的参数没做精标。结果在直线行驶时,左右目视差一直有0.5个像素的系统偏差。别看这0.5像素,换算成3米处的深度误差,直接差了15厘米——AGV撞了三次货架,我才意识到问题出在标定上。

标定的核心参数

标定参数分三大类,我一个个说。

1. 内参(Intrinsic Parameters)

内参描述的是传感器内部的几何特性。对于相机来说,就是镜头和感光芯片之间的映射关系。

标准的内参矩阵长这样:

K = [fx  0  cx]
    [ 0  fy  cy]
    [ 0   0   1]
  • fx, fy:焦距,单位是像素。说白了就是镜头到成像平面的距离,用像素个数来衡量
  • cx, cy:主点坐标,理论上应该在图像正中心,但实际总有偏移

我的经验:fx和fy的比值越接近1,说明镜头畸变越小。如果比值超过1.05,建议换个镜头。我在一个项目里用过廉价USB摄像头,fx/fy=1.12,标定完直接放弃了——畸变太大,边缘特征点根本没法用。

2. 外参(Extrinsic Parameters)

外参描述的是传感器之间的相对位置关系。在多传感器融合中,这是最容易被忽视、也最容易出问题的地方。

外参包括:

  • 旋转矩阵 R:3x3矩阵,描述两个坐标系之间的旋转关系
  • 平移向量 t:3x1向量,描述两个坐标系原点之间的位移

举个例子,如果你用相机+IMU做融合,外参就是相机坐标系到IMU坐标系的变换矩阵:

T_cam_imu = [R  t]
            [0  1]

注意:外参标定不是一次性的。我曾经遇到过,相机和IMU的固定支架在振动环境下松动了0.5毫米,结果VIO的精度直接掉了30%。所以,定期检查外参很有必要。

3. 畸变系数(Distortion Coefficients)

镜头不是完美的,光线经过透镜时会发生弯曲,这就是畸变。畸变主要分两种:

  • 径向畸变:光线在透镜边缘弯曲更严重,表现为图像边缘的直线变弯
  • 切向畸变:透镜和成像平面不平行,表现为图像倾斜

常用的畸变模型有5个参数(k1, k2, p1, p2, k3):

x_distorted = x * (1 + k1*r^2 + k2*r^4 + k3*r^6) + 2*p1*x*y + p2*(r^2 + 2*x^2)
y_distorted = y * (1 + k1*r^2 + k2*r^4 + k3*r^6) + p1*(r^2 + 2*y^2) + 2*p2*x*y

看着复杂?其实你只需要知道:畸变系数越大,图像变形越严重。k1通常占主导,k2和k3是修正项。

避坑指南:我曾经用鱼眼镜头做SLAM,畸变系数k1=-0.35,边缘畸变非常严重。当时没做去畸变就直接提取ORB特征,结果图像边缘的特征点全匹配错了。后来老老实实先做去畸变,再提取特征,问题就解决了。

标定的知识体系

下面这张图,是我自己整理的标定知识框架。你看一眼就能明白标定在整个SLAM系统中的位置:

传感器标定知识体系 传感器原始数据 标定参数(内参 + 外参 + 畸变) 数据校正(去畸变 + 坐标变换) SLAM跟踪(特征匹配 + 位姿估计) 地图构建 / 定位输出 标定误差反馈优化 输入 处理 核心 输出

从这张图你可以看到,标定参数是整个SLAM系统的「地基」。地基不稳,上面盖的楼再漂亮也得塌。

标定的常见方法

目前最常用的标定方法是张正友标定法。你只需要打印一张棋盘格,从不同角度拍20-30张照片,就能解算出内参和畸变系数。

我用OpenCV做过很多次标定,核心步骤就这几行代码:

# 找棋盘格角点
ret, corners = cv2.findChessboardCorners(gray, (cols, rows), None)

# 标定相机
ret, K, dist, rvecs, tvecs = cv2.calibrateCamera(
    objpoints, imgpoints, gray.shape[::-1], None, None
)

# 去畸变
undistorted = cv2.undistort(img, K, dist)

我的建议:拍标定照片时,注意让棋盘格覆盖图像的各个区域——四个角、中心、边缘都要有。我见过有人只拍了中心区域的照片,标定出来的畸变系数在边缘完全不准。另外,棋盘格不要太小,建议占图像面积的1/4到1/3。

标定质量的评估

标定完了,怎么知道标得好不好?我一般看三个指标:

指标 合格标准 说明
重投影误差 < 0.5 像素 标定点反投影到图像上的误差,越小越好
fx/fy比值 0.95 ~ 1.05 接近1说明镜头质量好
主点偏移 < 图像宽高的5% cx偏离图像中心太多说明镜头装配有问题

如果重投影误差超过1个像素,我建议重新标定。检查一下是不是棋盘格照片拍得不够好,或者标定板本身不平整。

我曾经踩过的坑:有一次标定双目相机,重投影误差只有0.3像素,看起来很好。但实际做立体匹配时,视差图全是噪声。后来发现是左右目的同步有问题——两个相机采集时间差了20毫秒,运动场景下图像对不上。所以标定不仅要看参数,还要检查传感器本身的硬件同步。

好了,这一章的内容就到这里。标定是SLAM的基石,花时间把标定做好,后面的跟踪和建图才能事半功倍。


可可精品资料库