传感器标定:内参标定、外参标定、联合标定、标定工具链

传感器标定这件事,说白了就是给车子的眼睛配眼镜。

你想想看,摄像头、激光雷达、毫米波雷达,每个传感器都有自己的坐标系。摄像头看到的是像素,激光雷达看到的是点云,毫米波雷达看到的是目标。如果它们之间没有对齐,那感知结果就是一团乱麻。我刚开始做自动驾驶那会儿,就吃过这个亏——标定没做好,车在高速上把路牌当成了障碍物,差点急刹。

内参标定:让摄像头看清世界

内参标定,解决的是传感器自身的问题。对于摄像头来说,就是搞清楚焦距、主点、畸变系数这些参数。

为什么需要这个?因为镜头不是完美的。广角镜头有桶形畸变,长焦镜头有枕形畸变。如果不矫正,你看到的直线是弯的,距离估计也会出错。

核心参数:
  • 焦距(fx, fy):像素坐标系与物理坐标系的比例关系
  • 主点(cx, cy):光轴与成像平面的交点
  • 畸变系数(k1, k2, p1, p2, k3):径向畸变和切向畸变的矫正参数

常用的方法是张正友标定法。你拿一个棋盘格,拍十几张不同角度的照片,然后让算法自动解算。我个人习惯用 OpenCV 的 cv2.calibrateCamera(),简单粗暴。

import cv2
import numpy as np

# 准备棋盘格角点
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
objp = np.zeros((6*9, 3), np.float32)
objp[:,:2] = np.mgrid[0:9, 0:6].T.reshape(-1, 2)

# 遍历图像,提取角点
objpoints = []  # 世界坐标系中的点
imgpoints = []  # 图像坐标系中的点

for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, corners = cv2.findChessboardCorners(gray, (9, 6), None)
    if ret:
        objpoints.append(objp)
        corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
        imgpoints.append(corners2)

# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
我的经验:棋盘格一定要贴平,不能有褶皱。我曾经用一张皱巴巴的纸做标定,结果畸变参数完全不对,车子在弯道里一直跑偏。

外参标定:让传感器对齐世界

外参标定,解决的是传感器之间的相对位置关系。比如摄像头装在车顶,激光雷达装在保险杠上,它们之间的旋转和平移矩阵是多少?

说白了,就是要把激光雷达看到的点云,投影到摄像头的图像上。如果外参不准,点云和图像对不上,融合就无从谈起。

常用的方法有两种:

  • 目标法:在场景中放置已知尺寸的标定物(如棋盘格、标定板),同时被摄像头和激光雷达看到,然后解算相对位姿。
  • 自然特征法:利用场景中的角点、边缘等自然特征,通过优化算法对齐。

我记得有一次在量产车上做外参标定,发现激光雷达和摄像头之间有 0.5 度的偏差。这个偏差在近距离看不出来,但到了 100 米外,投影误差能到 1 米。嗯,这种问题在路测时特别坑。

联合标定:多传感器的时间与空间对齐

联合标定,就是把内参和外参一起搞定。但这里有个更头疼的问题——时间同步。

你想想看,摄像头是 30fps,激光雷达是 10fps,毫米波雷达是 20fps。它们采集数据的时间戳不一样。如果直接用,就会出现「看到障碍物时,它已经不在那个位置了」的情况。

注意:时间同步的精度直接影响融合效果。对于高速场景(比如 120km/h),1ms 的时间误差会导致 3.3cm 的位置偏差。这在紧急制动场景下是致命的。

联合标定的流程一般是:

  1. 分别对每个传感器做内参标定
  2. 用标定物做两两之间的外参标定
  3. 做全局优化,最小化所有传感器的重投影误差
  4. 验证标定结果(比如看点云投影到图像上是否对齐)

我建议在联合标定时,使用 因子图优化 的方法。把每个传感器的观测作为因子,把位姿作为变量,用 Ceres 或 G2o 做非线性优化。这样能同时保证精度和鲁棒性。

标定工具链:从实验室到量产

标定这件事,在实验室里做一次不难。但到了量产阶段,每天要标定几百台车,那就完全不一样了。

一个完整的标定工具链,通常包含这几个环节:

环节 说明 常用工具
数据采集 在标定场地中采集多传感器数据 ROS bag、自定义采集程序
离线标定 用采集的数据解算内外参 OpenCV、Kalibr、lidar_camera_calibration
在线标定 车辆运行时实时修正外参 基于 SLAM 的在线标定模块
验证与监控 定期检查标定精度,发现漂移及时报警 可视化工具、自动化测试脚本

我个人比较推荐 Kalibr 这个工具包。它支持多摄像头、IMU、激光雷达的联合标定,而且代码质量很高。不过要注意,Kalibr 对数据质量要求很苛刻——运动太慢不行,太快也不行,得保持一个合适的角速度和线速度。

避坑指南:我曾经在量产项目中遇到一个问题——标定完的车,开出去两天外参就漂了。后来发现是固定支架的螺丝松了。所以,标定完一定要做「震动测试」,模拟实际路况下的振动环境。

知识体系总览

下面这张图,是我梳理的传感器标定知识体系。你可以把它当作一个「地图」,随时回来对照。

传感器标定知识体系 传感器标定 内参标定 焦距 (fx, fy) 主点 (cx, cy) 畸变系数 (k1, k2, p1, p2, k3) 外参标定 旋转矩阵 (R) 平移向量 (t) 传感器间相对位姿 联合标定 时间同步 全局优化 重投影误差最小化 标定工具链 数据采集 离线标定 在线标定 验证与监控 OpenCV / Kalibr / ROS / Ceres

标定这件事,看起来是「一次性工作」,但实际上贯穿了整个自动驾驶系统的生命周期。从研发阶段的离线标定,到量产阶段的在线标定,再到运营阶段的监控与重标定,每一步都不能马虎。

嗯,最后说一句:标定数据一定要保留好。我见过太多团队,标定完就把原始数据删了,结果出了问题想复盘都找不到依据。留一份数据,就是留一条后路。

我的习惯:每次标定完,我都会把标定参数、原始数据、标定报告一起归档,按日期命名。这样即使半年后出了问题,也能快速定位是标定漂了还是传感器坏了。

可可精品资料库