2. 坐标系基础
做BEV感知,说白了就是要把不同传感器看到的东西,统一到同一个空间里说话。这个空间,就是咱们常说的“鸟瞰图”。但传感器各自有各自的“小世界”——相机有相机的坐标系,车辆有车辆的坐标系。怎么把这些小世界串起来?这就是坐标系转换要干的事。
我刚开始接触自动驾驶时,被这五个坐标系绕得晕头转向。后来在项目里踩了几次坑,才真正搞明白。今天咱们就把这五个坐标系的关系彻底捋清楚。
五个坐标系,各自是什么?
先给个全景图。这五个坐标系,从大到小,从抽象到具体,分别是:
- 世界坐标系:全局的、固定的参考系。比如以某个路口中心为原点,东、北、天为轴。所有物体在真实世界的位置,都用它来描述。
- 车辆坐标系:跟着车走的坐标系。原点一般在车辆后轴中心,x轴朝前,y轴朝左,z轴朝上。车一动,这个坐标系就跟着动。
- 相机坐标系:以相机光心为原点,z轴沿着光轴朝前,x轴朝右,y轴朝下。这是相机“看”世界的视角。
- 图像坐标系:在成像平面上,以光轴与平面的交点为原点,x轴朝右,y轴朝下。单位是毫米。
- 像素坐标系:就是我们最终看到的图像,原点在左上角,u轴朝右,v轴朝下。单位是像素。
核心一句话:世界坐标系是“上帝视角”,车辆坐标系是“车本位”,相机坐标系是“镜头视角”,图像坐标系是“物理成像面”,像素坐标系是“数字图像”。
转换关系:一步步来
这五个坐标系之间的转换,其实是一条链。我习惯把它拆成三步走:
- 世界 → 车辆:刚体变换(旋转+平移)
- 车辆 → 相机:刚体变换(外参)
- 相机 → 图像 → 像素:透视投影 + 数字化(内参)
你想想看,这不就是“从全局定位到局部感知,再到图像生成”的过程吗?
1. 世界坐标系 → 车辆坐标系
这一步,说白了就是知道车在世界中的位置和姿态。车的位置用平移向量 t 表示,姿态用旋转矩阵 R 表示。公式很简单:
P_vehicle = R * P_world + t
其中 P_world 是某点在世界坐标系下的坐标,P_vehicle 是它在车辆坐标系下的坐标。
我的经验:实际项目中,这个 R 和 t 通常来自组合导航系统(IMU+GPS)。但要注意,不同厂家给的坐标系定义可能不一样。我曾经遇到过一家供应商把y轴朝前,结果我按x轴朝前算,整个点云都歪了。所以拿到数据后,第一件事就是确认坐标系定义。
2. 车辆坐标系 → 相机坐标系
这一步就是外参标定要干的事。相机安装在车上,它相对于车辆有一个固定的位置和朝向。这个关系用外参矩阵 [R | t] 表示:
P_camera = R_veh2cam * P_vehicle + t_veh2cam
这里的 R_veh2cam 和 t_veh2cam 就是我们要标定的外参。它们描述了相机在车辆坐标系下的位姿。
注意:外参标定不是一劳永逸的。车辆行驶中的震动、温度变化,都可能导致外参发生微小偏移。我建议每隔一段时间或者车辆经过剧烈颠簸后,重新做一次标定检查。
3. 相机坐标系 → 图像坐标系
这一步是透视投影。相机坐标系下的一个点 (X, Y, Z),投影到成像平面上,得到图像坐标 (x, y):
x = f * X / Z
y = f * Y / Z
其中 f 是焦距。这里有个关键点:Z 不能为0。如果物体正好在相机光心后面,那它在图像上就看不到。
4. 图像坐标系 → 像素坐标系
最后一步,把物理尺寸(毫米)转换成像素。这一步涉及两个参数:
- dx, dy:每个像素在x和y方向上的物理尺寸(毫米/像素)
- u0, v0:图像坐标系原点在像素坐标系中的位置(主点偏移)
转换公式:
u = x / dx + u0
v = y / dy + v0
把前面几步合起来,就得到了从世界坐标系到像素坐标系的完整投影公式。这就是我们常说的“相机模型”。
完整转换链:一张图说清楚
下面这张图,我把整个转换链画出来了。你可以把它当作坐标系转换的“地图”,每次做投影时对照着看,不容易出错。
实际项目中的坑与技巧
理论说完了,聊聊实战。我在做BEV感知时,坐标系转换这块踩过不少坑,分享几个典型的:
坑一:坐标系方向搞反
我曾经在标定外参时,把相机坐标系的y轴方向搞反了。结果投影出来的点云全在车底下。查了两天才发现,原来是相机坐标系定义里y轴朝下,而我习惯性地认为y轴朝上。从那以后,我每次拿到新传感器,第一件事就是画坐标系示意图,贴在墙上。
技巧一:用齐次坐标简化计算
我建议把所有转换都用齐次坐标表示。这样旋转和平移可以合并成一个4x4矩阵,连续转换就是矩阵乘法。代码写起来干净,也不容易出错。
# 齐次坐标示例
def transform_point(point, matrix):
# point: [x, y, z, 1]
# matrix: 4x4 变换矩阵
result = matrix @ point
return result[:3] / result[3]
技巧二:验证转换是否正确
每次做完标定,我都会找一个已知位置的点(比如车道线角点),手动算一遍投影结果,跟实际图像对比。如果偏差超过2个像素,我就知道标定有问题。这个方法虽然土,但很管用。
总结一下
坐标系转换是BEV感知的基石。你想想看,如果连相机看到的东西在车什么位置都搞不清楚,那后面的融合、预测、规划全都会乱套。
我个人习惯把转换链记在脑子里:世界→车辆→相机→图像→像素。每一步都有明确的物理意义和数学表达。遇到问题时,就沿着这条链一步步排查,总能找到问题出在哪。
嗯,今天就聊到这。坐标系这块内容不难,但细节很多。建议你动手写代码实现一遍,把每个转换矩阵都打印出来看看,感受一下数值的变化。这样印象会深很多。
一句话记住:坐标系转换,就是把不同“视角”下的坐标,统一到同一个“语言”里。BEV感知的核心,就是让所有传感器用同一种语言说话。