资讯详情

资讯详情

RCBEVDet:毫米波雷达与环视相机BEV前融合实战

1. 为什么偏要在相机 BEV 体系里加一路毫米波雷达做 BEV 3D 目标检测这几年视觉方案几乎成了默认答案环视相机便宜、图像语义丰富、bev 特征图一铺开检测头接上去就能出框。我刚接触 RCBEVDet 这个方向时也犯嘀咕——雷达点云一帧就那么几百上千个点角分辨率稀得可怜看着像撒了一把胡椒在自车周围凭什么能帮上忙。真正在车上跑过一段时间、经历过几次逆光和暴雨之后我的看法彻底变了不是雷达能帮上忙而是在某些场景里缺了它就没有保底方案。RCBEVDet 是围绕毫米波雷达与环视相机的前融合 BEV 检测展开的一套方案核心目标是把雷达的测距准、抗恶劣天气、带径向速度这几项能力塞进原本纯视觉的 BEV 检测框架里而且不是简单在检测框层面做后融合而是在 BEV 特征层面就把两路信息揉到一起。它适合的人群很明确已经跑通过一套纯视觉 BEV 检测不管是 LSS 系还是 query 系想要在雨雾、夜间、远距离这几个薄弱环节上补一刀的算法工程师也适合刚入门 BEV 感知、想搞清楚“多模态到底怎么融”的同学当做拆解样本。如果你连 BEV 特征图怎么来的都还没搞明白建议先把单模态跑通再来不然踩坑时会分不清是融合的问题还是底座的问题。1.1 纯视觉 BEV 绕不过去的三个物理限制相机本质上是个被动的光子接收器这句话说起来轻描淡写落到实车上就是三条硬约束。第一条是光照。逆光时前视相机对着太阳画面里前车只剩一个剪影夜间无路灯路段曝光拉长之后运动模糊直接把行人糊成一团。这类场景下图像特征的质量是断崖式下跌的不是靠数据增强能补回来的因为你喂进去的像素里本来就没有信息。第二条是散射介质。雨、雾、扬尘、前车卷起的水雾都会让图像对比度整体塌陷。我印象最深的一次是傍晚小雨雨刮刚刮过的那一帧还能看清车道线下一帧又被水膜糊住检测结果在两帧之间反复跳。这种抖动对下游规控来说是灾难。第三条是深度估计的几何衰减。基于环视几何的 BEV 方案深度精度随距离增长而下降越远越糊。而 BEV 网格往往铺到 50 米甚至更远远端的检测框位置误差会被放大。雷达不一样它靠飞行时间直接测距测距误差跟距离基本无关。1.2 雷达的“糙”里藏着两样相机给不了的东西很多人嫌弃雷达点云稀疏这个判断只对了一半。稀疏是事实但雷达点里有两个通道是图像根本产生不了的。信息维度相机毫米波雷达对检测的价值稠密语义/纹理强无分类、区分车型与行人直接径向测距间接三角化直接飞行时间远距离定位精度径向速度多普勒需多帧估计单帧直接输出区分静止物与运动目标RCS 反射强度无有材质/尺寸的粗线索雨雾鲁棒性差好恶劣天气保底高度信息有多数量产型号缺失需靠图像补径向速度这一项的价值经常被低估。一个在高速上静止的故障车视觉上看它和慢速行驶的车在单帧里几乎没有区别必须靠多帧关联才能分辨雷达单帧就能告诉你“这个目标的多普勒是 0”直接把它标成静止障碍物。RCS则是个粗糙但有效的材质探头金属车身的反射截面和行人的反射截面量级差得很远在图像过曝或欠曝时能当个兜底判据。代价也要说清楚量产毫米波雷达多数没有可靠的高度输出点云基本压在一个水平面上角度分辨率差相邻两个目标容易糊成一个多径反射会造出“幽灵目标”隧道壁、护栏、金属井盖都是重灾区。RCBEVDet 这类方案的设计难点一大半都花在怎么把这种“高置信度但低分辨率”的信号和“高分辨率但受环境影响大”的图像信号对齐到同一张 BEV 图上。1.3 RCBEVDet 的整体数据流长什么样把整条链路摊开看它其实分三条支路再汇合图像支路多路环视图像进 2D backbone 提特征再经视角转换模块LSS 式的深度分布加权或者 query 式的 BEV 采样压到统一的 BEV 网格上得到图像 BEV 特征。雷达支路原始点云先做逐点特征提取这一步会拿图像特征做引导然后把散点 scatter 到 BEV 网格过一个 BEV 编码器得到雷达 BEV 特征。融合支路两路 BEV 特征在 backbone 的多个层级上做跨注意力融合融合后的特征送进检测头出 3D 框。注意这里有个关键设计融合不是只在最后一层做一次。浅层特征分辨率高、位置信息准深层特征语义强、感受野大只在深层融合会丢掉小目标的定位精度只在浅层融合又拿不到足够的语义来做分类。多层融合是这套方案能同时兼顾远近目标的原因。2. 把稀疏点云变成 BEV 特征图雷达编码器的取舍这一块是整套方案里我认为最值得细看的部分。直接把点云 voxel 化再套一个 3D 卷积在小规模雷达数据上是跑不出东西的——点太少了卷出来的特征图大片空白卷积核扫过去全是零。2.1 为什么非要用图像特征去“指导”点云编码单看一个雷达点它携带的信息是x、y、z多数情况 z 不可靠、径向速度、RCS、时间戳。满打满算五六个有效维度。光靠几层 MLP 从这几维里学出“这是轿车还是卡车”的判别特征理论上可行、实际上很难收敛因为同一种车型的 RCS 分布方差很大不同车型的分布又会重叠。RCBEVDet 的做法是把点投影到图像平面上在对应的像素位置双线性采样图像特征拼到点特征后面。打个比方这相当于给每个雷达点贴一张“它落在画面哪个位置、那里的纹理长什么样”的小纸条。贴完之后点特征的维度从个位数涨到几百维语义信息一下就丰富了。这个操作看起来简单实操里三个地方最容易翻车投影越界。BEV 范围铺到 50 米但相机 FOV 覆盖不了那么宽大量雷达点会投到图像边界外。我的处理是把越界点的图像特征置零同时加一个 valid mask 通道告诉网络“这个点的图像信息不可信”。不加 mask 的话网络会把零向量当成一种真实特征去学反而污染。采样位置精度。双线性采样默认像素坐标系是连续的但标定参数里如果内参有半个像素的偏差采到的特征就会整体偏移。这个误差在近处不明显远处会放大。通道维度对齐。图像 backbone 不同 stage 的输出通道数不同选哪一层去采样直接影响效果。用太浅的层语义不够用太深的层分辨率又太低一个雷达点采到的可能是一整块区域的均值。我的经验是用中间层分辨率降采样 8 倍那一档。2.2 RCS 和径向速度这两个通道的预处理这两列数据的处理细节文档里一般不会写但处理不好会直接拖垮收敛。RCS 的动态范围极大。金属车身的 RCS 可能到几十 dBsm行人只有个位数甚至负值。直接喂原值网络会被少数大值主导。标准做法是先截断到某个区间比如 -20 到 40 dBsm再做线性归一化或者 log 压缩。截断阈值要根据你手上雷达型号的实际统计分布来定别照抄别人的数字——不同厂家的增益标定差别很大。我一般会先跑一遍全量数据的直方图看 1% 和 99% 分位数落在哪据此定截断边界。径向速度的坐标系转换是最容易出错的地方。雷达输出的是沿视线方向的相对速度转到自车坐标系需要按方位角做投影分解得到 vx 和 vy。这里有两个陷阱一是符号约定多普勒的正负在不同厂家定义相反二是自车运动补偿如果你的雷达输出没有扣掉自车速度那么所有静止物体都会带一个和车速等大的反向速度模型会把它学成“所有背景都在动”。我在这上面浪费过整整两天最后发现是自车信号没接进去。2.3 scatter 到 BEV 网格时那几个不显眼的选择散点转规则网格这一步代码量不大但参数选择影响很大。网格分辨率的选择是个平衡0.4 米一格点云细节保留得多但每个格子里平均不到一个点特征图极其稀疏0.8 米一格稀疏性缓解了但两个相邻目标容易落进同一格。RCBEVDet 这类方案通常选在和图像 BEV 网格一致的尺度上因为后面要融合分辨率不一致就得插值插值本身又会引入位置误差。多点落入同一格子怎么聚合也有讲究。max pooling 能保留最强的反射但会丢掉速度信息——同一个格子里一辆车和一个护栏max 之后只剩护栏的强反射车就消失了。我倾向于分通道做不同的聚合RCS 用 max速度用 mean同时额外保留“格内点数”作为一个通道让网络自己判断这个格子可不可信。提示BEV 网格的原点偏移和 y 轴朝向雷达支路和图像支路必须完全一致。这个错位是最隐蔽的 bug因为两路特征各自看起来都正常只有融合之后才会表现出“框整体偏移一个固定距离”。验证方法很简单把两路 BEV 特征各自降维到单通道可视化出来叠在一起看车道线之类的静态结构是否重合。# 散点聚合伪代码重点在分通道聚合与有效点计数 import torch def scatter_to_bev(points, feats, bev_range(-51.2, 51.2), res0.4): # points: [N, 3] (x, y, z) 自车坐标系 # feats: [N, C] 其中 C 包含 rcs, vx, vy 等 grid int((bev_range[1] - bev_range[0]) / res) ix ((points[:, 0] - bev_range[0]) / res).long().clamp(0, grid - 1) iy ((points[:, 1] - bev_range[0]) / res).long().clamp(0, grid - 1) linear ix * grid iy # 展平索引 bev torch.zeros(1, feats.shape[1], grid, grid, devicepoints.device) # RCS 通道用 scatter_reduce 的 amax其余用 mean bev[..., 0] torch.zeros(grid * grid, devicepoints.device).scatter_reduce( 0, linear, feats[:, 0], reduceamax, include_selfFalse ).view(grid, grid) # 有效点计数通道帮助网络判断该格子置信度 cnt torch.zeros(grid * grid, devicepoints.device).scatter_add( 0, linear, torch.ones_like(linear, dtypetorch.float) ).view(grid, grid).clamp(max8.0) / 8.0 bev[..., -1] cnt return bev3. 两路特征的对齐与跨注意力融合融合模块是整个方案里最“看起来高级”的部分但我个人的经验是八成的融合效果由对齐质量决定只有两成来自注意力模块本身的设计。对齐没做好再花哨的注意力机制也只是在错误的空间位置上做加权。3.1 空间对齐融合效果下降的首要原因对齐包含三件事任何一件出问题都会让融合变成负收益。外参标定是第一件。相机和雷达的安装位置不同从雷达到相机的变换矩阵哪怕差 0.5 度俯仰角在 50 米处就会造成近 0.5 米的纵向偏差。这个偏差在近处感知不到远处足以让两个相邻车道的目标混淆。我的做法是先用静态标定给出初值再用一段直线行驶数据做在线微调找路边的连续护栏或长直车道线雷达点应该在图像上贴合其边缘用这个残差反向优化外参。时间同步是第二件。雷达通常 10 到 20 Hz相机 10 到 30 Hz两者的采样时刻往往差几十毫秒。车速 30 米每秒时50 毫秒就是 1.5 米的位置差——这个量级已经超过一个车宽了。必须用硬件的同步信号做触发或者至少用时间戳做运动补偿把雷达点按自车运动外推到图像曝光时刻。软件层面忽略这一点的项目我见过不止一个表现就是“融合后高速场景变差、低速场景变好”。运动畸变是第三件。雷达在旋转扫描时一帧内的点其实是在不同时刻采到的车在动点云就会歪。帧率低、车速高的时候尤其明显。补偿方法是按每个点的相对采集时刻做外推需要雷达驱动把逐点时间戳透传上来——很多驱动默认不给得去翻手册。注意标定自检有个土办法但特别有效——把雷达点按标定参数投到图像上用不同颜色标出距离远近比如近处红色、远处蓝色然后找一段有清晰车辆轮廓的场景看叠加图。如果近处贴合、远处发散多半是外参角度有问题如果整体平移那是平移分量错了如果远近都贴但横向偏检查是不是坐标系手性搞反了。3.2 跨注意力里 query 和 key 该给谁RCBEVDet 用的是跨注意力形式的多层融合。这里有个设计选择值得展开谁是 query谁是 key/value。我的理解是让雷达 BEV 特征做 query、图像 BEV 特征做 key/value更符合两者的信息特性。雷达点虽然稀疏但每一个都是“这里确实有东西”的高置信度证据图像特征稠密但可能被光照欺骗。让雷达去提问、图像来回答等于用雷达的几何可靠性去约束图像特征的采样位置避免了图像里大片背景区域对融合特征的稀释。反过来做也能work但你会发现在雨雾天图像整体退化时以图像为 query 的融合会把噪声放大。双向交叉注意力当然更强代价是计算量翻倍。计算量这块必须有清醒认识。BEV 特征图假设是 128×128通道 128标准注意力的复杂度是 O((HW)²)直接算根本跑不动。所以实际实现要么用可变形注意力每个 query 只采样固定数量的参考点要么做窗口化局部注意力要么在融合前先降采样。可变形注意力是我比较推荐的它天然适合这种“稀疏查询、稠密键值”的场景还能顺带学出每个雷达位置应该往哪个图像区域看。3.3 融合层放在哪几层不是拍脑袋决定的融合位置特征分辨率语义强度适合弥补的问题代价仅深层低如 16×16强分类混淆、大目标小目标定位精度损失明显仅浅层高如 128×128弱小目标、远距离定位分类头拿不到足够语义多层本方案多尺度兼顾远近目标共存显存与算力开销上升多层融合的实操要点是融合权重的初始化。如果融合模块一开始就输出很大的值相当于在训练初期用噪声覆盖掉预训练好的图像特征收敛会非常慢甚至崩掉。我的做法是把融合分支的输出投影层初始化为接近零等于让模型一开始退化成纯图像检测器随着训练推进再逐步“打开”雷达信息。这个技巧在多个项目里都救过我。4. 训练策略雷达和图像不能共用一套增强多模态训练最容易犯的错是把单模态那套训练配方直接搬过来。雷达数据的统计特性和图像差得太远增强策略、学习率、损失权重都得单独考虑。4.1 数据增强必须成对设计几何类增强翻转、旋转、缩放两路必须严格同步而且坐标系变换要一一对应。图像水平翻转对应的是自车坐标系 y 轴取反雷达点的 y 坐标也要取反、方位角要取补角、径向速度的横向分量也要变号。这串操作漏掉任何一个就会出现“图像里的车在左边、雷达点跑到右边”的错位而这种错误在 loss 曲线上完全看不出来只会在最终指标上表现为莫名其妙的掉点。雷达特有的增强里随机丢点很有效。按 10% 到 20% 的比例随机丢弃点模拟雨雾衰减和远距离回波丢失能显著提升模型在恶劣天气下的稳健性。目标级复制粘贴把一个目标的点云抠出来贴到另一个位置对小目标召回提升明显但要注意粘贴位置的多普勒速度要重新计算否则会造出“以 80 迈速度静止”的物理上不可能的目标模型可能学到错误关联。图像侧的增强照常做但颜色抖动要克制。雷达分支的逐点特征是从图像特征采样来的如果图像被调得面目全非雷达点采到的引导特征也会跟着失真等于两路一起被污染。4.2 类别不平衡在雷达模态上被放大图像里一个远处的行人好歹还有几十个像素雷达里可能就是两三个点。这种“双重稀疏”让远距离小目标的召回率成为整个系统的短板。我一般会按距离分桶0-20 米、20-35 米、35-50 米、50 米以上分别统计各类别的召回而不是只看总体 mAP。总体指标好看但远距离行人召回只有 30% 的情况非常常见而这个短板在实车上恰恰最致命。针对性的处理包括给远距离目标的回归损失加权、在采样时对含远距离正样本的帧做超额采样、以及适当提高 BEV 网格在远处的分辨率如果算力允许。4.3 收敛节奏上的几个观察图像分支用纯视觉预训练权重初始化雷达分支和融合模块随机初始化这个组合的直接后果是训练前期两路特征分布差异巨大融合模块的梯度噪声很重。我的处理是给雷达分支和融合模块单独设一个更小的初始学习率配 1 到 2 个 epoch 的 warmup等两路特征尺度接近了再统一学习率。另一个观察是融合模块真正开始起作用的时间点。可以定期把融合分支关掉输出置零跑一次验证对比开与关的指标差。我实测下来前几个 epoch 关闭融合的指标反而更高大概在总训练进度的三分之一处才反超之后差距持续拉大。如果你发现训练到一半融合仍然是负收益别急着调结构先回去查对齐。5. 实测中绕不开的几个问题5.1 融合之后指标不升反降排查顺序怎么定这是最高频的问题。我的排查链路是固定顺序的因为它按“可能性从高到低”排列先确认单模态基线是干净的。把融合模块旁路掉只留雷达支路单独出检测结果看它能不能在自己模态上跑出一个合理的数。如果纯雷达基线本身就不行融合不可能救回来。查对齐。按前面说的方法把雷达点投到图像上可视化重点看 30 米以外的区域。这一条能解决我遇到问题的六成以上。查融合权重的分布。把跨注意力的注意力图可视化出来如果注意力均匀铺满整个 BEV 图说明它根本没学到“该看哪”如果全集中在某一小块可能是位置编码出了问题。查增强是否引入错位。把增强关掉重训一个短周期对比指标。这一步能排除掉大部分“莫名其妙”的退化。最后才怀疑结构设计。说实话在我处理过的情况里真正需要改网络结构的不到两成。5.2 幽灵目标雷达特有的误检来源金属井盖、护栏、隧道壁、大型车辆的侧裙都会产生多径反射在 BEV 上表现为一串位置固定但速度异常的虚假目标。这类误检对纯视觉方案来说几乎不存在是引入雷达之后新增的负担。压制手段有三层RCS 与速度的一致性检验——静止的金属结构 RCS 很高但速度必须是零扣掉自车运动后如果一个高 RCS 目标带着非零速度多半是反射假象高度过滤——如果你的雷达有哪怕粗略的高度输出把明显高于或低于地面一定范围的点剔掉时序一致性——真实目标在多帧之间的位置变化符合运动学幽灵目标往往是跳变的。第三层最有效但会引入延迟实时系统里要权衡。5.3 恶劣天气下到底能赚多少这块我不喜欢给漂亮的数字因为收益高度依赖具体雷达型号和场景分布。定性的结论是中雨、扬尘、逆光这几种场景下融合方案相对纯视觉的召回提升是明显的尤其是 30 米以外的目标和静止障碍物大暴雨时增益会收窄因为雨滴本身会产生杂波雷达点云里多出一层弥漫的低 RCS 噪声需要额外做滤波。雾天反而是雷达的主场能见度降到几十米时视觉基本失效雷达还能稳定输出测距。代价是有的暴雨场景下如果不做杂波抑制融合方案的误检率会比纯视觉高。我的经验是加一个基于 RCS 和点密度的前置滤波雨滴的回波强度普遍偏低且空间分布弥散用一个简单的阈值加邻域密度判断就能滤掉大半。6. 部署侧的现实约束6.1 算力账要先算清楚跨注意力融合的开销不能想当然。以 128×128 的 BEV 特征、128 通道为例可变形注意力在每个 query 采样 4 个点的设定下单层融合的浮点运算量大致在几 GFLOPs 量级多层叠加再加上图像 backbone 和 BEV 转换模块整体很容易超出车端芯片的预算。降本的手段按性价比排序融合层只保留两到三层而不是每层都融、在融合前对 BEV 特征做通道压缩、把雷达支路的 BEV 编码器换成深度可分离卷积、可变形注意力的采样点数从 4 降到 2。最后一项降得最狠但精度损失也最明显我一般放在最后考虑。6.2 量化时那些不报错但掉点的算子雷达支路里 scatter 类的操作在部分推理框架上不支持量化会退回到浮点执行形成一个隐性的性能瓶颈。跨注意力里的 softmax 和位置编码对量化也比较敏感int8 之后注意力分布容易塌缩成近似均匀分布。我的做法是分层策略图像 backbone 和检测头正常量化融合模块和雷达编码器先保持 fp16验证精度损失在可接受范围后再逐步下探。另外一定要做逐层输出比对把量化模型和浮点模型在每一层的输出余弦相似度都算一遍找出第一个明显掉下来的层。只看最终指标的话你很难定位是哪一层出的问题。6.3 标定漂移是个长期问题车开久了轻微碰撞、悬挂老化、温度变化都会让外参慢慢偏掉。离线标定再准跑三个月也会漂。实际项目里必须有一套在线监控用静止目标护栏、路面反射或者长直车道线作为参照持续统计雷达点投影到图像上的残差超过阈值就报警或者触发在线重标定。这套机制我在项目后期才加上代价是前期有好几例“用户反馈某些场景检测框整体偏左”的问题查到最后都是标定漂移而不是算法本身。我个人在这个方向上折腾下来最深的体会是多模态融合的收益上限由传感器本身的互补性决定但你能拿到多少几乎完全取决于工程细节——标定、同步、坐标系、预处理归一化这些“不性感”的部分。网络结构改来改去带来的提升往往还不如把投影对齐误差从 0.5 米压到 0.1 米来得实在。如果让我给刚上手的人一句建议那就是先把纯雷达单模态跑到一个能看的水平再谈融合这一步跳过去后面所有的调参都会变成盲猜。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →