传感器标定基础:内参标定、外参标定、标定工具与流程、常见问题排查

各位同学,欢迎来到《感知联调实战避坑指南》的第一章。

说实话,标定这件事,在很多人眼里就是个「配准」的活儿。但我在项目里摔过跟头之后才明白——标定没做好,后面所有感知算法都是空中楼阁。你想想看,相机看到的目标在像素坐标,激光雷达扫到的点在雷达坐标系,这两者如果对不上号,融合出来的结果就是「四不像」。

今天我们就来把标定的底子打扎实。我会从内参、外参、工具流程、再到常见坑点,一条一条捋清楚。

1. 内参标定:相机与激光雷达各自「认清自己」

内参标定,说白了就是让传感器知道「我是谁,我长什么样」。每个传感器出厂时都有理论参数,但实际安装、温度变化、震动都会让参数跑偏。所以我们必须重新标定。

1.1 相机内参标定

相机内参包括:焦距(fx, fy)、主点(cx, cy)、畸变系数(k1, k2, p1, p2, k3)。

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

核心步骤:

  1. 拍摄 15-20 张不同角度的棋盘格图像
  2. 检测亚像素级角点
  3. 调用标定函数,得到内参矩阵和畸变系数
  4. 用重投影误差评估标定质量(一般 < 0.1 像素算合格)
import cv2
import numpy as np

# 棋盘格尺寸(内角点)
pattern_size = (9, 6)
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)

objpoints = []  # 世界坐标系中的点
imgpoints = []  # 图像坐标系中的点

for fname in image_files:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, corners = cv2.findChessboardCorners(gray, pattern_size, None)
    if ret:
        objpoints.append(objp)
        imgpoints.append(corners)

ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
print("内参矩阵:\n", mtx)
print("畸变系数:\n", dist)

我的小技巧: 拍摄时让棋盘格占图像面积的 1/3 到 1/2,并且覆盖图像四个角落。我曾经偷懒只拍了中心区域,结果标出来的畸变参数在边缘完全不准,后来吃了大亏。

1.2 激光雷达内参标定

激光雷达的内参相对简单,主要是:

  • 激光发射器与接收器的相对位置
  • 每个激光束的俯仰角、水平角偏移
  • 距离测量偏移量

大部分激光雷达出厂时已经标定好了。但如果你用的是多线雷达(比如 64 线、128 线),或者自己组装的雷达,那就得重新标。

我记得有一次,项目里用的雷达因为运输震动,导致某几根激光束的角度偏了 0.1 度。结果点云投影到图像上,远处目标总是错位。排查了两天才找到原因——就是内参出了问题。

注意: 激光雷达内参标定通常需要专用靶标(如平面板、角反射器)。不要用普通墙面,因为反射强度不稳定,容易引入误差。

2. 外参标定:让传感器「对齐」到同一个坐标系

外参标定,就是求传感器之间的旋转矩阵 R 和平移向量 t。说白了,就是让相机和激光雷达「看」到同一个世界。

2.1 相机-激光雷达联合标定

这是感知系统中最常见的标定任务。我们需要找到 3D 点云到 2D 图像的投影关系。

常用的方法有两种:

方法 原理 精度 适用场景
靶标法 使用棋盘格或特制标定板,同时被相机和雷达观测 高(< 0.5°) 实验室、量产线
自然特征法 利用场景中的角点、边缘等特征自动匹配 中等(1°-2°) 现场标定、OTA 更新

我个人更推荐靶标法,尤其是用那种带反光标记的标定板。激光雷达打在反光标记上,回波强度会特别高,很容易和相机图像中的角点对应起来。

# 伪代码:外参标定流程
1. 采集 N 组数据(每组包含一张图像 + 一帧点云)
2. 在图像中检测标定板角点(像素坐标)
3. 在点云中提取标定板平面,计算角点的 3D 坐标
4. 使用 PnP 算法求解 R, t
5. 用重投影误差评估(一般 < 2 像素算合格)

