import os import numpy as np import torch __all__ = ["load_augmented_point_cloud", "reduce_LiDAR_beams"] def load_augmented_point_cloud(path, virtual=False, reduce_beams=32): # NOTE: following Tianwei's implementation, it is hard coded for nuScenes points = np.fromfile(path, dtype=np.float32).reshape(-1, 5) # NOTE: path definition different from Tianwei's implementation. tokens = path.split("/") vp_dir = "_VIRTUAL" if reduce_beams == 32 else f"_VIRTUAL_{reduce_beams}BEAMS" seg_path = os.path.join( *tokens[:-3], "virtual_points", tokens[-3], tokens[-2] + vp_dir, tokens[-1] + ".pkl.npy", ) assert os.path.exists(seg_path) data_dict = np.load(seg_path, allow_pickle=True).item() virtual_points1 = data_dict["real_points"] # NOTE: add zero reflectance to virtual points instead of removing them from real points virtual_points2 = np.concatenate( [ data_dict["virtual_points"][:, :3], np.zeros([data_dict["virtual_points"].shape[0], 1]), data_dict["virtual_points"][:, 3:], ], axis=-1, ) points = np.concatenate( [ points, np.ones([points.shape[0], virtual_points1.shape[1] - points.shape[1] + 1]), ], axis=1, ) virtual_points1 = np.concatenate( [virtual_points1, np.zeros([virtual_points1.shape[0], 1])], axis=1 ) # note: this part is different from Tianwei's implementation, we don't have duplicate foreground real points. if len(data_dict["real_points_indice"]) > 0: points[data_dict["real_points_indice"]] = virtual_points1 if virtual: virtual_points2 = np.concatenate( [virtual_points2, -1 * np.ones([virtual_points2.shape[0], 1])], axis=1 ) points = np.concatenate([points, virtual_points2], axis=0).astype(np.float32) return points def reduce_LiDAR_beams(pts, reduce_beams_to=32): # print(pts.size()) if isinstance(pts, np.ndarray): pts = torch.from_numpy(pts) radius = torch.sqrt(pts[:, 0].pow(2) + pts[:, 1].pow(2) + pts[:, 2].pow(2)) sine_theta = pts[:, 2] / radius # [-pi/2, pi/2] theta = torch.asin(sine_theta) phi = torch.atan2(pts[:, 1], pts[:, 0]) top_ang = 0.1862 down_ang = -0.5353 beam_range = torch.zeros(32) beam_range[0] = top_ang beam_range[31] = down_ang for i in range(1, 31): beam_range[i] = beam_range[i - 1] - 0.023275 # beam_range = [1, 0.18, 0.15, 0.13, 0.11, 0.085, 0.065, 0.03, 0.01, -0.01, -0.03, -0.055, -0.08, -0.105, -0.13, -0.155, -0.18, -0.205, -0.228, -0.251, -0.275, # -0.295, -0.32, -0.34, -0.36, -0.38, -0.40, -0.425, -0.45, -0.47, -0.49, -0.52, -0.54] num_pts, _ = pts.size() mask = torch.zeros(num_pts) if reduce_beams_to == 16: for id in [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31]: beam_mask = (theta < (beam_range[id - 1] - 0.012)) * ( theta > (beam_range[id] - 0.012) ) mask = mask + beam_mask mask = mask.bool() elif reduce_beams_to == 4: for id in [7, 9, 11, 13]: beam_mask = (theta < (beam_range[id - 1] - 0.012)) * ( theta > (beam_range[id] - 0.012) ) mask = mask + beam_mask mask = mask.bool() # [?] pick the 14th beam elif reduce_beams_to == 1: chosen_beam_id = 9 mask = (theta < (beam_range[chosen_beam_id - 1] - 0.012)) * ( theta > (beam_range[chosen_beam_id] - 0.012) ) else: raise NotImplementedError # points = copy.copy(pts) points = pts[mask] # print(points.size()) return points.numpy()