def random_crop_frustum(bboxes,
                        rect,
                        Trv2c,
                        P2,
                        max_crop_height=1.0,
                        max_crop_width=0.9):
    num_gt = bboxes.shape[0]
    crop_minxy = np.random.uniform([1 - max_crop_width, 1 - max_crop_height],
                                   [0.3, 0.3],
                                   size=[num_gt, 2])
    crop_maxxy = np.ones([num_gt, 2], dtype=bboxes.dtype)
    crop_bboxes = np.concatenate([crop_minxy, crop_maxxy], axis=1)
    left = np.random.choice([False, True], replace=False, p=[0.5, 0.5])
    if left:
        crop_bboxes[:, [0, 2]] -= crop_bboxes[:, 0:1]
    # crop_relative_bboxes to real bboxes
    crop_bboxes *= np.tile(bboxes[:, 2:] - bboxes[:, :2], [1, 2])
    crop_bboxes += np.tile(bboxes[:, :2], [1, 2])
    C, R, T = box_np_ops.projection_matrix_to_CRT_kitti(P2)
    frustums = box_np_ops.get_frustum_v2(crop_bboxes, C)
    frustums -= T
    # frustums = np.linalg.inv(R) @ frustums.T
    frustums = np.einsum("ij, akj->aki", np.linalg.inv(R), frustums)
    frustums = box_np_ops.camera_to_lidar(frustums, rect, Trv2c)

    return frustums
