1、 Lift
显示估计图像下采样(16倍)后的特征点深度,将2D图像提升到3D空间,得到图像特征的视锥(点云)。
根据图像和深度均分得到3D视锥索引
下采样16倍,得到特征图大小为 H x W, 每个特征点深度D量化为41。那么得到特征视锥体为H x W x D, 每个特征视锥体对应图像空间(u, v, d)。
源码中为(xs, ys, ds),即将图像和深度均分后得到。最后生成HxWxDx3的视锥体。经过内外参,每个(u, v, d)可转换到bev坐标系(x, y, z)。
2D图像卷积成3D 特征
1、backbone 提取图像特征;
2、一层卷积直接出D+C的维度,D属于深度分布,C是语义特征;
3、分离D维度,对D维深度做 softmax 归一化;
4、将D与C做外积,最终输出的是H×W×D×C;
5 、B×N张图像,对应的输出就是B×N×H×W×D×C
def get_depth_dist(self, x, eps=1e-20):return x.softmax(dim=1)def get_depth_feat(self, x):#主干网络提取特征x = self.get_eff_depth(x)# Depth#输出通道数为D+Cx = self.depthnet(x)#softmax编码,想理解为每个可选深度的权重depth = self.get_depth_dist(x[:, :self.D])#深度值*特征 = 2D特征转变为3D空间(俯视图)内的特征new_x = depth.unsqueeze(1) * x[:, self.D:(self.D + self.C)].unsqueeze(2)return depth, new_x
以上成为CamEncode()。
H×W×D×C 的特征刚好对应 HxWxDx3的视锥体索引。根据索引进行下一步的bev-pooling。
2、Splat
结合内外参,各相机的图像点云特征分配到bev网格,对同一个bev网格对应的多个图像点云特征进行sum-pooling,得到bev 特征图。
如何将H×W×D×C 的特征映射到BEV空间下,需要根据相机内外参将对应的图像空间位置(u,v, d)转换为bev空间位置(x, y, d)。这部分对应为GetGeometry()。
得到 H×W×D 的BEV空间位置索引后即可将 H×W×D 的图像特征映射到对应的BEV网格位置中。
如果有B X N 张图像输入(Batchsize x N 个视角)那么对应BxNxHxWxD 个特征点。这个数据量很庞大,将会是计算瓶颈。
由于图像空间映射到BEV很多点是无效的,直接从H×W×D一一映射将会产生大量无效计算。
1、特征reshape 成 M x C 维度, M = BxNxHxWxD
2、根据内外参,生成BxNxHxWxD个视锥点云BEV空间体素坐标,对每个体素进行位置编码,然后对位置进行argsort(位置排序,输出编码),这样投影到相同bev体素的位置编码相邻。通过位置编码找到图像特征。
由于N张图像均投影到同一个BEV网格下,经过投影,N 维度去除。
最后得到 B×C×Z×X×Y 的BEV特征。Z 量化为1,相当BEV下拍扁。后面就是在BEV 特征空间下的操作。
3、Shoot
在BEV 特征图上进行结果预测,参考centerPoint 等。
不足之处
1、依赖 depth 的显示估计。通过反向传播优化depth 网络效果较差,可以预训练depth 权重进行优化。
2、外积操作过于耗时。特别是精密预测,HxWxD 很大,不利于轻量化部署。