4、感知系统(一):摄像头标定与图像预处理、目标检测(YOLO系列、Transformer)在车端的部署优化
各位同学,欢迎来到感知系统的第一讲。说实话,感知是整个自动驾驶系统里最“卷”的模块,没有之一。摄像头又是感知的绝对主力,今天我们就来聊聊摄像头从上车到真正能用的那些关键步骤。
4.1 摄像头标定:让摄像头“认识”这个世界
摄像头装上车,它看到的是一堆像素点。怎么把这些像素点映射到真实世界的三维坐标?这就是标定要解决的问题。我个人习惯把标定分成两部分:内参标定和外参标定。
4.1.1 内参标定
内参,说白了就是摄像头自己的“脾气”。焦距、主点、畸变系数,这些参数决定了光线怎么穿过镜头落到传感器上。
我在项目中遇到过最头疼的事——同一批次的摄像头,内参居然有差异。你想想看,如果每个摄像头都用自己的“出厂默认参数”,那融合出来的结果肯定一塌糊涂。
常用的标定方法是张正友标定法。用棋盘格,拍个十几张不同角度的照片,然后解算。代码实现其实不复杂,OpenCV 里直接有现成的函数。
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)
# 存储所有图像的点
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)
imgpoints.append(corners)
# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
objpoints, imgpoints, gray.shape[::-1], None, None
)
4.1.2 外参标定
外参解决的是“摄像头装在车上的什么位置、什么角度”。旋转矩阵 R 和平移向量 T,把摄像头坐标系和车身坐标系对齐。
外参标定有两种主流方式:
- 离线标定:用标定间,车停到固定位置,拍标定板。精度高,但费时费力。
- 在线标定:利用车道线、静止物体等特征,实时估计外参。车开起来就能自动校准。
嗯,这里要注意。量产车上,外参是会漂移的。颠簸、碰撞、甚至温度变化,都可能导致摄像头松动。所以在线标定几乎是必备功能。
4.2 图像预处理:给算法“喂”好数据
摄像头采集的原始图像,直接扔给神经网络?不行。原始图像有噪声、光照变化、畸变,这些都会严重影响检测效果。
4.2.1 去畸变
广角摄像头拍出来的图像,边缘有明显的桶形畸变。如果不处理,远处的行人可能被“拉弯”。去畸变就是根据内参中的畸变系数,把图像“拉直”。
# 去畸变
undistorted = cv2.undistort(img, mtx, dist, None, newcameramtx)
这里有个性能问题。去畸变需要对每个像素做映射计算,在车端芯片上可能成为瓶颈。我建议用查表法——提前算好映射表,运行时直接查表。
4.2.2 图像增强
车端摄像头面临的环境太复杂了。逆光、隧道、夜间、雨雾……每个场景都需要不同的处理策略。
| 场景 | 问题 | 常用方法 |
|---|---|---|
| 逆光 | 目标区域过暗 | 自适应直方图均衡化(CLAHE) |
| 夜间 | 信噪比低 | 多帧融合、去噪 |
| 雨雾 | 对比度下降 | 去雾算法(暗通道先验) |
| 隧道 | 亮度突变 | 自动曝光控制 + 增益调整 |
4.3 目标检测:从 YOLO 到 Transformer
目标检测是感知系统的核心任务。车端需要检测车辆、行人、骑行者、交通标志、车道线……而且必须在毫秒级完成。
4.3.1 YOLO 系列在车端的部署
YOLO 系列,尤其是 YOLOv5 和 YOLOv8,是车端部署的常青树。为什么?
- 速度快:单阶段检测,一次前向推理直接输出结果。
- 精度够用:在车端场景下,mAP 能达到 70-80%。
- 生态好:有成熟的 ONNX 导出和 TensorRT 部署方案。
部署优化的关键点:
- 模型量化:FP32 转 INT8,推理速度提升 2-3 倍,精度损失控制在 1% 以内。
- 算子融合:Conv + BN + ReLU 融合成一个算子,减少内存访问。
- 输入尺寸优化:640x640 是 YOLO 的默认输入,但车端可以用 480x480,速度更快。
# TensorRT 部署示例(伪代码)
import tensorrt as trt
# 构建引擎
builder = trt.Builder(TRT_LOGGER)
network = builder.create_network()
parser = trt.OnnxParser(network, TRT_LOGGER)
parser.parse_from_file("yolov8n.onnx")
# 配置量化
config = builder.create_builder_config()
config.set_flag(trt.BuilderFlag.INT8)
config.int8_calibrator = MyCalibrator() # 自定义校准器
# 构建引擎
engine = builder.build_engine(network, config)
4.3.2 Transformer 在车端的落地
DETR 和它的变体(如 Deformable DETR)带来了端到端检测的新思路。不需要 NMS,不需要 anchor,直接输出检测结果。
但 Transformer 在车端部署有两个硬伤:
- 计算量大:自注意力机制的计算复杂度是 O(n²),对高分辨率图像不友好。
- 推理延迟高:在 Orin 上,DETR 的推理延迟可能是 YOLOv8 的 3-5 倍。
怎么优化?
我个人比较看好 Deformable DETR 的方案。它用可变形注意力代替全局注意力,只关注关键位置的特征。计算量大幅下降,精度反而有提升。
另外,混合架构也是一个方向。比如用 CNN 做 backbone 提取特征,用 Transformer 做 head 进行检测。这样既保留了 CNN 的高效特征提取能力,又利用了 Transformer 的全局建模能力。
4.4 车端部署的工程化思考
算法再好,部署不到车端也是白搭。这里分享几个工程化的经验。
4.4.1 芯片适配
不同芯片的算子支持不一样。Orin 对 Transformer 的支持比 TDA4 好很多。选芯片的时候,一定要先跑一遍模型,看看哪些算子不支持,哪些需要手动实现。
4.4.2 流水线设计
图像采集、预处理、推理、后处理,这些步骤可以做成流水线。用多线程 + 环形缓冲区,让每个阶段并行执行。我见过一个项目,流水线优化后,整体吞吐量提升了 40%。
4.4.3 故障处理
摄像头被泥巴糊住了怎么办?算法检测结果置信度持续偏低怎么办?量产系统必须有故障检测和降级机制。比如检测到摄像头遮挡,就切换到雷达为主、摄像头为辅的模式。
好了,这一讲的内容就到这里。下一讲我们会深入聊聊激光雷达和毫米波雷达的感知方案,以及多传感器融合的那些坑。各位同学,有什么问题可以随时交流。
公众号:蓝海资料掘金营,微信deep3321