自动驾驶为什么突然都在讲BEV?传统2D感知到底卡在哪?LSS凭什么成为BEV感知的“鼻祖”?1. 痛点:2D感知的“盲人摸象”
如果你写过自动驾驶感知代码,一定踩过这些坑:
透视投影的歧义:相机将3D世界压成2D图像,近大远小。一个行人在图像上只有100像素高,你无法判断他是在10米外还是20米外。
后融合之殇:每个相机独立检测2D目标,再通过IPM(逆透视变换)或三角测量拼到3D空间。不同相机检测结果不一致、遮挡导致漏检、融合规则复杂到崩溃。
时序信息浪费:单帧2D检测难以利用历史帧,速度估计靠“猜”。
BEV(Bird‘s-Eye-View,鸟瞰视图)方案彻底改变了游戏规则——所有传感器特征统一映射到一个俯视的栅格空间,感知、预测、规划都在同一个坐标系下沟通。
2. LSS:BEV感知的“开山之作”
LSS(Lift-Splat-Shoot)来自论文《Lift, Splat, Shoot: Encoding Images from Arbitrary Camera Rigs by Implicitly Unprojecting to 3D》。名字很形象:先“举起”2D特征到3D,再“拍平”到BEV。
核心步骤拆解
Step 1: Lift —— 给每个像素预测一个深度分布
2D图像上的一个像素,对应3D空间中的一条射线。LSS不直接回归一个确切深度,而是把深度离散化为 D 个 bins(比如 [1m, 2m, ..., 60m])。对于每个像素,网络输出:
特征向量 c(C维)
深度概率分布 α(D维,和为1)
于是这个像素被“举起”成 D 个3D点,每个点的特征为 α_d * c,坐标由相机内参/外参 + 深度值 d 计算得到。
代码示意(伪代码):
# img_feat: [B, C, H, W]# depth_prob: [B, D, H, W]B, C, H, W = img_feat.shapepoints_3d = []for b in range(B): for u in range(W): for v in range(H): for d_idx in range(D): depth = depth_bins[d_idx] x, y, z = uv_depth_to_camera(v, u, depth) # 转到相机坐标系 x_ego, y_ego, z_ego = camera_to_ego(x, y, z) # 转到自车坐标系 feat = img_feat[b, :, v, u] * depth_prob[b, d_idx, v, u] points_3d.append((x_ego, y_ego, z_ego, feat))
Step 2: Splat —— 将3D点投影到BEV栅格
把自车周围(比如 [-50m, 50m] 范围)划分为网格,每个格子分辨率 0.5m × 0.5m。每个3D点根据其 (x, y) 坐标落入某个栅格。所有落到同一个栅格的特征做累加或平均,形成BEV特征图 [B, C, H_bev, W_bev]。
Step 3: Shoot —— 在BEV上完成下游任务
有了BEV特征,就可以直接接检测头(CenterPoint、BEVDet的Head)或分割头,输出3D框、车道线、路沿等。
3. 工程实现的硬核细节
LSS看似简单,落地时处处是坑:
深度分布监督:需要LiDAR点云作为真值,将点云投影到图像上,落在哪个深度 bin 就给对应位置 one-hot 标签。没有LiDAR的车厂只能仿真或买数据。
计算量爆炸:每张图 H×W×D 个3D点(比如 224×400×60 ≈ 537万个),再 splat 到 BEV。优化手段:
相机外参标定误差:几厘米的平移或0.1°的旋转,就会导致投影偏差。训练时可加入外参噪声做数据增强。
4. LSS 的宿命:优点与局限
| 优点 | 局限 |
|---|
| 几何可解释性强,深度分布符合物理 | 深度估计不准时,BEV特征“糊成一片” |
| 易于扩展环视相机(n个相机独立lift再合并splat) | 计算量大,实时性受限于栅格分辨率 |
| 支持多模态融合(BEVFusion 加LiDAR特征) | 对超出深度范围的目标无能为力 |
LSS 之后的 BEVDet、BEVDepth、FastBEV 都在它的骨架上做了手术,但本质仍是“2D→3D→BEV”的范式。直到 Transformer 家族出现,BEV感知才迎来第二幕。
小结:LSS 教会了行业如何用“软深度”实现环视相机到BEV的转换。虽然如今很多方案转向 Transformer,但 LSS 的“Lift-Splat”思想仍然是所有基于深度分布的方法的基石。