2. 坐标系与空间变换
做BEV融合感知,说白了就是跟坐标系打交道。我刚开始接触这个领域时,觉得坐标系不就是几个箭头嘛,后来才发现——坐标系搞不清楚,后面的目标关联全是扯淡。今天咱们就把这四个坐标系和它们之间的投影关系彻底捋清楚。
1. 四个坐标系,一个都不能少
先说说这四个坐标系各自是干嘛的。你想想看,一辆自动驾驶车在路上跑,车本身有个位置,相机装在车上有个角度,图像是二维的,而真实世界是三维的——这中间差了整整一个维度。所以我们需要坐标系来搭桥。
| 坐标系 | 维度 | 原点/定义 | 典型用途 |
|---|---|---|---|
| 世界坐标系 | 3D (Xw, Yw, Zw) | 自定义,通常为地面某点 | 全局定位、地图构建 |
| 车辆坐标系 | 3D (Xv, Yv, Zv) | 车辆后轴中心或质心 | 车辆运动、控制 |
| 相机坐标系 | 3D (Xc, Yc, Zc) | 相机光心 | 3D到2D投影 |
| 图像坐标系 | 2D (u, v) | 图像左上角 | 像素位置、特征点 |
我个人习惯把世界坐标系当作「绝对参考系」,车辆坐标系是「相对参考系」。嗯,这里要注意:车辆坐标系的原点位置各家定义不一样,有的用后轴中心,有的用GPS天线位置。我在项目中遇到过因为原点定义不一致导致融合结果偏移半米的情况,排查了整整两天。
2. 投影关系:从3D世界到2D图像
投影,说白了就是把三维空间里的点「拍扁」到二维图像上。这个过程分三步走:
- 世界 → 车辆:刚体变换(旋转+平移)
- 车辆 → 相机:刚体变换(外参)
- 相机 → 图像:透视投影(内参)
为什么会这样?因为相机装在车上,车又在地球上跑。每一步变换都对应一个矩阵,咱们一个一个来看。
2.1 世界坐标系 → 车辆坐标系
这个变换用到了外参中的一部分。假设世界坐标系下有个点 Pw = (Xw, Yw, Zw, 1),要转到车辆坐标系下:
Pv = T_w2v * Pw
其中 T_w2v = [R_w2v t_w2v]
[0 1 ]
R_w2v 是旋转矩阵,t_w2v 是平移向量。我记得第一次手写这个矩阵时,把旋转顺序搞反了,结果车在仿真里原地打转。后来养成了习惯:先验证旋转矩阵的行列式是否为1,再往下走。
2.2 车辆坐标系 → 相机坐标系
这一步就是相机外参的核心。相机装在车上的位置和朝向,决定了这个变换矩阵:
Pc = T_v2c * Pv
T_v2c = [R_v2c t_v2c]
[0 1 ]
2.3 相机坐标系 → 图像坐标系
这一步是透视投影,用相机内参矩阵 K:
s * [u] [fx 0 cx] [Xc]
[v] = [0 fy cy] * [Yc]
[1] [0 0 1] [Zc]
其中 fx, fy 是焦距(像素单位),cx, cy 是主点坐标。s 是尺度因子,等于 Zc。说白了,这一步把三维点投影到归一化平面上,再乘以内参得到像素坐标。
3. 逆投影:从2D图像反推3D
逆投影比投影难得多。为什么?因为投影是降维,信息丢失了。一个像素点对应的是三维空间中的一条射线,而不是一个点。
逆投影的数学表达:
给定像素 (u, v) 和深度 d,可以恢复相机坐标系下的3D点:
Xc = (u - cx) * d / fx
Yc = (v - cy) * d / fy
Zc = d
你看,这里需要深度 d。没有深度,你只能得到方向,得不到位置。这就是为什么BEV感知里,单目相机必须依赖深度估计网络来补全这个缺失的维度。
我在项目中遇到过一个问题:用逆投影把2D检测框的底边中心点投影到地面上,结果发现车辆位置总是偏。后来排查发现,是因为地面不是绝对平坦的——车辆有俯仰角变化。所以逆投影前,一定要考虑车辆自身的姿态(pitch/roll)。
4. 知识体系总览
下面这张图把四个坐标系和它们之间的变换关系串起来了。我建议你把它当作「坐标系变换速查表」来用。
5. 实战中的坐标系管理
在BEV融合感知系统中,坐标系管理是个脏活累活。我总结了几条经验:
- 统一时间戳:坐标系变换依赖车辆位姿,而位姿是随时间变化的。不同传感器的时间戳必须对齐,否则变换矩阵就是错的。
- 缓存变换矩阵:不要每帧都重新计算外参。如果相机安装位置固定,外参矩阵可以离线标定好,在线直接查表。
- 验证闭环:我习惯做一个验证——把一个3D点投影到图像上,再用逆投影加深度恢复回来,看误差有多大。误差超过1个像素就要查原因。
核心要点:坐标系变换的本质是「用矩阵乘法描述空间关系」。你不需要记住每个矩阵的具体数值,但必须清楚:
- 哪个坐标系是源,哪个是目标
- 变换是刚体变换还是透视投影
- 逆投影缺少深度信息,需要额外估计
嗯,今天就先聊到这儿。坐标系这部分是BEV感知的基石,后面讲目标关联时,你会发现所有操作都在这些坐标系之间来回跳转。把基础打牢,后面才能跑得快。