def get_roi_from_rpn(box_score,box,nms_cfg):
    """
    box_score:(num of anchor,)
    box:(num of anchor, 7)
    nms_cfg:nms的配置文件
    """

    selected = []
    if box.shape[0]>0:
        rank_score,indices = torch.topk(box_score,k=min(nms_cfg.NMS_PRE_MAXSIZE,box.shape[0]))
        for_nms_box = box[indices]
        nms_indices, _ = iou3d_nms_utils.nms_gpu(for_nms_box,rank_score,nms_cfg.NMS_THRESH,**nms_cfg)
        selected = indices[nms_indices[:nms_cfg.NMS_POST_MAXSIZE]]

    return selected.view(-1),box_score[selected]
Beispiel #2
0
    def class_final_nms(self,box_scores,box_preds,nms_config,score_thresh=None):
        """
        box_scores:(N,)
        box_preds:(N,7)
        score thresh:(1,)
        """
        box_scores_src = box_scores
        score_mask = (box_scores>score_thresh).squeeze(dim=-1)
        box_scores = box_scores[score_mask]
        box_preds = box_preds[score_mask]
        selected =[]
        if box_scores.shape[0]>0:
            score_for_nms,indices = torch.topk(
                box_scores.squeeze(dim=-1),k=min(nms_config.NMS_PRE_MAXSIZE,box_scores.shape[0]))
            box_for_nms = box_preds[indices]
            keep_id,_ = iou3d_nms_utils.nms_gpu(box_for_nms,score_for_nms,nms_config.NMS_THRESH)
            selected = indices[keep_id[:nms_config.NMS_POST_MAXSIZE]]

            origin_idx = torch.nonzero(score_mask).view(-1)
            selected = origin_idx[selected].view(-1)
        return selected,box_scores_src[selected].view(-1)