Ejemplo n.º 2
0
    def sample_all(
        self,
        root_path,
        gt_boxes,
        gt_names,
        num_point_features,
        random_crop=False,
        gt_group_ids=None,
        calib=None,
        road_planes=None,
    ):
        sampled_num_dict = {}
        sample_num_per_class = []
        for class_name, max_sample_num in zip(self._sample_classes,
                                              self._sample_max_nums):
            sampled_num = int(max_sample_num -
                              np.sum([n == class_name for n in gt_names]))

            sampled_num = np.round(self._rate * sampled_num).astype(np.int64)
            sampled_num_dict[class_name] = sampled_num
            sample_num_per_class.append(sampled_num)

        sampled_groups = self._sample_classes
        if self._use_group_sampling:
            assert gt_group_ids is not None
            sampled_groups = []
            sample_num_per_class = []
            for group_name, class_names in self._group_name_to_names:
                sampled_nums_group = [sampled_num_dict[n] for n in class_names]
                sampled_num = np.max(sampled_nums_group)
                sample_num_per_class.append(sampled_num)
                sampled_groups.append(group_name)
            total_group_ids = gt_group_ids
        sampled = []
        sampled_gt_boxes = []
        avoid_coll_boxes = gt_boxes

        for class_name, sampled_num in zip(sampled_groups,
                                           sample_num_per_class):
            if sampled_num > 0:
                if self._use_group_sampling:
                    sampled_cls = self.sample_group(class_name, sampled_num,
                                                    avoid_coll_boxes,
                                                    total_group_ids)
                else:
                    sampled_cls = self.sample_class_v2(class_name, sampled_num,
                                                       avoid_coll_boxes)

                sampled += sampled_cls
                if len(sampled_cls) > 0:
                    if len(sampled_cls) == 1:
                        sampled_gt_box = sampled_cls[0]["box3d_lidar"][
                            np.newaxis, ...]
                    else:
                        sampled_gt_box = np.stack(
                            [s["box3d_lidar"] for s in sampled_cls], axis=0)

                    sampled_gt_boxes += [sampled_gt_box]
                    avoid_coll_boxes = np.concatenate(
                        [avoid_coll_boxes, sampled_gt_box], axis=0)
                    if self._use_group_sampling:
                        if len(sampled_cls) == 1:
                            sampled_group_ids = np.array(
                                sampled_cls[0]["group_id"])[np.newaxis, ...]
                        else:
                            sampled_group_ids = np.stack(
                                [s["group_id"] for s in sampled_cls], axis=0)
                        total_group_ids = np.concatenate(
                            [total_group_ids, sampled_group_ids], axis=0)

        if len(sampled) > 0:
            sampled_gt_boxes = np.concatenate(sampled_gt_boxes, axis=0)

            if road_planes is not None:
                # Only support KITTI
                # image plane
                assert False, "Not correct yet!"
                a, b, c, d = road_planes

                center = sampled_gt_boxes[:, :3]
                center[:, 2] -= sampled_gt_boxes[:, 5] / 2
                center_cam = box_np_ops.lidar_to_camera(
                    center, calib["rect"], calib["Trv2c"])

                cur_height_cam = (-d - a * center_cam[:, 0] -
                                  c * center_cam[:, 2]) / b
                center_cam[:, 1] = cur_height_cam
                lidar_tmp_point = box_np_ops.camera_to_lidar(
                    center_cam, calib["rect"], calib["Trv2c"])
                cur_lidar_height = lidar_tmp_point[:, 2]

                # botom to middle center
                # kitti [0.5, 0.5, 0] center to [0.5, 0.5, 0.5]
                sampled_gt_boxes[:,
                                 2] = cur_lidar_height + sampled_gt_boxes[:,
                                                                          5] / 2

                # mv_height = sampled_gt_boxes[:, 2] - cur_lidar_height
                # sampled_gt_boxes[:, 2] -= mv_height

            num_sampled = len(sampled)
            s_points_list = []
            for info in sampled:
                try:
                    # TODO fix point read error
                    s_points = np.fromfile(
                        str(pathlib.Path(root_path) / info["path"]),
                        dtype=np.float32).reshape(-1, num_point_features)
                    # if not add_rgb_to_points:
                    #     s_points = s_points[:, :4]
                    if "rot_transform" in info:
                        rot = info["rot_transform"]
                        s_points[:, :
                                 3] = box_np_ops.rotation_points_single_angle(
                                     s_points[:, :4], rot, axis=2)
                    s_points[:, :3] += info["box3d_lidar"][:3]
                    s_points_list.append(s_points)
                    # print(pathlib.Path(info["path"]).stem)
                except Exception:
                    print(str(pathlib.Path(root_path) / info["path"]))
                    continue
            # gt_bboxes = np.stack([s["bbox"] for s in sampled], axis=0)
            # if np.random.choice([False, True], replace=False, p=[0.3, 0.7]):
            # do random crop.
            if random_crop:
                s_points_list_new = []
                assert calib is not None
                rect = calib["rect"]
                Trv2c = calib["Trv2c"]
                P2 = calib["P2"]
                gt_bboxes = box_np_ops.box3d_to_bbox(sampled_gt_boxes, rect,
                                                     Trv2c, P2)
                crop_frustums = prep.random_crop_frustum(
                    gt_bboxes, rect, Trv2c, P2)
                for i in range(crop_frustums.shape[0]):
                    s_points = s_points_list[i]
                    mask = prep.mask_points_in_corners(
                        s_points, crop_frustums[i:i + 1]).reshape(-1)
                    num_remove = np.sum(mask)
                    if num_remove > 0 and (s_points.shape[0] -
                                           num_remove) > 15:
                        s_points = s_points[np.logical_not(mask)]
                    s_points_list_new.append(s_points)
                s_points_list = s_points_list_new
            ret = {
                "gt_names": np.array([s["name"] for s in sampled]),
                "difficulty": np.array([s["difficulty"] for s in sampled]),
                "gt_boxes": sampled_gt_boxes,
                "points": np.concatenate(s_points_list, axis=0),
                "gt_masks": np.ones((num_sampled, ), dtype=np.bool_),
            }
            if self._use_group_sampling:
                ret["group_ids"] = np.array([s["group_id"] for s in sampled])
            else:
                ret["group_ids"] = np.arange(gt_boxes.shape[0],
                                             gt_boxes.shape[0] + len(sampled))
        else:
            ret = None
        return ret
