周六下午,市体育场的草坪边,教练老周来回踱步。他手下的前锋明明已经跑到了空位,可边裁的旗子就是没举——因为老周站在边线上,视线被防守队员的背挡住,根本看不清远端是否越位。“要是能从天上看到全场就好了。”他低声说。第二天,俱乐部的无人机升到球场正上方,一张俯瞰图传回平板:所有队员的位置、间距、跑动方向,像棋盘一样清清楚楚。老周第一次在“上帝视角”下完成了决策。 自动驾驶汽车也是“站在边线上的教练”。它车顶四角的摄像头,每颗都只能拍到一块透视、有遮挡的局部街景。BEV(Bird's Eye View,鸟瞰视角)感知,就是要给汽车装上那架“战术无人机”——把多路摄像头看到的 2D 图像,转换到一张统一的鸟瞰坐标系中。本文要讲的 LSS(Lift-Splat-Shoot)方法,正是实现这一转换的经典思路:先把每个像素“提起”(Lift)到三维空间,再把这些三维特征“铺洒”(Splat)到地面网格上,最终“发射”(Shoot)出检测结果。听起来像魔法?其实每一步都有清晰的几何逻辑。

岗位关联

掌握 BEV 感知原理,是进入自动驾驶感知、多传感器融合等热门方向的关键一步,能帮你理解 LSS、BEVFormer 等主流模型的核心设计思路,直接对应用人单位对自动驾驶感知算法工程师的核心技能要求。

目录
  1. 可视化演示
  2. BEV感知基础
  3. 图像特征提取
  4. Lift升维
  5. Splat铺洒
  6. 体素池化
  7. BEV应用
  8. 挑战与优化
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示Lift-Splat-Shoot三阶段流水线:多相机2D特征经深度分布预测提升至3D视锥,Pillar池化投影到BEV栅格,CenterPoint检测头完成3D目标感知,含数据流背景动画。

本节配有交互动效(进入视口后自动加载,约 3KB)。

BEV感知基础

周六下午,市体育场的草坪边,教练老周来回踱步。他手下的前锋明明已经跑到了空位,可边裁的旗子就是没举——因为老周自己站在边线上,视线被防守队员的背挡住,根本看不清远端到底有没有越位。“要是能从天上看到全场就好了。”他低声说。第二天,俱乐部的无人机升到球场正上方,一张俯瞰图传回平板:所有队员的位置、间距、跑动方向,像棋盘一样清清楚楚。老周第一次在“上帝视角”下完成了换人决策。

自动驾驶汽车也是“站在边线上的教练”。它的摄像头装在车顶四角,每颗镜头都只能拍到一块透视、有遮挡的局部街景。如果能把多路摄像头的信息拼成一张“天上的俯瞰图”——所有车辆、行人、车道线都在同一个平面坐标下——那么感知、预测、规划都会变得异常直观。这正是 BEV(Bird's Eye View,鸟瞰视角)感知要解决的问题。

在 BEV 感知中,我们不再把感知困在“每一张图像自己的坐标系”里,而是建立一个统一的全局坐标系。从相机坐标系到世界坐标系的刚体变换,由旋转矩阵 $\mathbf{R}$ 和平移向量 $\mathbf{t}$ 描述:

对老周来说,$\mathbf{R}$ 和 $\mathbf{t}$ 就像把每台摄像机“搬”到球场正上方的过程:先让镜头正对地面(旋转),再把它举到球场中心上空(平移)。所有照片终于对到了同一张战术板上。

pw=Rpc+t\mathbf{p}_{w} = \mathbf{R} \mathbf{p}_{c} + \mathbf{t}
通俗理解:只要知道相机在世界中的位置和朝向(外参),就能把相机“眼里”的每一个三维点,挪到世界地图对应的位置上。
  1. 相机坐标点$\mathbf{p}_{c}$ —— 相机坐标系中的三维点,比如“镜头正前方 5 米处”的那个点。
    pc=[xc,yc,zc]⊤\mathbf{p}_{c} = [x_c, y_c, z_c]^{\top}
  2. 旋转矩阵$\mathbf{R}$ —— 描述相机朝向的三个旋转角(俯仰、偏航、翻滚)压成的矩阵,负责把点“转到正方向”。
    R∈R3×3\mathbf{R} \in \mathbb{R}^{3 \times 3}
  3. 平移向量$\mathbf{t}$ —— 描述相机在世界中的位置偏移,负责把点“挪到位”。
    t=[tx,ty,tz]⊤\mathbf{t} = [t_x, t_y, t_z]^{\top}
  4. 世界坐标输出$\mathbf{p}_{w}$ —— 变换后的点,落在统一的鸟瞰世界坐标系里,供后续建图使用。
    pw∈R3\mathbf{p}_{w} \in \mathbb{R}^{3}

图像特征提取

老周拿到高清无人机照片前,先得看清照片里谁是己方前锋、谁是对方后卫。如果只把像素原样交给教练组,那就等于给老周一张没有标注的球员合影——颜色再多,也分不清身份。摄像头的 2D 画面同样需要“认人”这一步,才能从像素变成有语义的特征。

在深度学习中,这个“认人”由主干网络完成。常见做法是用 ResNet 等骨干网络(Backbone)对每路相机图像提取特征。骨干网络经过层层卷积,把 RGB 像素编码为携带语义信息的特征图(Feature Map):浅层特征保留边缘纹理,深层特征记住“这是车、那是人”。为了兼顾大小目标,LSS 常搭配特征金字塔(Feature Pyramid Network),让高层语义和低层纹理融合,使小目标也不漏检。卷积的单个输出位置可写成:

就像老周的助手先给照片里每个人标上名字和队服颜色,骨干网络的输出是一张张“带标签的球员图”——2D 特征图。下一步,就要考虑这些选手在球场上的真正站位了。

fi,j(l)=σ(∑m=0k−1∑n=0k−1Wm,n(l)⋅Ii+m,j+n+b(l))f^{(l)}_{i,j} = \sigma \left( \sum_{m=0}^{k-1} \sum_{n=0}^{k-1} \mathbf{W}^{(l)}_{m,n} \cdot I_{i+m,j+n} + b^{(l)} \right)
通俗说:拿一个 $k \times k$ 的小滑窗扫过图像,在每个位置做加权求和并加偏置,再经过激活函数,得到特征图上的一个值。
  1. 卷积核窗口$\mathbf{W}^{(l)}_{m,n}$ —— 第 $l$ 层卷积核,$k \times k$ 的权重矩阵,像“滤镜”一样扫过图像。
    W(l)∈Rk×k\mathbf{W}^{(l)} \in \mathbb{R}^{k \times k}
  2. 加权求和$\sum_{m=0}^{k-1}\sum_{n=0}^{k-1} \cdots$ —— 把窗口覆盖的 $k \times k$ 个像素与对应权重相乘后累加。
    ∑m=0k−1∑n=0k−1Wm,n⋅Ii+m,j+n\sum_{m=0}^{k-1}\sum_{n=0}^{k-1} \mathbf{W}_{m,n} \cdot I_{i+m,j+n}
  3. 偏置$b^{(l)}$ —— 每个卷积核的偏移量,让输出可以整体上下移动。
    b(l)∈Rb^{(l)} \in \mathbb{R}
  4. 激活函数$\sigma$ —— ReLU 等非线性函数,决定这个位置是否“激活”,让网络能表达复杂模式。
    σ(x)=max⁡(0,x)\sigma(x) = \max(0, x)
  5. 输出坐标$i, j$ —— 特征图上的位置,对应原图某个感受野的中心。
    fi,j(l)∈Rf^{(l)}_{i,j} \in \mathbb{R}

Lift升维

老周的战术板上画着一张俯瞰图,可他的无人机还没起飞。手里只有三台地面摄像机拍到的画面:每台都对着球场的一侧,画面里的球员大小不一、互相遮挡,而且每台摄像机都不知道“他盯着的那个球员到底离自己多远”——有的看着小,可能隔着整个球场;有的看着大,也可能就在眼前。于是助理提出一个大胆想法:“要不先猜一猜每个像素可能飞多远?”

这就是 LSS 中 Lift 步骤的核心:为每个像素估计一个离散的深度分布(Depth Distribution)。假设把从相机到无穷远分成 $D$ 个深度区间(bin),网络为每个像素输出 $D$ 个概率,表示“这个像素属于每个深度的可能性”。它不是一个确定的值,而是一个分布——这正是对深度不确定性的诚实表达。有了深度分布,Lift 用外积把 2D 特征“抬升”为 3D 视锥(Frustum)候选点。设像素 $p$ 的 $C$ 维特征向量为 $\mathbf{f}(p)$,$D$ 维深度分布为 $\mathbf{d}(p)$,外积生成 $C \times D$ 的矩阵:

就像助理给每个球员照片“猜了十种站位距离”,每种猜测都保留一张带概率的胶片。接下来,这些胶片要落到真正的球场地图上——Splat 登场。

V(p)=f(p)⊗d(p)=f(p)⋅d(p)⊤\mathbf{V}(p) = \mathbf{f}(p) \otimes \mathbf{d}(p) = \mathbf{f}(p) \cdot \mathbf{d}(p)^{\top}
通俗说:原来每个像素只有 $C$ 个数的特征,现在在每个深度候选上都复制一份特征,再乘上该深度的概率——从“一个点”变成“一串点”。
  1. 像素特征$\mathbf{f}(p)$ —— $C$ 维向量,比如 64 维的语义特征,描述“这个像素是什么”。
    f(p)∈RC\mathbf{f}(p) \in \mathbb{R}^{C}
  2. 深度分布$\mathbf{d}(p)$ —— $D$ 维向量,各元素和为 1,表示不同深度的概率。
    d(p)=[d1,d2,…,dD]⊤,∑d=1Ddd=1\mathbf{d}(p) = [d_1, d_2, \dots, d_D]^{\top}, \quad \sum_{d=1}^{D} d_d = 1
  3. 外积运算$\mathbf{f}(p) \cdot \mathbf{d}(p)^{\top}$ —— 把列向量和行向量相乘,得到 $C \times D$ 的矩阵。
    f(p)⋅d(p)⊤∈RC×D\mathbf{f}(p) \cdot \mathbf{d}(p)^{\top} \in \mathbb{R}^{C \times D}
  4. 视锥候选$\mathbf{V}(p)$ —— 每个深度对应一列,深度概率越大,该列特征越强。
    V(p)c,d=fc(p)⋅dd(p)\mathbf{V}(p)_{c,d} = f_c(p) \cdot d_d(p)

Splat铺洒

十张胶片叠在手里没有用。老周的助理把每张胶片按照猜测的距离投射到场地的三维模型里:猜得近的,落在禁区附近;猜得远的,落到中场甚至对方半场。然后一松手,所有胶片“哗啦”一声铺洒到足球场的平面网格上。这就是 Splat——把抬升后的 3D 候选点铺回规则的 BEV 地面网格。

Splat 的输入是 Lift 产生的 3D 视锥点,输出是一张 BEV 网格特征图。实现上需要两步:先用相机外参把点在相机坐标系的坐标变换到世界坐标系(用前面的 $\mathbf{R}$、$\mathbf{t}$);再按 BEV 网格的分辨率做离散化,把每个点分配到对应格子。离散化就是把连续坐标“就近取整”到网格索引。设网格左下角原点为 $(x_{\min}, y_{\min})$,每个格子边长为 $s$,那么世界坐标 $(x_w, y_w)$ 对应的网格索引为:

球场上所有球员的胶片最终都“落”进了各自的站位方格。一张整齐的 BEV 特征地图初见雏形——但多台相机对同一个方格可能投进好几份胶片,这就要处理“重叠”了。

gx=⌊xw−xmin⁡s⌋,gy=⌊yw−ymin⁡s⌋g_x = \left\lfloor \frac{x_w - x_{\min}}{s} \right\rfloor, \qquad g_y = \left\lfloor \frac{y_w - y_{\min}}{s} \right\rfloor
通俗说:像把一支飞镖按落点投进对应的方格——先量出它离地图原点多远,再按格子大小算出它在第几行第几列。
  1. 世界坐标$x_w, y_w$ —— 经过外参变换后的地面平面坐标,单位是米。
    (xw,yw)∈R2(x_w, y_w) \in \mathbb{R}^{2}
  2. 网格原点$x_{\min}, y_{\min}$ —— BEV 区域的左下角,通常是感知范围的最小值。
    (xmin⁡,ymin⁡)∈R2(x_{\min}, y_{\min}) \in \mathbb{R}^{2}
  3. 格子边长$s$ —— 分辨率,比如 0.5 米/格,决定 BEV 特征图的精细程度。
    s∈R,s>0s \in \mathbb{R}, \quad s > 0
  4. 向下取整$\lfloor \cdot \rfloor$ —— 保证结果是整数索引,落在整数网格上。
    gx,gy∈Zg_x, g_y \in \mathbb{Z}

体素池化

三台摄像机的胶片同时落在中场同一个方格:一台说这里有个人影,一台说这里有个白点,一台说这里模糊不清。如果直接把三份信息相加,这个格子会“过热”——特征数值虚高,仿佛那里站着三个人。老周的助理说:得把这个格子里投进的胶片数数清楚,取个平均值才行。

LSS 的做法是在每个 BEV 网格内做“求和池化”,得到累积特征;同时记录每个格子被多少个视锥点命中,这个计数称为密度(Density)。最后用累积特征除以密度,得到每个格子的平均特征。之所以必须除以密度,是因为不同相机、不同深度候选可能反复命中同一格子,不归一化会让重叠区域的特征量级失衡。设落在格子 $(i,j)$ 内的所有 3D 点为集合 $\mathcal{B}(i,j)$,密度为 $\mathbf{D}(i,j)$,则该格子的 BEV 特征为:

老周的战术板上,每个方格现在都写着一个“平均站位意见”:重叠越多的区域,意见越可靠。整个球场的统一态势图,终于画出来了。

FBEV(i,j)=∑v∈B(i,j)vD(i,j)\mathbf{F}_{BEV}(i,j) = \frac{ \sum_{\mathbf{v} \in \mathcal{B}(i,j)} \mathbf{v} }{ \mathbf{D}(i,j) }
通俗说:一个格子里所有点的特征相加,再除以点数,得到“平均意见”。密度越大,说明多视角越一致,特征越可信。
  1. 命中集合$\mathcal{B}(i,j)$ —— 所有映射到格子 $(i,j)$ 的 3D 特征点组成的集合。
    B(i,j)={v1,v2,…,vn}\mathcal{B}(i,j) = \{ \mathbf{v}_1, \mathbf{v}_2, \dots, \mathbf{v}_n \}
  2. 分子求和$\sum_{\mathbf{v} \in \mathcal{B}(i,j)} \mathbf{v}$ —— 把格子里每个点的 $C$ 维特征向量逐元素相加。
    ∑v∈Bv∈RC\sum_{\mathbf{v} \in \mathcal{B}} \mathbf{v} \in \mathbb{R}^{C}
  3. 密度$\mathbf{D}(i,j)$ —— 该格子被命中的次数,由 Splat 阶段同时统计出来。
    D(i,j)=∣B(i,j)∣\mathbf{D}(i,j) = |\mathcal{B}(i,j)|
  4. 平均特征$\mathbf{F}_{BEV}(i,j)$ —— 归一化后的输出,防止重叠区域特征量级失真。
    FBEV(i,j)∈RC\mathbf{F}_{BEV}(i,j) \in \mathbb{R}^{C}

BEV应用

俯瞰图摆在老周面前,他终于可以像玩即时战略游戏一样做决策:在图上圈出对方整条防线,量一量前锋和中场之间的空当距离,再写下一个箭头——让左边锋插上。自动驾驶拿到 BEV 特征后,同样可以在“棋盘”上直接做各种判断。

BEV 特征图 $\mathbf{F}_{BEV}$ 是一张规则的网格特征,可以像普通图像一样送入检测头、分割头。在 3D 目标检测中,模型在 BEV 网格上回归每个物体的中心位置、长宽和朝向角;在语义分割中,给每个格子预测道路、车辆、行人等类别;在时序融合中,把过去几帧的 BEV 特征对齐后拼接,供规划模块使用。以 3D 检测头为例,总损失函数通常由分类损失和回归损失加权组成:

就像老周在战术板上既要点出“谁是对方球员”(分类),也要标出“他站在哪、跑多快”(回归)。BEV 把二维的猜谜题,变成了三维棋盘的判断题。

L=Lcls+λLreg=−log⁡p^cls+λ⋅SmoothL1(Δb)L = L_{cls} + \lambda L_{reg} = - \log \hat{p}_{cls} + \lambda \cdot \mathrm{SmoothL1}(\Delta \mathbf{b})
通俗说:一方面让模型把“这儿有车”的概率说对(分类),另一方面让预测框的位置、尺寸贴近真实框(回归),两项加权求和。
  1. 分类损失$L_{cls}$ —— 交叉熵,$\hat{p}_{cls}$ 是模型给出的类别置信度,越接近 1,损失越小。
    Lcls=−log⁡p^clsL_{cls} = - \log \hat{p}_{cls}
  2. 回归损失$L_{reg}$ —— SmoothL1 是抗异常值的回归函数,对较大的偏差也不会给出过大的惩罚。
    Lreg=SmoothL1(Δb)L_{reg} = \mathrm{SmoothL1}(\Delta \mathbf{b})
  3. 框偏移$\Delta \mathbf{b}$ —— 预测框相对真实框的中心、长宽和朝向差值。
    Δb=[Δx,Δy,Δw,Δl,Δθ]\Delta \mathbf{b} = [\Delta x, \Delta y, \Delta w, \Delta l, \Delta \theta]
  4. 平衡权重$\lambda$ —— 人为设定的超参数,控制两项损失各占多大比重。
    λ∈R≥0\lambda \in \mathbb{R}_{\geq 0}

挑战与优化

可老周的无人机不是万能的。下一场是夜场比赛,灯光昏暗;又下起小雨,无人机镜头蒙上水雾——俯瞰图开始模糊。更麻烦的是,当两名球员在画面里几乎重叠时,助理猜的“深度分布”完全分不清谁前谁后。俯瞰图再好,也怕“看不清的源头”。

LSS 最大的误差来源就是深度分布的模糊性。弱纹理区域、远距离目标、遮挡场景下,深度分布往往趋近均匀——什么深度都像,什么深度都不确定。深度分布的不确定性可以用信息熵衡量:分布越平坦,熵越大。对像素 $p$ 的深度分布 $\mathbf{d}(p)$,信息熵定义为:

面对这些挑战,业界有一系列优化策略:轻量化骨干网络与 TensorRT 加速降低计算开销;引入时序信息让深度估计借助运动视差不那么“平”;增加数据增强还原雨天、扬尘等极端场景。LSS 并非终点,但它奠定了“多相机到 BEV”这一范式的基础。就像给老周又添了几架不同载体的无人机——雷达图、红外夜视、更强的算力。它拍得再清楚,也改变不了一个事实:把所有 2D 视角合成统一 3D 视角,永远是自动驾驶绕不开的课题。

H(d(p))=−∑d=1Ddd(p)⋅log⁡dd(p)H\big(\mathbf{d}(p)\big) = - \sum_{d=1}^{D} \mathbf{d}_d(p) \cdot \log \mathbf{d}_d(p)
通俗说:如果深度概率集中在一个深度上,熵很低,说明模型很有把握;如果 10 个深度都有可观的概率,熵很高,说明模型在“瞎猜”。
  1. 深度概率$\mathbf{d}_d(p)$ —— 像素 $p$ 在第 $d$ 个深度区间的概率值。
    dd(p)∈[0,1]\mathbf{d}_d(p) \in [0, 1]
  2. 对数项$\log \mathbf{d}_d(p)$ —— 概率介于 0-1 时对数为负,前面加负号使每个分项非负。
    −log⁡dd(p)≥0- \log \mathbf{d}_d(p) \geq 0
  3. 求和$\sum_{d=1}^{D}$ —— 所有深度区间的贡献相加。
    H=∑d=1D−ddlog⁡ddH = \sum_{d=1}^{D} - \mathbf{d}_d \log \mathbf{d}_d
  4. 熵的含义$H$ —— 数值越大,深度分布越平坦,模型越不确定。
    H∈[0,log⁡D]H \in [0, \log D]

AI 应用场景

自动驾驶多相机BEV感知

阶段:环境感知

解决的问题:传统前视检测只能看到单视角,多相机“后融合”无法形成统一坐标系,车辆在十字路口容易丢失全局态势。AI 通过 LSS 将 6-8 路环视相机统一到 BEV 空间,形成一张 200 米范围的全景感知图,遮挡区域也能由多视角互补。

具体案例:某自动驾驶公司使用 8 路 120° 摄像头,LSS 模型输出 128×128 分辨率的 BEV 特征。在雨夜场景下,准确检测横穿行人,漏检率比传统前视方案降低 38%。

智能路口全息感知

阶段:多传感器融合感知

解决的问题:路口的信号灯优化依赖准确的交通态势,单相机视角窄、存在盲区。AI 把路侧多个鱼眼相机的画面用 LSS 思路合成为路口 BEV 态势图,实时统计各方向车流、行人流量,替代传统物理线圈检测。

具体案例:某智慧城市项目在路口四角部署 4 台鱼眼相机,生成 20m×20m 的 BEV 网格,检测精度达到 95%,信号灯平均等待时间减少 17%。

自动泊车环视拼接

阶段:近场感知

解决的问题:泊车时车身四周盲区大,超声波雷达只能测距不能识别物体类别。AI 用环视相机生成 BEV 俯视图,叠加障碍物轮廓和车位线,让驾驶员像玩“赛车游戏”一样看清周围。

具体案例:某量产车型的自动泊车系统采用 LSS 思路,将 4 路环视相机特征映射到车体 BEV 网格,车位识别成功率从 82% 提升到 96%。

Python 演示

python64 行
"""简化版 LSS(Lift-Splat-Shoot)演示将多相机2D特征提升为3D视锥,再铺洒到BEV网格并池化"""import numpy as np N_CAM = 3        # 相机数H, W = 8, 8      # 2D特征图尺寸D = 10           # 深度离散数(10个深度bin)C = 4            # 特征通道数BEV_SIZE = 16    # BEV网格边长GRID = 1.0       # 每个格子的世界坐标宽度(米) np.random.seed(42) # 模拟2D特征图:每个像素有C维特征features = np.random.randn(N_CAM, C, H, W) * 0.5 # 模拟深度分布:每个像素的D维深度概率(softmax后)depth_logits = np.random.randn(N_CAM, D, H, W)depth = np.exp(depth_logits - depth_logits.max(axis=1, keepdims=True))depth = depth / depth.sum(axis=1, keepdims=True) # 相机位置:三个相机分别位于网格左侧、下方、右侧cam_pos = np.array([[0.0, 8.0], [8.0, 0.0], [16.0, 8.0]]) # Lift:特征与深度做外积,得到3D视锥特征lifted = features[:, :, None, :, :] * depth[:, None, :, :, :]lifted = lifted.reshape(N_CAM, C * D, -1)   # (N_CAM, C*D, H*W) # 像素坐标生成射线方向(简化),Depth bin为离相机距离pix_idx = np.arange(H * W) % Wpix_y = np.arange(H * W) // Wrays = np.stack([pix_idx - W / 2, pix_y - H / 2], axis=1)depth_bins = np.arange(1, D + 1) * 0.8 # Splat:把3D点映射到BEV网格并累加特征bev_grid = np.zeros((BEV_SIZE, BEV_SIZE, C))density = np.zeros((BEV_SIZE, BEV_SIZE)) for nc in range(N_CAM):    for pd in range(H * W):        f_vec = lifted[nc, :, pd].reshape(D, C)        for d in range(D):            wx = cam_pos[nc, 0] + rays[pd, 0] * depth_bins[d] * 0.1            wy = cam_pos[nc, 1] + rays[pd, 1] * depth_bins[d] * 0.1            gx = int(wx // GRID)            gy = int(wy // GRID)            if 0 <= gx < BEV_SIZE and 0 <= gy < BEV_SIZE:                bev_grid[gx, gy] += f_vec[d]                density[gx, gy] += 1 # 池化:除以密度,防止重叠区域特征虚高mask = density > 0bev_grid[mask] = bev_grid[mask] / density[mask][:, None] print("BEV特征网格 shape:", bev_grid.shape)print("非空格子数量:", mask.sum(), "/", BEV_SIZE * BEV_SIZE)print("格子平均特征强度:", bev_grid[mask].mean(axis=1).mean()) # 输出非空格子的热力示意for y in range(BEV_SIZE):    row = "".join("#" if mask[x, y] else "." for x in range(BEV_SIZE))    print(row)
目的:用 NumPy 从零实现 LSS 的核心流程——Lift 外积、Splat 网格映射、体素池化,输出 BEV 特征热力图。
  1. depth = np.exp(depth_logits - depth_logits.max(axis=1, keepdims=True))Softmax 前先减最大值,防止指数溢出。
  2. lifted = features[:, :, None, :, :] * depth[:, None, :, :, :]广播乘法实现特征与深度的外积。
  3. gx = int(wx // GRID)世界坐标按格子边长离散化为网格索引。
  4. bev_grid[gx, gy] += f_vec[d]同一格子内所有特征逐元素累加。
  5. bev_grid[mask] = bev_grid[mask] / density[mask][:, None]除以密度做均值池化,防止重叠区域特征虚高。

常见误区

误区我之前以为 BEV 就是把每张摄像头图像用透视变换拉成俯视图,再像拼图一样拼起来就行了,完全没想到还有“深度”什么事。

正解透视变换(单应矩阵)只在“地面是纯平面”的假设下成立,遇到坡道、立交桥就会错位。LSS 的 Lifted 思路是先为每个像素估计深度分布,再投到 3D 世界坐标系,最后落到 BEV 网格,能处理非平面场景。

为何常见:BEV 俯瞰图看起来确实像“拼接图”,而且很多科普图直接画了“相机图像 → BEV”两步,省略了中间的深度估计环节。

误区以为 Lift 输出的深度就是激光雷达那种精确距离值,一个像素对应一个确定的距离数。

正解Lift 输出的是 $D$ 个离散深度区间的概率分布,表示“这个像素可能出现在这个深度”,而不是确定值。这是为了表达单目几何固有的不确定性,也是 LSS 与 LIDAR 路线的本质区别。

为何常见:人们习惯把“深度估计”理解为精确测距,而且网络输出的深度图可视化很清晰,容易误以为是逐像素精确值。

误区以为把像素提升到 3D 空间后,把点云投到地面就自动得到 BEV 特征了,Splat 和池化只是无关紧要的“后处理”。

正解Lift 产生的是稀疏、离散的视锥点;Splat 还要负责坐标变换、网格离散化和特征投放;最后体素池化要处理重叠。少了任何一步,都无法得到规则、可用的 BEV 特征图。

为何常见:论文一图流经常把 Lift-Splat 画成一个独立模块,读者容易忽略其中还有多个关键子步骤。

误区现在都是端到端训练,相机内外参随便标一下就行,反正网络会自己学。

正解LSS 的 Lift-Splat 是显式几何建模,相机内外参直接决定 3D 投影位置。内参误差会让射线方向偏移,外参误差会让整个 BEV 图错位。工程上标定精度严重制约感知效果。

为何常见:“端到端深度学习”的叙事让人以为几何标定已不重要,而 LSS 恰恰是深度学习和几何标定紧密结合的方法。

面试题

Q1. BEV感知最大的优势是什么?

单选题 · easy

  • A.大幅降低计算开销
  • B.获得统一鸟瞰全局特征← 正确答案
  • C.完全替代激光雷达
  • D.彻底消除感知误差

答案:B。BEV 把多相机信息统一到鸟瞰坐标系,消除遮挡和透视畸变,为下游检测、规划提供全局视角。它并不能替代激光雷达,也无法消除所有感知误差,因此 B 正确。

Q2. LSS中Lift步骤的输入是什么?

单选题 · easy

  • A.二维图像特征图← 正确答案
  • B.三维点云数据
  • C.BEV网格特征图
  • D.激光雷达距离图

答案:A。Lift 发生在图像特征提取之后,输入是骨干网络输出的 2D 特征图,通过深度分布将其提升为 3D 候选点。三维点云和激光雷达数据不是 LSS 的输入。

Q3. 外积运算中C维特征与D维深度相乘得到什么形状?

单选题 · mid

  • A.C维特征×D维深度得C×D矩阵← 正确答案
  • B.C维特征与D维深度相加得标量
  • C.C维特征与C维特征得D维深度
  • D.D维深度与D维深度得C维特征

答案:A。外积 $\mathbf{f} \cdot \mathbf{d}^{\top}$ 将 C 维列向量与 D 维行向量相乘,得到 $C \times D$ 的矩阵,每个深度候选对应一列特征。其他选项混淆了运算类型和维度。

Q4. 为什么用深度分布而非单值深度?

单选题 · easy

  • A.为了提高模型参数量
  • B.像素深度天然伴随不确定性← 正确答案
  • C.分布比单值计算速度更快
  • D.单值无法进行反向传播

答案:B。单目图像存在遮挡和尺度模糊,同一像素可能对应多个深度,深度分布如实表达这种不确定性,LSS 用概率形式做“软选择”。单值深度同样可以反向传播,参数也不是越多越好。

Q5. Splat阶段把3D点放入BEV网格时,主要依据是什么?

单选题 · mid

  • A.像素颜色和亮度值
  • B.相机外参与网格分辨率← 正确答案
  • C.训练数据的总数量
  • D.目标物体的运动速度

答案:B。先用相机外参把点从相机坐标系变换到世界坐标系,再用网格分辨率(格子边长)离散化成网格索引。颜色、数据量、运动速度与落格位置无关。

Q6. 为什么单纯用单应矩阵做BEV变换受限?

单选题 · hard

  • A.只适用近似水平的地面场景← 正确答案
  • B.会导致景深信息完全丢失
  • C.无法处理多个相机的输入
  • D.需要大量标注数据训练

答案:A。单应变换假设场景是平面,坡道、立交桥等非平面区域会产生重影和错位。LSS 用深度分布 + 3D 投影摆脱平面假设,因此 A 正确。单应变换本身是纯几何方法,并不需要训练数据。

Q7. 体素池化中除以密度的主要作用是什么?

单选题 · hard

  • A.防止重叠区域特征值虚高← 正确答案
  • B.提升特征金字塔的深度
  • C.增加深度分布的不确定度
  • D.让BEV特征图更加稀疏

答案:A。同一格子可能被多个相机、多个深度候选反复命中,直接求和会让重叠区域特征量级虚高。除以密度得到平均特征,数值更均衡,与金字塔、不确定性、稀疏度无关。

Q8. BEV感知适合哪些下游任务?

多选题 · mid

  • A.三维空间目标检测← 正确答案
  • B.语义地图分割← 正确答案
  • C.相机外部参数标定
  • D.全局运动路径规划← 正确答案

答案:ABD。BEV 是统一坐标系下的特征表示,目标检测、语义分割、运动规划都能直接使用。相机标定是系统输入条件,不是 BEV 的下游任务。

Q9. LSS中相机内参的作用包括哪些?

多选题 · hard

  • A.把像素坐标转为射线方向← 正确答案
  • B.决定深度分箱的采样范围← 正确答案
  • C.决定特征图通道数量
  • D.将3D点反投影回2D参考← 正确答案

答案:ABD。内参(焦距、主点)把像素坐标映射为归一化射线方向,深度分箱范围依赖内参,3D 点反投影也需要它。特征图通道数由网络结构决定,与相机内参无关。

Q10. 相机外参标定误差在LSS中会造成哪些影响?

多选题 · extreme

  • A.3D投影点的网格位置偏移← 正确答案
  • B.深度分布学到错误参照← 正确答案
  • C.BEV特征出现错位与重影← 正确答案
  • D.完全不影响仅降低推理帧率

答案:ABC。外参误差会让 3D 点方向偏移、深度参照错乱,多个相机的特征会错位叠加产生重影。外参误差影响输出质量;推理帧率取决于算力,与标定误差无关。