2. 坐标系与空间变换:相机坐标系、车辆坐标系、世界坐标系、内参外参、投影变换与逆投影变换

做BEV感知,说白了就是跟坐标系打交道。我刚开始接触这个领域时,最头疼的就是这些坐标系来回倒腾。你想想看,相机看到的是2D图像,但我们要输出的是3D空间中的鸟瞰图,这中间差了整整一个维度。

嗯,今天我们就来彻底搞明白这件事。

2.1 四大坐标系,一个都不能少

在BEV感知中,我们通常要处理四个坐标系。我个人习惯把它们分成两组:传感器坐标系和世界坐标系。

坐标系 原点 轴定义 典型用途
相机坐标系 相机光心 Z轴指向拍摄方向,X向右,Y向下 描述物体相对于相机的位置
车辆坐标系 车辆后轴中心 X向前,Y向左,Z向上 描述物体相对于车辆的位置
世界坐标系 自定义(如GPS原点) 通常X向东,Y向北,Z向上 全局定位与地图构建
像素坐标系 图像左上角 u向右,v向下 图像上的像素位置

我在项目中遇到过一个问题:团队里有人把相机坐标系的Y轴方向搞反了,结果投影出来的BEV图整个上下颠倒。排查了整整两天才找到原因。所以,坐标系定义一定要统一,这是血的教训。

2.2 相机内参:从3D到2D的钥匙

相机内参,说白了就是描述相机本身光学特性的参数。它负责把相机坐标系下的3D点投影到像素平面上。

内参矩阵通常写成这样:

K = [[fx,  0, cx],
     [ 0, fy, cy],
     [ 0,  0,  1]]

其中:

  • fx, fy:焦距,单位是像素。注意,这里不是物理焦距,而是物理焦距 × 像素密度。
  • cx, cy:主点偏移,通常是图像中心,但实际生产中会有偏差。
我的小技巧:拿到一个新相机,第一件事就是标定内参。我曾经用张正友标定法标定过几十个相机,发现同一个型号的相机,内参差异其实挺大的。千万别偷懒用标称值。

投影公式很简单:

pixel_u = fx * (X_cam / Z_cam) + cx
pixel_v = fy * (Y_cam / Z_cam) + cy

为什么会这样?其实就是相似三角形原理。你想想看,相机成像本质上就是小孔成像模型。

2.3 相机外参:把相机放到车上去

相机外参解决的是「相机相对于车辆(或世界)的位置和朝向」问题。它由一个旋转矩阵R和一个平移向量t组成。

P_vehicle = R * P_camera + t

这里有个坑:旋转矩阵的表示方式。我见过有人用欧拉角,有人用四元数,还有人用旋转向量。在BEV感知中,我建议统一用旋转矩阵,因为后续做投影变换时矩阵运算最方便。

避坑指南:我曾经在项目中遇到一个bug,原因是外参的旋转矩阵是「相机到车辆」的,但代码里写成了「车辆到相机」。这两个是互逆关系,搞反了投影结果完全不对。一定要在代码注释里写清楚变换方向。

2.4 世界坐标系:全局的锚点

世界坐标系是BEV感知的终极目标空间。在自动驾驶中,通常以车辆起始位置或GPS原点作为世界坐标系原点。

从车辆坐标系到世界坐标系的变换,其实就是车辆的位姿:

P_world = R_vehicle_to_world * P_vehicle + t_vehicle

这里R_vehicle_to_world和t_vehicle通常来自IMU+GPS的融合定位结果。

2.5 投影变换:从3D到2D的完整链路

把上面所有的变换串起来,就得到了完整的投影公式:

pixel = K * [R_cam_to_vehicle | t_cam_to_vehicle] * [R_vehicle_to_world | t_vehicle_to_world] * P_world

这个公式看起来复杂,但说白了就是:世界点 → 车辆坐标系 → 相机坐标系 → 像素坐标系。

在BEV感知中,我们经常要做的是逆投影变换:给定图像上的一个像素,找到它在世界坐标系中对应的3D点。但这里有个问题——单目相机无法恢复深度信息。

核心难点:逆投影变换是一个「一对多」的映射。一个像素对应的是3D空间中的一条射线,而不是一个点。所以BEV感知必须引入深度估计,或者用多目/激光雷达来提供深度信息。

2.6 逆投影变换的工程实现

在实际的BEV感知系统中,我们通常这样做逆投影:

  1. 预定义BEV网格:在世界坐标系中定义一个固定大小的BEV平面(比如前后各50米,左右各25米),划分成网格。
  2. 计算每个网格中心点的世界坐标:比如网格大小0.5米,那么每个网格中心点都有一个明确的世界坐标。
  3. 投影到图像上:用上面的投影公式,把每个网格中心点投影到各个相机的图像上。
  4. 采样特征:在投影位置采样图像特征,填充到BEV网格中。

这个流程在LSS(Lift-Splat-Shoot)方法中被广泛使用。我个人觉得,理解这个流程是理解BEV感知的第一道门槛。

2.7 知识体系总览

下面这张图总结了本章的核心逻辑:

坐标系与空间变换知识体系 世界坐标系 车辆坐标系 相机坐标系 像素坐标系 车辆位姿 外参(R,t) 内参K 投影变换(3D → 2D) pixel = K · [R|t] · P_world 逆投影变换(2D → 3D) 需要深度估计 + BEV网格预定义 关键:统一坐标系定义,明确变换方向,深度估计是逆投影的核心 外参 内参 投影

2.8 工程实践中的几个坑

最后,分享几个我在实际项目中踩过的坑:

  • 坐标系方向:不同传感器厂商对坐标轴的定义可能不同。比如有的激光雷达Z轴向上,有的Z轴向下。一定要仔细看手册。
  • 外参标定精度:外参标定误差1度,在50米处就会产生约0.87米的偏差。这在BEV感知中是致命的。
  • 时间同步:相机和IMU的时间戳必须对齐。我曾经遇到过因为时间戳偏差导致投影结果抖动的问题。
  • 浮点数精度:在计算投影时,尽量使用double而不是float。尤其是在做逆投影时,精度损失会被放大。
我的建议:在代码中建立一个统一的坐标系管理模块,把所有变换函数封装好。每次新增传感器,只需要注册它的内参和外参,剩下的变换逻辑复用即可。这样既减少了bug,也方便调试。

嗯,坐标系与空间变换这部分就讲到这里。理解了这个基础,后面讲BEV特征提取和时序融合时,你就会觉得顺理成章了。

可可精品资料库