Ejemplo n.º 3
0
    def __call__(self, res, info):

        res["mode"] = self.mode

        if res["type"] in ["KittiDataset", "WaymoDataset", "LyftDataset"]:
            points = res["lidar"]["points"]
        elif res["type"] in ["NuScenesDataset"]:
            points = res["lidar"]["combined"]

        if self.mode == "train":
            anno_dict = res["lidar"]["annotations"]

            gt_dict = {
                "gt_boxes": anno_dict["boxes"],
                "gt_names": np.array(anno_dict["names"]).reshape(-1),
            }

            if "difficulty" not in anno_dict:
                difficulty = np.zeros([anno_dict["boxes"].shape[0]],
                                      dtype=np.int32)
                gt_dict["difficulty"] = difficulty
            else:
                gt_dict["difficulty"] = anno_dict["difficulty"]

        if "calib" in res:
            calib = res["calib"]
        else:
            calib = None

        if self.add_rgb_to_points:
            assert calib is not None and "image" in res
            image_path = res["image"]["image_path"]
            image = (imgio.imread(str(pathlib.Path(root_path) /
                                      image_path)).astype(np.float32) / 255)
            points_rgb = box_np_ops.add_rgb_to_points(points, image,
                                                      calib["rect"],
                                                      calib["Trv2c"],
                                                      calib["P2"])
            points = np.concatenate([points, points_rgb], axis=1)
            num_point_features += 3

        if self.reference_detections is not None:
            assert calib is not None and "image" in res
            C, R, T = box_np_ops.projection_matrix_to_CRT_kitti(P2)
            frustums = box_np_ops.get_frustum_v2(reference_detections, C)
            frustums -= T
            frustums = np.einsum("ij, akj->aki", np.linalg.inv(R), frustums)
            frustums = box_np_ops.camera_to_lidar(frustums, rect, Trv2c)
            surfaces = box_np_ops.corner_to_surfaces_3d_jit(frustums)
            masks = points_in_convex_polygon_3d_jit(points, surfaces)
            points = points[masks.any(-1)]

        if self.remove_outside_points:
            assert calib is not None
            image_shape = res["metadata"]["image_shape"]
            points = box_np_ops.remove_outside_points(points, calib["rect"],
                                                      calib["Trv2c"],
                                                      calib["P2"], image_shape)
        if self.remove_environment is True and self.mode == "train":
            selected = keep_arrays_by_name(gt_names, target_assigner.classes)
            _dict_select(gt_dict, selected)
            masks = box_np_ops.points_in_rbbox(points, gt_dict["gt_boxes"])
            points = points[masks.any(-1)]

        if self.mode == "train":
            selected = drop_arrays_by_name(gt_dict["gt_names"],
                                           ["DontCare", "ignore"])

            _dict_select(gt_dict, selected)
            if self.remove_unknown:
                remove_mask = gt_dict["difficulty"] == -1
                """
                gt_boxes_remove = gt_boxes[remove_mask]
                gt_boxes_remove[:, 3:6] += 0.25
                points = prep.remove_points_in_boxes(points, gt_boxes_remove)
                """
                keep_mask = np.logical_not(remove_mask)
                _dict_select(gt_dict, keep_mask)
            gt_dict.pop("difficulty")

            if self.min_points_in_gt > 0:
                # points_count_rbbox takes 10ms with 10 sweeps nuscenes data
                point_counts = box_np_ops.points_count_rbbox(
                    points, gt_dict["gt_boxes"])
                mask = point_counts >= min_points_in_gt
                _dict_select(gt_dict, mask)

            gt_boxes_mask = np.array(
                [n in self.class_names for n in gt_dict["gt_names"]],
                dtype=np.bool_)

            if self.db_sampler:
                sampled_dict = self.db_sampler.sample_all(
                    res["metadata"]["image_prefix"],
                    gt_dict["gt_boxes"],
                    gt_dict["gt_names"],
                    res["metadata"]["num_point_features"],
                    self.random_crop,
                    gt_group_ids=None,
                    calib=calib,
                    road_planes=None  # res["lidar"]["ground_plane"]
                )

                if sampled_dict is not None:
                    sampled_gt_names = sampled_dict["gt_names"]
                    sampled_gt_boxes = sampled_dict["gt_boxes"]
                    sampled_points = sampled_dict["points"]
                    sampled_gt_masks = sampled_dict["gt_masks"]
                    gt_dict["gt_names"] = np.concatenate(
                        [gt_dict["gt_names"], sampled_gt_names], axis=0)
                    gt_dict["gt_boxes"] = np.concatenate(
                        [gt_dict["gt_boxes"], sampled_gt_boxes])
                    gt_boxes_mask = np.concatenate(
                        [gt_boxes_mask, sampled_gt_masks], axis=0)

                    if self.remove_points_after_sample:
                        masks = box_np_ops.points_in_rbbox(
                            points, sampled_gt_boxes)
                        points = points[np.logical_not(masks.any(-1))]

                    points = np.concatenate([sampled_points, points], axis=0)
            prep.noise_per_object_v3_(
                gt_dict["gt_boxes"],
                points,
                gt_boxes_mask,
                rotation_perturb=self.gt_rotation_noise,
                center_noise_std=self.gt_loc_noise_std,
                global_random_rot_range=self.global_random_rot_range,
                group_ids=None,
                num_try=100,
            )

            _dict_select(gt_dict, gt_boxes_mask)

            gt_classes = np.array(
                [self.class_names.index(n) + 1 for n in gt_dict["gt_names"]],
                dtype=np.int32,
            )
            gt_dict["gt_classes"] = gt_classes

            iskitti = res["type"] in ["KittiDataset"]

            if self.kitti_double:
                assert False, "No more KITTI"
                gt_dict["gt_boxes"], points = prep.random_flip_both(
                    gt_dict["gt_boxes"], points, flip_coor=70.4 / 2)
            elif self.flip_single or iskitti:
                assert False, "nuscenes double flip is better"
                gt_dict["gt_boxes"], points = prep.random_flip(
                    gt_dict["gt_boxes"], points)
            else:
                gt_dict["gt_boxes"], points = prep.random_flip_both(
                    gt_dict["gt_boxes"], points)

            gt_dict["gt_boxes"], points = prep.global_rotation(
                gt_dict["gt_boxes"],
                points,
                rotation=self.global_rotation_noise)
            gt_dict["gt_boxes"], points = prep.global_scaling_v2(
                gt_dict["gt_boxes"], points, *self.global_scaling_noise)

        if self.shuffle_points:
            # shuffle is a little slow.
            np.random.shuffle(points)

        if self.mode == "train" and self.random_select:
            if self.npoints < points.shape[0]:
                pts_depth = points[:, 2]
                pts_near_flag = pts_depth < 40.0
                far_idxs_choice = np.where(pts_near_flag == 0)[0]
                near_idxs = np.where(pts_near_flag == 1)[0]
                near_idxs_choice = np.random.choice(near_idxs,
                                                    self.npoints -
                                                    len(far_idxs_choice),
                                                    replace=False)

                choice = (np.concatenate(
                    (near_idxs_choice, far_idxs_choice), axis=0)
                          if len(far_idxs_choice) > 0 else near_idxs_choice)
                np.random.shuffle(choice)
            else:
                choice = np.arange(0, len(points), dtype=np.int32)
                if self.npoints > len(points):
                    extra_choice = np.random.choice(choice,
                                                    self.npoints - len(points),
                                                    replace=False)
                    choice = np.concatenate((choice, extra_choice), axis=0)
                np.random.shuffle(choice)

            points = points[choice]

        if self.symmetry_intensity:
            points[:, -1] -= 0.5  # translate intensity to [-0.5, 0.5]
            # points[:, -1] *= 2

        if self.normalize_intensity and res["type"] in ["NuScenesDataset"]:
            # print(points[:20, 3])
            assert 0, "Velocity Accuracy drops 3 percent with normalization.."
            points[:, 3] /= 255

        res["lidar"]["points"] = points

        if self.mode == "train":
            res["lidar"]["annotations"] = gt_dict

        return res, info
