BEV(1)---lift splat shoot

2024-01-14 14:10
文章标签 bev lift splat shoot

本文主要是介绍BEV(1)---lift splat shoot,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 算法简介

1.1 2D坐标与3D坐标的关系

如图,已知世界坐标系上的某点P(Xc, Yc, Zc)经过相机的内参矩阵可以获得唯一的图像坐标p(x, y),但是反过来已知图像上某点p(x, y),无法获得唯一的世界坐标(只能知道P在Ocp这一射线上),只有当深度坐标Zc已知时,我们才可求得唯一的世界坐标P,因此2D坐标往3D坐标的转换多围绕Zc的获取展开。
请添加图片描述

1.2 LSS原理

LSS这篇论文的核心是通过lift模块显式估计图像的深度信息,将2D往3D映射的射线离散化为D段,每段都对应深度的概率分布,从而实现2D图像坐标向3D世界坐标的转换,利用splat模块完成从3D到BEV空间的特征映射,最终利用shoot模块完成自动驾驶中的语义分割任务。

1.3 算法流程

①. 利用Efficientnet-B0主干网络对环视图像进行特征提取。同时借鉴FPN的思想将1/32层上采样与1/16层进行特征融合,获得 [B * N, 512, H / 16, W / 16]的特征输出层。
②. 利用11进行通道缩放,将输出的512通道变为105(41 + 64),其中41代表深度特征,64代表语义特征。
③. 将深度特征进行softmax获得深度信息的概率分布。
④. 深度概率分布与语义特征作外积,构建点云特征。
⑤. 在深度方向上给每个图像点预测一个离散的深度信息(4m~45m,间隔为1m),这样就获得了41个离散的深度值,同时根据对原图的1/16下采样,在x、y方向上划分22
8的网格,将他们stack在一起,便可获得视锥frustum 。
⑥. 利用相机内、外参,将基于图像坐标系的视锥转换为车辆坐标系下的空间位置来表示,其维度也是HxWxDx3,即HxWxD个[x, y, z]。
⑦. 排除掉BEV网格所表示空间范围(以自车为中心100mx100m范围)以外的点,就可以把剩余有效的视锥点云对应的特征分配到每个BEV Pillar里。
⑧. 对于一个BEV Pillar分配多个视锥点,使用QuickCumsum的方法,把视锥点的特征相加,最后得到了200x200x64的BEV特征图。

1.4 优缺点

优:提出了bottom-up式利用显式离散深度估计的方法构建2D转3D模块的方式,给后续任务有很大启发。
缺:深度估计模块只是隐式监督,单纯从2d图像估算深度值,存在很大的估算偏差。
深度估计对训练集和测试集的尺寸较敏感,当两者偏差较大时,深度估计在测试集效果很差。

2. 代码解读

2.1 2D转3D(lift)

2.1.1 生成视锥点云

①. 在深度方向上给每个图像点预测一个离散的深度信息(4m~45m,间隔为1m),这样就获得了41个离散的深度值,同时根据对原图的1/16下采样,在x、y方向上划分22*8的网格,将他们stack在一起,便可获得视锥frustum 。
在这里插入图片描述