避坑指南: 我曾经在标定时只用了 5 组数据,结果外参在某个方向上特别敏感。后来我改成至少采集 15 组不同角度、不同距离的数据,标定结果才稳定下来。记住:数据多样性比数据量更重要。

2.2 多传感器联合标定

如果你的系统里有多个相机、多个激光雷达,甚至还有毫米波雷达,那就需要做联合标定。这时候通常采用「链式标定」或「全局优化」两种策略。

  • 链式标定: 先标定主传感器(如主相机)到车体的外参,再标定其他传感器到主传感器的外参。简单,但误差会累积。
  • 全局优化: 把所有传感器的外参放在一起,用图优化(如 g2o、Ceres)同时求解。精度高,但计算量大。

嗯,这里要注意:链式标定适合传感器数量少(2-3 个)的场景。如果超过 4 个,我建议直接上全局优化,否则累积误差会让你怀疑人生。

3. 标定工具与流程

工欲善其事,必先利其器。我常用的标定工具有这些:

工具 适用场景 优点 缺点
OpenCV 相机内参、单目外参 免费、文档全 不支持激光雷达
Autoware Calibration Toolkit 相机-激光雷达联合标定 开源、有 GUI 依赖 ROS
Apollo 标定工具 多传感器联合标定 支持全局优化 配置复杂
MATLAB Lidar Camera Calibrator 快速原型验证 交互式、可视化好 需要 License

标定流程我一般分三步走:

  1. 准备阶段: 制作标定板、搭建采集环境(光照均匀、无遮挡)
  2. 采集阶段: 多角度、多距离采集数据,保证覆盖整个视场
  3. 优化阶段: 用重投影误差、点云投影一致性等指标反复调优

我的习惯: 每次标定完,我都会做一次「验证标定」——用标定好的参数投影一帧点云到图像上,肉眼看看边缘是否对齐。如果对齐得不好,就重新采集数据再标。别嫌麻烦,这一步能省掉后面很多排查时间。

4. 常见标定问题排查

标定过程中,你大概率会遇到下面这些问题。我一个个说。

4.1 重投影误差很大

原因可能是:

  • 标定板不平整(换用亚克力板或铝板)
  • 图像模糊(检查快门速度,避免运动模糊)
  • 角点检测不准(改用亚像素检测)

4.2 点云投影到图像上整体偏移

这通常是外参的平移向量不准。我遇到过的情况是:标定板距离太近(< 1m),导致平移量估计偏差大。建议标定距离覆盖 2m-10m。

4.3 远处目标投影偏差大

大概率是激光雷达内参(角度偏移)没标好。或者相机畸变参数在边缘区域不准。解决办法:重新标定相机内参,或者用更多边缘数据优化。

4.4 标定结果时好时坏

嗯,这个问题最让人头疼。我排查过几次,发现原因往往是:

  • 数据采集时传感器有微小震动(用三脚架固定)
  • 标定板反光不均匀(换用哑光材质)
  • 算法初始化不好(换个初始值试试)

重要提醒: 标定不是一劳永逸的。车辆行驶一段时间后,螺丝松动、温度变化都会导致外参漂移。我建议每 3 个月或每 1 万公里做一次标定校验。如果发现感知结果异常,优先检查标定参数。

知识体系总览

最后,我用一张图把本章的核心逻辑串起来。你一看就明白标定在整个感知系统中的位置了。

传感器标定知识体系 相机 激光雷达 其他传感器 内参标定 内参标定 内参标定 外参标定(联合标定) 统一坐标系 → 感知融合 图:传感器标定从内参到外参再到感知融合的完整链路

好了,这一章的内容就到这里。标定是感知系统的「地基」,地基不稳,上层建筑再漂亮也没用。下一章我们会深入聊聊相机和激光雷达的联合标定实操,到时候我会带上具体的代码和踩坑记录。

可可精品资料库