def box_nuscenes_to_kitti( box: Box, velo_to_cam_rot: Quaternion, velo_to_cam_trans: np.ndarray, r0_rect: Quaternion, kitti_to_nu_lidar_inv: Quaternion = Quaternion(axis=(0, 0, 1), angle=np.pi / 2).inverse, ) -> Box: """Transform from nuScenes lidar frame to KITTI reference frame. Args: box: Instance in nuScenes lidar frame. velo_to_cam_rot: Quaternion to rotate from lidar to camera frame. velo_to_cam_trans: <np.float: 3>. Translate from lidar to camera frame. r0_rect: Quaternion to rectify camera frame. kitti_to_nu_lidar_inv: Quaternion to rotate nuScenes to KITTI LIDAR. Returns: Box instance in KITTI reference frame. """ # Copy box to avoid side-effects. box = box.copy() # Rotate to KITTI lidar. box.rotate(kitti_to_nu_lidar_inv) # Transform to KITTI camera. box.rotate(velo_to_cam_rot) box.translate(velo_to_cam_trans) # Rotate to KITTI rectified camera. box.rotate(r0_rect) # KITTI defines the box center as the bottom center of the object. # We use the true center, so we need to adjust half height in y direction. box.translate(np.array([0, box.wlh[2] / 2, 0])) return box
def get_boxes(self, token: str, filter_classes: List[str] = None, max_dist: float = None) -> List[Box]: """Load up all the boxes associated with a sample. Boxes are in nuScenes lidar frame. Args: token: KittiDB unique id. filter_classes: List of Kitti classes to use or None to use all. max_dist: List of Kitti classes to use or None to use all. Returns: Boxes in nuScenes lidar reference frame. """ # Get transforms for this sample transforms = self.get_transforms(token, root=self.root) boxes = [] if token.startswith("test_"): # No boxes to return for the test set. return boxes with open(KittiDB.get_filepath(token, "label_2", root=self.root), "r") as f: for line in f: # Parse this line into box information. parsed_line = self.parse_label_line(line) if parsed_line["name"] in {"DontCare", "Misc"}: continue center = parsed_line["xyz_camera"] wlh = parsed_line["wlh"] yaw_camera = parsed_line["yaw_camera"] name = parsed_line["name"] score = parsed_line["score"] # Optional: Filter classes. if filter_classes is not None and name not in filter_classes: continue # The Box class coord system is oriented the same way as as KITTI LIDAR: x forward, y left, z up. # For orientation confer: http://www.cvlibs.net/datasets/kitti/setup.php. # 1: Create box in Box coordinate system with center at origin. # The second quaternion in yaw_box transforms the coordinate frame from the object frame # to KITTI camera frame. The equivalent cannot be naively done afterwards, as it's a rotation # around the local object coordinate frame, rather than the camera frame. quat_box = Quaternion(axis=(0, 1, 0), angle=yaw_camera) * Quaternion( axis=(1, 0, 0), angle=np.pi / 2) box = Box([0.0, 0.0, 0.0], wlh, quat_box, name=name) # 2: Translate: KITTI defines the box center as the bottom center of the vehicle. We use true center, # so we need to add half height in negative y direction, (since y points downwards), to adjust. The # center is already given in camera coord system. box.translate(center + np.array([0, -wlh[2] / 2, 0])) # 3: Transform to KITTI LIDAR coord system. First transform from rectified camera to camera, then # camera to KITTI lidar. box.rotate(Quaternion(matrix=transforms["r0_rect"]).inverse) box.translate(-transforms["velo_to_cam"]["T"]) box.rotate( Quaternion(matrix=transforms["velo_to_cam"]["R"]).inverse) # 4: Transform to nuScenes LIDAR coord system. box.rotate(self.kitti_to_nu_lidar) # Set score or NaN. box.score = score # Set dummy velocity. box.velocity = np.array((0.0, 0.0, 0.0)) # Optional: Filter by max_dist if max_dist is not None: dist = np.sqrt(np.sum(box.center[:2]**2)) if dist > max_dist: continue boxes.append(box) return boxes