def create_frustum():# 原始图片大小  ogfH:128  ogfW:352ogfH, ogfW = self.data_aug_conf['final_dim']# 下采样16倍后图像大小  fH: 8  fW: 22fH, fW = ogfH // self.downsample, ogfW // self.downsample # self.grid_conf['dbound'] = [4, 45, 1]# 在深度方向上划分网格 ds: DxfHxfW (41x8x22)ds = torch.arange(*self.grid_conf['dbound'], dtype=torch.float).view(-1, 1, 1).expand(-1, fH, fW)D, _, _ = ds.shape # D: 41 表示深度方向上网格的数量"""1. torch.linspace(0, ogfW - 1, fW, dtype=torch.float)tensor([0.0000, 16.7143, 33.4286, 50.1429, 66.8571, 83.5714, 100.2857,117.0000, 133.7143, 150.4286, 167.1429, 183.8571, 200.5714, 217.2857,234.0000, 250.7143, 267.4286, 284.1429, 300.8571, 317.5714, 334.2857,351.0000])2. torch.linspace(0, ogfH - 1, fH, dtype=torch.float)tensor([0.0000, 18.1429, 36.2857, 54.4286, 72.5714, 90.7143, 108.8571,127.0000])"""# 在0到351上划分22个格子 xs: DxfHxfW(41x8x22)xs = torch.linspace(0, ogfW - 1, fW, dtype=torch.float).view(1, 1, fW).expand(D, fH, fW)  # 在0到127上划分8个格子 ys: DxfHxfW(41x8x22)ys = torch.linspace(0, ogfH - 1, fH, dtype=torch.float).view(1, fH, 1).expand(D, fH, fW)  # D x H x W x 3# 堆积起来形成网格坐标, frustum[i,j,k,0]就是(i,j)位置,深度为k的像素的宽度方向上的栅格坐标   frustum: DxfHxfWx3frustum = torch.stack((xs, ys, ds), -1)  return nn.Parameter(frustum, requires_grad=False)

②. 利用相机内、外参,将基于图像坐标系的视锥转换为车辆坐标系下的空间位置来表示,其维度也是HxWxDx3,即HxWxD个[x, y, z]。

def get_geometry(self, rots, trans, intrins, post_rots, post_trans):B, N, _ = trans.shape  # B: batch size N:环视相机个数# undo post-transformation# B x N x D x H x W x 3# 抵消数据增强及预处理对像素的变化points = self.frustum - post_trans.view(B, N, 1, 1, 1, 3)points = torch.inverse(post_rots).view(B, N, 1, 1, 1, 3, 3).matmul(points.unsqueeze(-1))# 图像坐标系 -> 归一化相机坐标系 -> 相机坐标系 -> 车身坐标系# 但是自认为由于转换过程是线性的,所以反归一化是在图像坐标系完成的,然后再利用# 求完逆的内参投影回相机坐标系points = torch.cat((points[:, :, :, :, :, :2] * points[:, :, :, :, :, 2:3],points[:, :, :, :, :, 2:3]), 5)  # 反归一化combine = rots.matmul(torch.inverse(intrins))points = combine.view(B, N, 1, 1, 1, 3, 3).matmul(points).squeeze(-1)points += trans.view(B, N, 1, 1, 1, 3)# (bs, N, depth, H, W, 3):其物理含义# 每个batch中的每个环视相机图像特征点,其在不同深度下位置对应# 在ego坐标系下的坐标return points
2.1.2 给视锥点云上的每个点生成特征

①. 利用Efficientnet-B0主干网络对环视图像进行特征提取。同时借鉴FPN的思想将1/32层上采样与1/16层进行特征融合,获得 [B * N, 512, H / 16, W / 16]的特征输出层。
②. 利用1*1进行通道缩放,将输出的512通道变为105(41 + 64),其中41代表深度特征,64代表语义特征。
③. 将深度特征进行softmax获得深度信息的概率分布。
④. 深度概率分布与语义特征作外积,构建点云特征。
如下图中,第三个深度(α2)的概率分布最高,因此α2c的特征最显著。

在这里插入图片描述

2.2 3D转BEV(splat)

有了视锥点云特征,就可以根据视锥点的空间位置把每个视锥点的特征放到BEV网格中的合适位置,组成BEV特征图。

BEV网格由200x200个格子(BEV Pillar)组成,每个格子对应物理尺寸为0.5米x0.5米。即BEV网格对应车辆前、后和左、右各50m,且高度不限的3维空间。

上面通过相机的内外参,已经把视锥点云转换到车辆坐标系下的空间位置。排除掉BEV网格所表示空间范围(以自车为中心100mx100m范围)以外的点,就可以把剩余有效的视锥点云分配到每个BEV Pillar里。

注意,这里存在同一个BEV Pillar可能分配多个视锥点的情况,这是由两个原因引起:

1. 单张2D图像不同的像素点可能投影在俯视图中的同一个位置,例如垂直于地面的电线杆,它成像的多个像素点可能投到同一个BEV Pillar。
2. 相邻两相机有部分成像区域重叠,相机图像中的不同像素点投影在同一个BEV Pillar。例如不同相机画面中的同一个目标。

