【玩转PointPillars】PillarScatter操作

41 篇文章 48 订阅
15 篇文章 0 订阅

    在PFN阶段只是对非空Pillar进行了特征提取,按照PointPIllars的默认设置,每个非空Pillar经过PFN后表示为一个通道数为64的特征向量。最后PFN阶段的输出feature-map尺寸为(C,P),C表示通道数,P为PIllar的数量。但是,因为不同点云帧P的数量是不固定的,再送入下以阶段之前还要做一个PillarScatter的操作。

查看源图像

                                                                    图:点云的Pillar化过程

 这里引用论文中的一段原话,也就是将点云特征投射回Pillar在原始网格中的位置。根据设定,PointPillars在点云空间X-Y平面上划分了固定大小的网格。 假如点云的空间范围(point_cloud_range)为:[0, -39.68, -3, 69.12, 39.68, 1],单个Pillar的尺寸(pillar_size)为:[0.16,0.16,4],可以通过point_cloud_range/pillar_size计算的网格的尺寸为[432,496,1],这里依次是X,Y,Z三个方向。不考虑Z方向,则X-Y网格尺寸为[432,496]。

class PointPillarsScatter(nn.Module):
    def __init__(self,
                 output_shape,
                 num_input_features=64,
                 batch_size=2):
        """
        Point Pillar's Scatter.
        Converts learned features from dense tensor to sparse pseudo image. This replaces SECOND's
        second.pytorch.voxelnet.SparseMiddleExtractor.
        :param output_shape: ([int]: 4). Required output shape of features.
        :param num_input_features: <int>. Number of input features.
        """
        super().__init__()
        self.name = 'PointPillarsScatter'
        #[1,496,432]是grid_size(z,y,x)?
        self.output_shape = output_shape #shape[1, 1, 496, 432, 64]
        self.ny = output_shape[2]
        self.nx = output_shape[3]
        self.nchannels = num_input_features #64
        self.batch_size = batch_size

    # def forward(self, voxel_features, coords, batch_size):
    def forward(self, voxel_features, coords):
        """
        voxel_features,shape[6815,64]
        coords,[6815,4]
        """
        #import pdb 
        #pdb.set_trace()
        # batch_canvas will be the final output.
        batch_canvas = []

        if self.batch_size == 1:
            #shape[64,214272]
            canvas = torch.zeros(self.nchannels, self.nx * self.ny, 
                dtype=voxel_features.dtype,device=voxel_features.device)
            #计算索引,y*N_X + x
            indices = coords[:, 2] * self.nx + coords[:, 3] #shape[6815]
            indices = indices.type(torch.float64)
            transposed_voxel_features = voxel_features.t() #shape[64,6815]

            # Now scatter the blob back to the canvas.
            indices_2d = indices.view(1, -1) #shape[1,6815]
            ones = torch.ones([self.nchannels, 1], dtype=torch.float64, device=voxel_features.device)
         
            indices_num_channel = torch.mm(ones, indices_2d)
            indices_num_channel = indices_num_channel.type(torch.int64)
            #shape[64,214272]
            scattered_canvas = canvas.scatter_(1, indices_num_channel, transposed_voxel_features)

            # Append to a list for later stacking.
            batch_canvas.append(scattered_canvas)

            # Stack to 3-dim tensor (batch-size, nchannels, nrows*ncols)
            """
            stack注意与cat的区别,stack是沿着一个新的维度进行拼接,
            输入张量必需为相同的维度
            (Pdb) batch_canvas.shape
            torch.Size([1, 64, 214272])
            """
            batch_canvas = torch.stack(batch_canvas, 0)

            # Undo the column stacking to final 4-dim tensor
            #torch.Size([1, 64, 496, 432])
            batch_canvas = batch_canvas.view(1, self.nchannels, self.ny, self.nx)
            return batch_canvas
        else:
            raise Exception("NotImplemented")

最重要的一句就是:scattered_canvas = canvas.scatter_(1, indices_num_channel, transposed_voxel_features)。

Tensor.scatter_(dimindexsrcreduce=None) → Tensor

Writes all values from the tensor src into self at the indices specified in the index tensor. For each value in src, its output index is specified by its index in src for dimension != dim and by the corresponding value in index for dimension = dim.

pytorch的scatter api简单说就是通过一个张量来修改另外一个张量,具体修改那些元素呢?通过index,dim配合来给出。官方给出了3-D tensor的计算方式:

self[index[i][j][k]][j][k] = src[i][j][k] # if dim == 0 
self[i][index[i][j][k]][k] = src[i][j][k] # if dim == 1 
self[i][j][index[i][j][k]] = src[i][j][k] # if dim == 2

我们这里只考虑2-D的情形:

self[index[i][j]][j] = src[i][j] #if dim == 0

在这里插入图片描述

self[i][index[i][j]] = src[i][j] #if dim == 1

在这里插入图片描述

scatter操作后对得到的scatter_canvas进一步reshape到(1,self.channels,self.ny,self.nx),这里self.channels,self.ny,self.nx对于每一帧点云都是固定值。这样,我们就得到了点云的伪图像。后面的操作就跟普通图像的操作一样了。

【参考文献】

https://blog.csdn.net/weixin_43496455/article/details/103870889

https://www.cnblogs.com/dogecheng/p/11938009.html

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
PointPillars是一种基于点云的目标检测算法,其主要应用于自动驾驶领域。该算法的核心思想是将点云数据转换为三维网格数据,并使用卷积神经网络(CNN)来检测目标。相比于传统的基于图像的目标检测算法,PointPillars在保留场景空间信息的同时,大幅提高了目标检测的准确度和效率。 具体来说,PointPillars的算法流程如下:首先,将点云数据转换为三维网格数据,然后使用CNN对每个网格进行分类并预测目标的边界框。最后,通过非极大值抑制(NMS)算法来筛选出最终的目标检测结果。在该算法中,点云的密度以及对边界框的准确度影响较为显著,因此PointPillars通过密集采样和点云旋转等方法优化了点云数据的输入。 相比于基于图像的目标检测算法,PointPillars的优势主要体现在以下方面:首先,该算法能够准确地捕捉目标的三维空间信息,可以有效地解决目标遮挡或者遮挡较多的情况;其次,该算法的检测效率较高,可以实现实时检测,并且其能够在运行过程中进行端到端的训练和优化;最后,该算法具有较强的鲁棒性和泛化能力,可以适应不同场景下的目标检测需求。 总之,PointPillars作为新兴的目标检测算法之一,具有较高的应用潜力和研究价值,其可以改善自动驾驶等领域的目标检测能力,并促进相关技术的进一步发展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值