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
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
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
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