对于一个BEV Pillar分配多个视锥点,使用QuickCumsum的方法,把视锥点的特征相加,最后得到了200x200xC的BEV特征图,源码中C取64。

def voxel_pooling(self, geom_feats, x):# geom_feats;(B x N x D x H x W x 3):在ego坐标系下的坐标点;# x;(B x N x D x fH x fW x C):图像点云特征B, N, D, H, W, C = x.shapeNprime = B*N*D*H*W # 将特征点云展平,一共有 B*N*D*H*W 个点x = x.reshape(Nprime, C)# ego下的空间坐标转换到体素坐标(范围从-50m~50m,转换为0-200的体素坐标)geom_feats = ((geom_feats - (self.bx - self.dx/2.)) / self.dx).long() # 将体素坐标同样展平,geom_feats: (B*N*D*H*W, 3)geom_feats = geom_feats.view(Nprime, 3)  # 每个点对应于哪个batchbatch_ix = torch.cat([torch.full([Nprime//B, 1], ix,device=x.device,dtype=torch.long) for ix in range(B)])  # geom_feats: (B*N*D*H*W, 4)geom_feats = torch.cat((geom_feats, batch_ix), 1)  # 过滤掉在边界线之外的点 x:0~199  y: 0~199  z: 0kept = (geom_feats[:, 0] >= 0) & (geom_feats[:, 0] < self.nx[0])\& (geom_feats[:, 1] >= 0) & (geom_feats[:, 1] < self.nx[1])\& (geom_feats[:, 2] >= 0) & (geom_feats[:, 2] < self.nx[2])x = x[kept]geom_feats = geom_feats[kept]# 给每一个点一个rank值,rank相等的点在同一个batch,并且在在同一个格子里面ranks = geom_feats[:, 0] * (self.nx[1] * self.nx[2] * B)\+ geom_feats[:, 1] * (self.nx[2] * B)\+ geom_feats[:, 2] * B\+ geom_feats[:, 3] # 按照rank排序,这样rank相近的点就在一起了sorts = ranks.argsort()x, geom_feats, ranks = x[sorts], geom_feats[sorts], ranks[sorts]  # 对每个体素中的点云特征进行QuickCumsum,输出去重之后的Voxel特征,BxCxZxXxY。if not self.use_quickcumsum:x, geom_feats = cumsum_trick(x, geom_feats, ranks)else:x, geom_feats = QuickCumsum.apply(x, geom_feats, ranks)# final (B x C x Z x X x Y)final = torch.zeros((B, C, self.nx[2], self.nx[0], self.nx[1]), device=x.device)  # 将x按照网格坐标放到final中final[geom_feats[:, 3], :, geom_feats[:, 2], geom_feats[:, 0], geom_feats[:, 1]] = x  # 消除掉z维,B x C x 200 x 200final = torch.cat(final.unbind(dim=2), 1)  return final  

cumsum_trick(): 池化累积求和技巧

模型中使用Pillar累积求和池化,“累积求和”是通过bin id 对所有点进行排序,对所有特征执行累积求和,然后减去 bin 部分边界处的累积求和值来执行求和池化。无需依赖 autograd 通过所有三个步骤进行反向传播,而是可以导出整个模块的分析梯度,从而将训练速度提高 2 倍。 该层被称为“Frustum Pooling”,因为它将 n 个图像产生的截锥体转换为与摄像机数量 n 无关的固定维度 CxHxW 张量。

计算原理的过程示意图:
在这里插入图片描述

这篇关于BEV(1)---lift splat shoot的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/605438

相关文章

BEV学习---LSS-1:论文原理及代码串讲

目前在自动驾驶领域,比较火的一类研究方向是基于采集到的环视图像信息,去构建BEV视角下的特征完成自动驾驶感知的相关任务。所以如何准确的完成从相机视角向BEV视角下的转变就变得由为重要。目前感觉比较主流的方法可以大体分为两种: 1、显式估计图像的深度信息,完成BEV视角的构建,在某些文章中也被称为自下而上的构建方式; 2、利用transformer中的query查询机制,利用BEV Query