Beispiel #3
0
    def forward(self, inputs):
        x = self.conv_input(inputs["input_sp_tensor"])
        x_conv1 = self.conv1(x)
        x_conv2 = self.conv2(x_conv1)
        x_conv3 = self.conv3(x_conv2)
        x_conv4 = self.conv4(x_conv3)
        out = self.conv_out(x_conv4)
        spatial_features = out.dense()
        N, C, D, H, W = spatial_features.shape
        spatial_features = spatial_features.view(N, C * D, H, W)  #压缩到二维特征

        #######################--------VOXEL_SA----------############################################################
        #对原始点云采集keypoints作为new_xyz
        keypoints = self.get_sampled_points(inputs["points"])
        point_features_list = []
        point_bev_features = self.interpolate_from_bev_features(
            keypoints, spatial_features)
        point_features_list.append(point_bev_features)
        batch_size, num_keypoints, _ = keypoints.shape
        new_xyz = keypoints.view(-1, 3)
        new_xyz_batch_cnt = new_xyz.new_zeros(batch_size).int().fill_(
            num_keypoints)
        #对原始点云进行聚合
        xyz = inputs["points"][:, :3]
        xyz_batch_cnt = xyz.new_zeros(batch_size).int()
        xyz_batch_cnt[0] = xyz.shape[0]
        point_features = inputs["points"][:, 3:]
        pooled_points, pooled_features = self.raw_sa_layer(
            xyz=xyz.contiguous(),
            xyz_batch_cnt=xyz_batch_cnt,
            new_xyz=new_xyz,
            new_xyz_batch_cnt=new_xyz_batch_cnt,
            features=point_features.contiguous(),
        )
        point_features_list.append(
            pooled_features.view(batch_size, num_keypoints, -1))
        #对conv1进行聚合
        cur_coords = x_conv1.indices
        xyz = self.get_voxel_centers(
            cur_coords[:, 1:4],
            downsample_times=self.downsample_times_map[0],
            voxel_size=self.voxel_size,
            point_cloud_range=self.point_cloud_range)
        xyz_batch_cnt = xyz.new_zeros(batch_size).int()
        xyz_batch_cnt[0] = (cur_coords[:, 0] == 0).sum()
        pooled_points, pooled_features = self.conv1_sa_layer(
            xyz=xyz.contiguous(),
            xyz_batch_cnt=xyz_batch_cnt,
            new_xyz=new_xyz,
            new_xyz_batch_cnt=new_xyz_batch_cnt,
            features=x_conv1.features.contiguous(),
        )
        point_features_list.append(
            pooled_features.view(batch_size, num_keypoints, -1))
        #对conv2聚合
        cur_coords = x_conv2.indices
        xyz = self.get_voxel_centers(
            cur_coords[:, 1:4],
            downsample_times=self.downsample_times_map[1],
            voxel_size=self.voxel_size,
            point_cloud_range=self.point_cloud_range)
        xyz_batch_cnt = xyz.new_zeros(batch_size).int()
        xyz_batch_cnt[0] = (cur_coords[:, 0] == 0).sum()
        pooled_points, pooled_features = self.conv2_sa_layer(
            xyz=xyz.contiguous(),
            xyz_batch_cnt=xyz_batch_cnt,
            new_xyz=new_xyz,
            new_xyz_batch_cnt=new_xyz_batch_cnt,
            features=x_conv2.features.contiguous(),
        )
        point_features_list.append(
            pooled_features.view(batch_size, num_keypoints, -1))
        # 对conv3聚合
        cur_coords = x_conv3.indices
        xyz = self.get_voxel_centers(
            cur_coords[:, 1:4],
            downsample_times=self.downsample_times_map[2],
            voxel_size=self.voxel_size,
            point_cloud_range=self.point_cloud_range)
        xyz_batch_cnt = xyz.new_zeros(batch_size).int()
        xyz_batch_cnt[0] = (cur_coords[:, 0] == 0).sum()
        pooled_points, pooled_features = self.conv3_sa_layer(
            xyz=xyz.contiguous(),
            xyz_batch_cnt=xyz_batch_cnt,
            new_xyz=new_xyz,
            new_xyz_batch_cnt=new_xyz_batch_cnt,
            features=x_conv3.features.contiguous(),
        )
        point_features_list.append(
            pooled_features.view(batch_size, num_keypoints, -1))
        # 对conv4聚合
        cur_coords = x_conv4.indices
        xyz = self.get_voxel_centers(
            cur_coords[:, 1:4],
            downsample_times=self.downsample_times_map[3],
            voxel_size=self.voxel_size,
            point_cloud_range=self.point_cloud_range)
        xyz_batch_cnt = xyz.new_zeros(batch_size).int()
        xyz_batch_cnt[0] = (cur_coords[:, 0] == 0).sum()
        pooled_points, pooled_features = self.conv4_sa_layer(
            xyz=xyz.contiguous(),
            xyz_batch_cnt=xyz_batch_cnt,
            new_xyz=new_xyz,
            new_xyz_batch_cnt=new_xyz_batch_cnt,
            features=x_conv4.features.contiguous(),
        )
        point_features_list.append(
            pooled_features.view(batch_size, num_keypoints, -1))

        # 关键点的坐标:point_coords(bxyz)
        batch_idx = torch.arange(batch_size, device=keypoints.device).view(
            -1, 1).repeat(1, keypoints.shape[1]).view(-1)
        point_coords = torch.cat(
            (batch_idx.view(-1, 1).float(), keypoints.view(-1, 3)), dim=1)
        #关键点的特征 :point_features
        point_features = torch.cat(point_features_list, dim=2)
        point_features_before_fusion = point_features.view(
            -1, point_features.shape[-1])  #原始拼接特征
        point_features = self.vsa_point_feature_fusion(
            point_features.view(-1, point_features.shape[-1]))  #经过线性层后的特征

        ############################################--RPN-Head----#################################################
        ups = []
        x = self.block1(spatial_features)
        ups.append(self.deblock1(x))
        x = self.block2(x)
        ups.append(self.deblock2(x))
        x = torch.cat(ups, dim=1)
        rpn_box_preds = self.rpn_head_conv_box(x)
        rpn_cls_preds = self.rpn_head_conv_cls(x)
        rpn_box_preds = rpn_box_preds.permute(0, 2, 3, 1).contiguous()
        rpn_cls_preds = rpn_cls_preds.permute(0, 2, 3, 1).contiguous()
        rpn_dir_preds = self.rpn_head_conv_dir_cls(x)
        #使用box回归值和anhcor进行decode,
        rpn_box_preds = rpn_box_preds.reshape(batch_size, -1, 7)
        rpn_cls_preds = rpn_cls_preds.reshape(batch_size, -1, 3)
        rpn_dir_preds_score = rpn_dir_preds.permute(0, 2, 3, 1).reshape(
            batch_size, -1, 2)
        dir_cls_preds_label = torch.argmax(rpn_dir_preds_score, dim=-1)
        rpn_box_preds = self.decode_torch(rpn_box_preds, self.anchors)
        rot_angle_preds = self.limit_period(rpn_box_preds[..., 6] - 0.78539,
                                            offset=0.0,
                                            period=np.pi)
        rot_angle_preds_final = rot_angle_preds + 0.78539 + np.pi * dir_cls_preds_label.to(
            rpn_box_preds.dtype)
        rpn_box_preds[..., 6] = rot_angle_preds_final % (np.pi * 2)

        ##################################Point Head######################################################
        point_cls_preds = self.point_head_cls_layer(
            point_features_before_fusion)
        point_cls_score, _ = torch.sigmoid(point_cls_preds).max(dim=-1)
        ###################################-----RCNN--------##############################################
        #感兴趣区域的筛选
        rois = rpn_box_preds.new_zeros(batch_size, 100, 7)
        roi_score = rpn_box_preds.new_zeros(batch_size, 100)
        roi_labels = rpn_box_preds.new_zeros(batch_size, 100, dtype=torch.long)
        cur_box = rpn_box_preds[0]
        cur_cls = rpn_cls_preds[0]
        cur_roi_score, cur_roi_labels = torch.max(cur_cls, dim=1)
        rank_score, indices = torch.topk(cur_roi_score,
                                         k=min(1024, 7))  #根据rpn类别得分得到前1024个box
        for_nms_box = cur_box[indices]
        nms_indices, _ = iou3d_nms_utils.nms_gpu(for_nms_box, rank_score,
                                                 0.7)  #对1024个box进行nms
        selected = indices[
            nms_indices[:100]]  #选则rpn类别得分前100个box进行second-stage细化
        rois[0, :len(selected), :] = cur_box[selected]
        roi_score[0, :len(selected)] = cur_roi_score[selected]
        roi_labels[0, :len(
            selected)] = cur_roi_labels[selected] + 1  #类别从1-3并非0-2,将0认为是背景应该是
        #将感兴趣区域网格化,每个3d-box转化为6*6*6的网格
        rois = rois.view(-1, 7)
        local_grid = rois.new_ones(6, 6, 6)
        local_grid_id = torch.nonzero(local_grid).float()  #(6*6*6,3)
        local_grid_id = local_grid_id.repeat(100, 1, 1)  #(100,216,3)
        rois_size = rois[..., 3:6].unsqueeze(dim=1).clone()
        gloal_grid_points = (local_grid_id + 0.5) * (
            rois_size / 6) - rois_size / 2  #将原点转化到box中心
        rois_ry = rois[..., 6].clone()
        gloal_grid_points = self.rotate_points_along_z(
            gloal_grid_points.clone(),
            rois_ry.view(-1))  #将网格化的rois由规定坐标系旋转到真实坐标系
        roi_centers = rois[..., 0:3].clone()
        gloal_grid_points += roi_centers.unsqueeze(dim=1)  #平移网格化的roi
        gloal_grid_points = gloal_grid_points.view(batch_size, -1,
                                                   gloal_grid_points.shape[-1])
        #网格化的roi作为关键点,聚合keypoints的特征
        xyz = point_coords[:, 1:4]
        xyz_batch_count = xyz.new_zeros(batch_size, ).int()
        xyz_batch_count[0] = keypoints.shape[1]  #keypoints的个数
        new_xyz = gloal_grid_points.view(-1, 3)
        new_xyz_bn_count = new_xyz.new_zeros(batch_size).int()
        new_xyz_bn_count[0] = gloal_grid_points.shape[1]
        pooled_xyz, pooled_features = self.roi_pool_layer(
            xyz.contiguous(),
            xyz_batch_count,
            new_xyz,
            new_xyz_bn_count,
            features=point_features)
        pooled_features = pooled_features.view(-1, 6**3,
                                               pooled_features.shape[-1])
        pooled_features = pooled_features.permute(
            0, 2, 1).contiguous()  # (100,128,6*6*6)
        share_features = self.rcnn_share_layer(pooled_features.view(
            100, -1, 1))
        rcnn_cls_preds = self.rcnn_cls_layer(share_features).squeeze(
            dim=-1).contiguous()
        rcnn_reg_preds = self.rcnn_reg_layer(share_features).squeeze(
            dim=-1).contiguous()
        rcnn_cls_preds = rcnn_cls_preds.unsqueeze(dim=0)
        rcnn_reg_preds = rcnn_reg_preds.unsqueeze(dim=0)
        #将second-stage阶段的回归结果根据roi进行解码,得到最终的box,解码顺序就是先不带xyz解码,然后在roi的xyz加上
        rois = rois.unsqueeze(dim=0)
        rois_y = rois[..., 6].view(-1)
        rois_xyz = rois[..., 0:3]
        rois_temp = rois.clone().detach()
        rois_temp[..., 0:3] = 0
        box_ct = self.decode_torch(rcnn_reg_preds, rois_temp).view(-1, 7)
        box_preds = self.rotate_points_along_z(box_ct.unsqueeze(dim=1),
                                               rois_y).squeeze(dim=1).view(
                                                   batch_size, -1, 7)
        box_preds[..., 0:3] += rois_xyz
        #最终的输出为:box_preds,rcnn_cls_preds
        #############################################----POST-Processing----######################################
        cur_box_preds = box_preds[0]
        cur_cls_preds = rcnn_cls_preds[0]
        cur_normal_cls_preds = torch.sigmoid(cur_cls_preds)
        label_preds = roi_labels[0]
        #进行后处理
        score_mask = (cur_normal_cls_preds > 0.1).squeeze(dim=-1)
        pps_box_scores = cur_normal_cls_preds[score_mask]  #post processing box
        pps_box_preds = cur_box_preds[score_mask]
        selected = []
        if pps_box_scores.shape[0] > 0:
            score_for_nms, indices = torch.topk(pps_box_scores.squeeze(dim=-1),
                                                k=min(4096,
                                                      pps_box_scores.shape[0]))
            box_for_nms = pps_box_preds[indices]
            keep_id, _ = iou3d_nms_utils.nms_gpu(box_for_nms, score_for_nms,
                                                 0.1)
            selected = indices[keep_id[:500]]
            origin_idx = torch.nonzero(score_mask).view(-1)
            selected = origin_idx[selected].view(-1)
        final_box = cur_box_preds[selected]
        final_cls = label_preds[selected]
        final_score = cur_normal_cls_preds[selected]
        return (final_box, final_cls, final_score)