Ejemplo n.º 4
0
    def __call__(self, res, info, res_1, info_1, res_2, info_2):

        res["mode"] = self.mode
        res_1["mode"] = self.mode
        res_2["mode"] = self.mode

        if res["type"] in ["KittiDataset", "LyftDataset", "LvxDataset"]:
            points = res["lidar"]["points"]
            points_1 = res_1["lidar"]["points"]
            points_2 = res_2["lidar"]["points"]
        elif res["type"] == "NuScenesDataset":
            points = res["lidar"]["combined"]

        if self.mode == "train":
            anno_dict = res["lidar"]["annotations"]

            gt_dict = {
                "gt_boxes": anno_dict["boxes"],
            # 加入之前之后一帧的boxes
                "gt_boxes_1": anno_dict["boxes_1"],
                "gt_boxes_2": anno_dict["boxes_2"],
                "gt_boxes_3": anno_dict["boxes_3"],
                "gt_names": np.array(anno_dict["names"]).reshape(-1),
            }

            if "difficulty" not in anno_dict:
                difficulty = np.zeros([anno_dict["boxes"].shape[0]],
                                      dtype=np.int32)
                gt_dict["difficulty"] = difficulty
            else:
                gt_dict["difficulty"] = anno_dict["difficulty"]

        if "calib" in res:
            calib = res["calib"]
        else:
            calib = None

        if self.add_rgb_to_points:
            assert calib is not None and "image" in res
            image_path = res["image"]["image_path"]
            image = (imgio.imread(str(pathlib.Path(root_path) /
                                      image_path)).astype(np.float32) / 255)
            points_rgb = box_np_ops.add_rgb_to_points(points, image,
                                                      calib["rect"],
                                                      calib["Trv2c"],
                                                      calib["P2"])
            points = np.concatenate([points, points_rgb], axis=1)
            num_point_features += 3

        if self.reference_detections is not None:
            assert calib is not None and "image" in res
            C, R, T = box_np_ops.projection_matrix_to_CRT_kitti(P2)
            frustums = box_np_ops.get_frustum_v2(reference_detections, C)
            frustums -= T
            frustums = np.einsum("ij, akj->aki", np.linalg.inv(R), frustums)
            frustums = box_np_ops.camera_to_lidar(frustums, rect, Trv2c)
            surfaces = box_np_ops.corner_to_surfaces_3d_jit(frustums)
            masks = points_in_convex_polygon_3d_jit(points, surfaces)
            points = points[masks.any(-1)]

        if self.remove_outside_points:
            assert calib is not None
            image_shape = res["image"]["image_shape"]
            points = box_np_ops.remove_outside_points(points, calib["rect"],
                                                      calib["Trv2c"],
                                                      calib["P2"], image_shape)
        if self.remove_environment is True and self.mode == "train":
            selected = kitti.keep_arrays_by_name(gt_names,
                                                 target_assigner.classes)
            _dict_select(gt_dict, selected)
            masks = box_np_ops.points_in_rbbox(points, gt_dict["gt_boxes"])
            points = points[masks.any(-1)]

        if self.mode == "train":
            selected = kitti.drop_arrays_by_name(gt_dict["gt_names"],
                                                 ["DontCare", "ignore"])

            _dict_select(gt_dict, selected)
            if self.remove_unknown:
                remove_mask = gt_dict["difficulty"] == -1
                """
                gt_boxes_remove = gt_boxes[remove_mask]
                gt_boxes_remove[:, 3:6] += 0.25
                points = prep.remove_points_in_boxes(points, gt_boxes_remove)
                """
                keep_mask = np.logical_not(remove_mask)
                _dict_select(gt_dict, keep_mask)
            gt_dict.pop("difficulty")

            # 保证每个box内点的数量
            if self.min_points_in_gt > 0:
                # points_count_rbbox takes 10ms with 10 sweeps nuscenes data
                point_counts = box_np_ops.points_count_rbbox(
                    points, gt_dict["gt_boxes"])
                mask = point_counts >= min_points_in_gt
                _dict_select(gt_dict, mask)

            gt_boxes_mask = np.array(
                [n in self.class_names for n in gt_dict["gt_names"]],
                dtype=np.bool_)

            # 数据增广暂时去掉,有点改不过来
            if self.db_sampler:
                pass
                assert NotImplementedError
                sampled_dict = self.db_sampler.sample_all(
                    res["metadata"]["image_prefix"],
                    gt_dict["gt_boxes"],
                    gt_dict["gt_names"],
                    res["metadata"]["num_point_features"],
                    self.random_crop,
                    gt_group_ids=None,
                    calib=calib,
                )

                if sampled_dict is not None:
                    sampled_gt_names = sampled_dict["gt_names"]
                    sampled_gt_boxes = sampled_dict["gt_boxes"]
                    sampled_points = sampled_dict["points"]
                    sampled_gt_masks = sampled_dict["gt_masks"]
                    gt_dict["gt_names"] = np.concatenate(
                        [gt_dict["gt_names"], sampled_gt_names], axis=0)
                    gt_dict["gt_boxes"] = np.concatenate(
                        [gt_dict["gt_boxes"], sampled_gt_boxes])
                    gt_boxes_mask = np.concatenate(
                        [gt_boxes_mask, sampled_gt_masks], axis=0)

                    if self.remove_points_after_sample:
                        masks = box_np_ops.points_in_rbbox(
                            points, sampled_gt_boxes)
                        points = points[np.logical_not(masks.any(-1))]

                    points = np.concatenate([sampled_points, points], axis=0)
            # 暂时不加扰动了
            # TODO:需要改4帧,t-2,t-1,t的点云,以及t+1的box
            prep.noise_per_object_v3_(
                gt_dict["gt_boxes"],
                gt_dict["gt_boxes_1"],
                gt_dict["gt_boxes_2"],
                gt_dict["gt_boxes_3"],
                points,
                points_1,
                points_2,
                gt_boxes_mask,
                rotation_perturb=self.gt_rotation_noise,
                center_noise_std=self.gt_loc_noise_std,
                global_random_rot_range=self.global_random_rot_range,
                group_ids=None,
                num_try=100,
            )

            _dict_select(gt_dict, gt_boxes_mask)

            # 将类别转换为index
            gt_classes = np.array(
                [self.class_names.index(n) + 1 for n in gt_dict["gt_names"]],
                dtype=np.int32,
            )
            gt_dict["gt_classes"] = gt_classes

            # 添加了三帧的全局变换
            gt_dict["gt_boxes"], gt_dict["gt_boxes_1"], gt_dict[
                "gt_boxes_2"], points, points_1, points_2 = prep.random_flip(
                    gt_dict["gt_boxes"], gt_dict["gt_boxes_1"],
                    gt_dict["gt_boxes_2"], points, points_1, points_2)
            gt_dict["gt_boxes"], gt_dict["gt_boxes_1"], gt_dict[
                "gt_boxes_2"], points, points_1, points_2 = prep.global_rotation(
                    gt_dict["gt_boxes"], gt_dict["gt_boxes_1"],
                    gt_dict["gt_boxes_2"],
                    points,
                    points_1,
                    points_2,
                    rotation=self.global_rotation_noise)
            gt_dict["gt_boxes"], gt_dict["gt_boxes_1"], gt_dict[
                "gt_boxes_2"], points, points_1, points_2 = prep.global_scaling_v2(
                    gt_dict["gt_boxes"], gt_dict["gt_boxes_1"],
                    gt_dict["gt_boxes_2"], points, points_1, points_2, *self.global_scaling_noise)

        if self.shuffle_points:
            # shuffle is a little slow.
            np.random.shuffle(points)
            np.random.shuffle(points_1)
            np.random.shuffle(points_2)

        if self.mode == "train" and self.random_select:
            # 进行点的随机采样,暂时不需要
            if self.npoints < points.shape[0]:
                pts_depth = points[:, 2]
                pts_near_flag = pts_depth < 40.0
                far_idxs_choice = np.where(pts_near_flag == 0)[0]
                near_idxs = np.where(pts_near_flag == 1)[0]
                near_idxs_choice = np.random.choice(near_idxs,
                                                    self.npoints -
                                                    len(far_idxs_choice),
                                                    replace=False)

                choice = (np.concatenate(
                    (near_idxs_choice, far_idxs_choice), axis=0)
                          if len(far_idxs_choice) > 0 else near_idxs_choice)
                np.random.shuffle(choice)
            else:
                choice = np.arange(0, len(points), dtype=np.int32)
                if self.npoints > len(points):
                    extra_choice = np.random.choice(choice,
                                                    self.npoints - len(points),
                                                    replace=False)
                    choice = np.concatenate((choice, extra_choice), axis=0)
                np.random.shuffle(choice)

            points = points[choice]

        if self.symmetry_intensity:
            points[:, -1] -= 0.5    # translate intensity to [-0.5, 0.5]
            # points[:, -1] *= 2

        res["lidar"]["points"] = points
        res_1["lidar"]["points"] = points_1
        res_2["lidar"]["points"] = points_2

        if self.mode == "train":
            import copy

            res["lidar"]["annotations"] = gt_dict
            res_1["lidar"]["annotations"] = copy.deepcopy(gt_dict)
            res_2["lidar"]["annotations"] = copy.deepcopy(gt_dict)

        return res, info, res_1,info_1,res_2,info_2