hdu a strang lift

按得最短路做的,DP 搜索也能搞 #include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <queue>using namespace std;#define MAX_N 10000#define INF 0xfffftypedef pair<int, int> P;in

BEV 中 multi-frame fusion 多侦融合(一)

文章目录 参数设置align_dynamic_thing:为了将动态物体的点云数据从上一帧对齐到当前帧流程 旋转函数平移公式filter_points_in_ego:筛选出属于特定实例的点get_intermediate_frame_info: 函数用于获取中间帧的信息,包括点云数据、传感器校准信息、自车姿态、边界框及其对应的实例标识等intermediate_keyframe_align

【自动驾驶】浅学一下BEV目标检测记录

现在BEV与OCC占用网络非常火,在日常工作中,如果没有接触到,可能会忽略相应的知识储备。本人还未看大量文献,所以只能算浅学下记录,这里主要从互联网上学习到的,还是就是跟专业的同事请教之后,自己总结的。 1.BEV视角 BEV视觉其实是全局俯视图,更好的得到其他障碍物到自车的横纵向距离。在2D检测的时候,对于深度(其他障碍物离自车的纵向距离)估计不是很准。 2.BEV数据标签

【Java】Java小游戏之Shoot游戏源码及详解

【Java】Java小游戏之Shoot游戏源码及详解 Shoot游戏是模仿微信中打飞机小游戏,这个游戏虽然简单,但通过这个游戏小项目,可以练习很多小的知识点,提高对面向对象的理解,还能提高逻辑思维能力。总之,好处多多,下面我将对游戏的结构及代码进行详细说明: 游戏运行状态界面: 1)游戏中类的结构图: 2)游戏步骤01: 1.class FlyingObject{ima

Codeforces 479E Riding in a Lift(dp)

题目链接:Codeforces 479E Riding in a Lift 题目大意:有一栋高N层的楼,有个无聊的人在A层,他喜欢玩电梯,每次会做电梯到另外一层。但是这栋楼里有个秘 密实验室在B层,所以每次他移动的时候就有了一个限制,x为当前所在层,y为目标层,|x - y| < |x - b|。问说移动K次 后,有多少不同的路径。 解题思路:dp[i][j]表示在第i步到达j层

Bev算法在J5平台的部署

文章目录 1. 介绍1. 1 Bev的优势1. 2 视角转换13 Bev 感知总体框架 2 IPM 方案2.1 性能指标2.2 Backbone2.3 视角转换2.3 坐标系转换2.4 grid sample采样原理2.5 IPM空间融合2.6 IPM-Neck2.7 多任务头2.7.1 分割头2.7.2 检测头

自动驾驶---Perception之IPM图和BEV图

1 前言         IPM(Inverse Perspective Mapping,逆透视变换)图的历史可以追溯到计算机视觉和图像处理领域的发展。逆透视变换是一种用于消除图像中透视效应的技术,使得原本由于透视产生的形变得以纠正,进而更准确地描述和理解图像中的场景。比如在行车中的车道线检测,泊车中的常见障碍物检测,自动驾驶感知最开始的方案基本都离不开IPM图。        早期,自动驾驶

经典文献阅读之--U-BEV(基于高度感知的鸟瞰图分割和神经地图的重定位)

0. 简介 高效的重定位对于GPS信号不佳或基于传感器的定位失败的智能车辆至关重要。最近,Bird’s-Eye-View (BEV) 分割的进展使得能够准确地估计局部场景的外观,从而有利于车辆的重定位。然而,BEV方法的一个缺点是利用几何约束需要大量的计算。本文《U-BEV: Height-aware Bird’s-Eye-View Segmentation and Neural Map-bas

LSS (Lift, Splat, Shoot)代码解析

文章目录 论文研究背景算法实现过程梳理一、相关参数设置二、模型相关参数三、算法前向过程 论文研究背景 LSS是一篇发表在ECCV 2020上有关自动驾驶感知方向的论文,具体子任务为object segmentation and map segmentation。论文和官方repo如下: 论文:https://link.zhihu.com/?target=https%3A//ar