4、传感器标定:相机内参标定、相机-激光雷达联合标定、标定工具使用

传感器标定这件事,说白了你得先让车「看清楚」自己身上长了什么。我见过不少团队,算法调得飞起,结果标定没做好,一上路就翻车。嗯,这章咱们就把标定这块硬骨头啃下来。

4.1 相机内参标定——给眼睛配副眼镜

相机内参标定,说白了就是搞清楚镜头是怎么扭曲光线的。每颗镜头都有出厂误差,比如焦距偏差、光心偏移、还有那烦人的畸变。你想想看,如果内参不准,后面做视觉测距、目标检测,全都会跟着歪。

我个人习惯用棋盘格标定板。为什么?因为角点检测稳定,算法成熟。OpenCV 的 cv2.calibrateCamera() 就能搞定。但这里有个坑——

注意: 棋盘格必须贴平!我曾经在项目里用 A4 纸打印棋盘格,贴在纸箱上,结果标定出来的内参全是错的。后来换成亚克力板,一次过。

标定流程其实不复杂:

  1. 拍 20-30 张不同角度的棋盘格照片
  2. 检测角点,提取像素坐标
  3. 用张正友标定法解算内参矩阵和畸变系数
  4. 验证重投影误差,一般要小于 0.5 像素
# 伪代码示意
import cv2
import numpy as np

# 准备棋盘格角点坐标
objp = np.zeros((6*9, 3), np.float32)
objp[:,:2] = np.mgrid[0:9, 0:6].T.reshape(-1,2)

# 遍历图片,检测角点
imgpoints = []
objpoints = []
for img in images:
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, corners = cv2.findChessboardCorners(gray, (9,6), None)
    if ret:
        imgpoints.append(corners)
        objpoints.append(objp)

# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
    objpoints, imgpoints, gray.shape[::-1], None, None
)
小技巧: 标定完成后,记得用 cv2.undistort() 去畸变看看效果。如果图像边缘的直线还是弯的,说明标定没到位。

4.2 相机-激光雷达联合标定——让眼睛和耳朵对齐

相机看到的是像素,激光雷达看到的是点云。怎么把两者对齐?这就是联合标定要干的事。说白了,就是求一个外参矩阵,把激光雷达坐标系下的点,投影到相机图像上。

我建议用标定板来做。找一块带反光标记的平板,或者用棋盘格加边缘检测。激光雷达扫到标定板边缘,会形成明显的点云轮廓。相机拍到棋盘格,能提取出角点。然后找对应关系,解算旋转和平移。

这里有个经典方法——

  • 手动选点法: 在点云里选几个特征点,在图像里标出对应像素。至少 4 组点,用 PnP 解算。简单粗暴,但精度看手抖不抖。
  • 自动匹配法: 用标定板检测算法,自动提取点云中的平面和图像中的角点。精度高,但实现复杂。

我在项目中遇到过最头疼的问题:激光雷达和相机的时间戳没对齐。车一动起来,点云和图像差了几十毫秒,标定结果完全不能用。后来加了硬件同步触发,才搞定。

核心公式: 联合标定本质是求解 [R|t] 矩阵,使得激光点 P_lidar 投影到图像坐标 p_image 时,误差最小。
p_image = K * [R|t] * P_lidar

4.3 标定工具使用——Kalibr 和 lidar_camera_calibration

手写标定代码太累?直接用现成工具。我常用的两个:

Kalibr

Kalibr 是 ETH 出的多传感器标定工具,支持相机内参、相机-IMU、多相机联合标定。它用 B-spline 模型拟合运动轨迹,精度很高。

使用步骤:

  1. 准备标定板(Aprilgrid 或棋盘格)
  2. 录制 rosbag,包含图像和 IMU 数据
  3. 写配置文件,指定标定板参数和传感器模型
  4. 运行 kalibr_calibrate_cameras 或 kalibr_calibrate_imu_camera
# Kalibr 命令行示例
kalibr_calibrate_cameras \
    --bag cam_imu.bag \
    --topics /cam0/image_raw \
    --models pinhole-radtan \
    --target april_6x6.yaml
注意: Kalibr 对数据质量要求高。我吃过亏——录 bag 时手抖了一下,标定结果直接发散。建议录 3-5 分钟数据,包含旋转和平移运动。

lidar_camera_calibration

这是另一个好用的工具,专门做激光雷达和相机联合标定。它用棋盘格作为中介,自动检测点云中的平面和图像中的角点。

优点:

  • 全自动,不需要手动选点
  • 支持多线激光雷达(Velodyne、Ouster 等)
  • 输出外参矩阵和重投影误差

缺点:

  • 对棋盘格摆放位置敏感
  • 标定板必须足够大,否则点云检测不到边缘

我个人习惯先用 lidar_camera_calibration 做粗标定,再用 Kalibr 做精调。两轮下来,重投影误差能控制在 2 像素以内。

4.4 标定流程总览

下面这张图是我自己总结的标定流程,你照着走基本不会出错:

准备标定板 采集数据 相机内参标定 联合标定 验证重投影误差 部署到系统 误差过大?重新标定 标定流程:准备 → 采集 → 内参标定 → 联合标定 → 验证 → 部署

4.5 避坑指南

最后,我把自己踩过的坑列出来,你遇到类似问题直接对照:

  • 标定板不平: 我曾经用纸板贴棋盘格,结果标定出来的畸变系数全是错的。换成亚克力板或铝板,一次过。
  • 光照不足: 相机标定需要均匀光照。我在阴天室外标定,角点检测率直接掉到 60%。后来加了补光灯,好多了。
  • 激光雷达反射干扰: 标定板边缘如果有高反光材料,点云会飘。建议用哑光材料做标定板。
  • 时间戳不同步: 联合标定前,先检查相机和激光雷达的时间戳是否对齐。差 10ms 以上,标定结果就废了。
我的习惯: 每次标定完,我都会在实车上跑一段路,看看点云投影到图像上是否对齐。如果远处路灯杆的点云和图像边缘重合,说明标定合格。

嗯,标定这块就讲这么多。工具和方法都给你了,剩下的就是多练。记住,标定是感知系统的地基,地基不稳,上层算法再牛也白搭。

可可精品资料库