import argparse import glob import os import pickle as pkl from typing import Dict, List import diffstack_utils.box.sensor as box_sensor import diffstack_utils.box.transform as box_transform import diffstack_utils.box.vis as box_vis import diffstack_utils.carla.category as carla_class import diffstack_utils.carla.control as carla_control import diffstack_utils.object.rotation as object_rotation import diffstack_utils.sensor.calibration as calib_utils import numpy as np import pyquaternion import scipy import xinshuo_io as io_utils import xinshuo_miscellaneous as miscell_utils from diffstack_utils.box.data_structure import Box3D from nuscenes.eval.common.utils import Quaternion, quaternion_yaw FPS = 20 FRAME_INTERVAL = 10.0 FPS_KEYFRAME = FPS / FRAME_INTERVAL def parse_token(anno: Dict, scene_root: str, frame: str) -> Dict: """Convert root of the sequence dir and frame of a file to nuScenes-like token and ts Returns: token: unique identifier for every frame of the data timestamp: unique identifier of the frame according to time """ # example: seq -> routes_extensive_RouteScenario_0_Town02_2023_04_13_02_54_17 # town_index -> 6, route_index -> 45 seq: str = scene_root.split("/")[-1] town_string: str = seq.split("_")[4] try: town_index = int(scene_root.split("Town")[-1].split("_")[0]) except ValueError: town_index = int(scene_root.split("Town")[-1].split("_")[0][:2]) # Town10HD route_index = int(scene_root.split("RouteScenario_")[-1].split("_")[0]) # we construct the "unique" token by concatenating seq and frame token: str = f"{seq}_frame_{frame}" # we constrcut the "unique" timestamp by using frames and adding offset for each route frame_int: int = int(float(frame)) max_frame_per_route = 100000 max_route_per_town = 1000 timestamp: int = ( town_index * max_route_per_town + route_index ) * max_frame_per_route + frame_int # update dictionary anno.update( { "token": token, # unique str for each frame "timestamp": timestamp, "scene_token": seq, # unique str for each sequence "frame_idx": frame_int, # frame ID within this sequence "town_string": town_string, # e.g., Town06 } ) return anno def parse_traffic_light_anno(anno: Dict, scene_root: str, frame: str) -> Dict: """Parse annotation of traffic light and stop sign and add to dictionary""" # load traffic light GT traffic_light_path = f"{scene_root}/metadata/traffic_light/{frame}.pkl" with open(traffic_light_path, "rb") as f: traffic_light_data: Dict = pkl.load(f) # update dictionary anno["traffic_light"] = { "hazard": traffic_light_data["hazard"], "in_range": traffic_light_data["in_range"], "light_close_in_dist": traffic_light_data["light_close_in_dist"], "red_light_in_front": traffic_light_data["red_light_in_front"], } # initialize data infos num_obj: int = traffic_light_data["location"].shape[1] anno["traffic_light"].update( { "gt_boxes": np.zeros((num_obj, 7), dtype="float32"), "gt_names": np.zeros((num_obj,), dtype=object), "attr_labels": np.asarray([[] for _ in range(num_obj)]), "valid_flag": np.ones((num_obj,), dtype="bool"), # all valid "bbox_ego_matrix": np.zeros((num_obj, 4, 4), dtype="float32"), } ) # go through all bbox to fill in database info for bbox_idx in range(num_obj): # retrieve basic property bbox_location: np.ndarray = traffic_light_data["location"][0, bbox_idx] # (3, ) bbox_rotation: np.ndarray = traffic_light_data["rotation"][0, bbox_idx] # (3, ) bbox_size: np.ndarray = traffic_light_data["size"][0, bbox_idx] # (3, ) bbox_state: str = traffic_light_data["states"][bbox_idx] # (cls, ) # get box in global coordinate bbox2global = calib_utils.create_transform( bbox_location, bbox_rotation ) # 4 x 4 # compute bbox center, convert to LiDAR coordinate bbox_center = np.array([[0, 0, 0, 1]]).transpose() # 4 x 1 bbox_center_world: np.ndarray = bbox2global @ bbox_center # 4 x 1 bbox_center_ego = np.linalg.inv(anno["ego2global"]) @ bbox_center_world # 4 x 1 bbox_center_lidar = np.linalg.inv(anno["lidar2ego"]) @ bbox_center_ego # 4 x 1 # get orientation in radian bbox2lidar = np.linalg.inv(anno["lidar2global"]) @ bbox2global # 4 x 4 yaw = scipy.spatial.transform.Rotation.from_matrix(bbox2lidar[:3, :3]).as_euler( "xyz", degrees=False )[-1] # get 7dof representation: xyzlwh + yaw, lidar coordinate l, w, h = bbox_size.tolist() x, y, z = bbox_center_lidar[:3, 0] box_7dof = np.array([float(x), float(y), float(z)] + [l, w, h] + [yaw]) # (7, ) # add data into list anno["traffic_light"]["gt_boxes"][bbox_idx] = box_7dof anno["traffic_light"]["bbox_ego_matrix"][bbox_idx] = bbox2global anno["traffic_light"]["gt_names"][bbox_idx] = bbox_state return anno def parse_stop_sign_anno(anno: Dict, scene_root: str, frame: str) -> Dict: """Parse annotation of traffic light and stop sign and add to dictionary""" # load stop sign GT stop_sign_path = f"{scene_root}/metadata/stop_sign/{frame}.pkl" with open(stop_sign_path, "rb") as f: stop_sign_data: Dict = pkl.load(f) # update dictionary anno["stop_sign"] = { "hazard": stop_sign_data["hazard"], "in_range": stop_sign_data["in_range"], } # initialize data infos num_obj: int = stop_sign_data["location"].shape[1] anno["stop_sign"].update( { "gt_boxes": np.zeros((num_obj, 7), dtype="float32"), "gt_names": np.zeros((num_obj,), dtype=object), "attr_labels": np.asarray([[] for _ in range(num_obj)]), "valid_flag": np.ones((num_obj,), dtype="bool"), # all valid "bbox_ego_matrix": np.zeros((num_obj, 4, 4), dtype="float32"), } ) # go through all bbox to fill in database info for bbox_idx in range(num_obj): # retrieve basic property bbox_location: np.ndarray = stop_sign_data["location"][0, bbox_idx] # (3, ) bbox_rotation: np.ndarray = stop_sign_data["rotation"][0, bbox_idx] # (3, ) bbox_size: np.ndarray = stop_sign_data["size"][0, bbox_idx] # (3, ) bbox_state: str = "" # get box in global coordinate bbox2global = calib_utils.create_transform( bbox_location, bbox_rotation ) # 4 x 4 # compute bbox center, convert to LiDAR coordinate bbox_center = np.array([[0, 0, 0, 1]]).transpose() # 4 x 1 bbox_center_world: np.ndarray = bbox2global @ bbox_center # 4 x 1 bbox_center_ego = np.linalg.inv(anno["ego2global"]) @ bbox_center_world # 4 x 1 bbox_center_lidar = np.linalg.inv(anno["lidar2ego"]) @ bbox_center_ego # 4 x 1 # get orientation in radian bbox2lidar = np.linalg.inv(anno["lidar2global"]) @ bbox2global # 4 x 4 yaw = scipy.spatial.transform.Rotation.from_matrix(bbox2lidar[:3, :3]).as_euler( "xyz", degrees=False )[-1] # get 7dof representation: xyzlwh + yaw, lidar coordinate l, w, h = bbox_size.tolist() x, y, z = bbox_center_lidar[:3, 0] box_7dof = np.array([float(x), float(y), float(z)] + [l, w, h] + [yaw]) # (7, ) # add data into list anno["stop_sign"]["gt_boxes"][bbox_idx] = box_7dof anno["stop_sign"]["bbox_ego_matrix"][bbox_idx] = bbox2global anno["stop_sign"]["gt_names"][bbox_idx] = bbox_state return anno def parse_ego_sensor_calib( anno: Dict, scene_root: str, frame: str, vis: bool = False ) -> Dict: """Parse calibration between world, ego, lidar and camera""" save_root = "data/carla/carla_data_0414" # load planning data planning_path = f"{scene_root}/metadata/planning/{frame}.pkl" with open(planning_path, "rb") as handle: planning_data: Dict = pkl.load(handle) # load calibration raw data pose_path = f"{scene_root}/metadata/ego/{frame}.pkl" ego2global = np.asarray(calib_utils.load_ego2world_transform(pose_path)) # 4 x 4 lidar2ego = np.asarray(calib_utils.lidar_to_ego_transform()) # 4 x 4 lidar2global: np.ndarray = ego2global @ lidar2ego # 4 x 4 e2g_r = ego2global[:3, :3] # 3 x 3 # print(lidar2ego) # print(ego2global) # print(lidar2global) # zxc # print('scene_token', anno['scene_token']) # print('frame_idx', anno['frame_idx']) # load raw ego data to build can_bus can_bus = np.zeros((18), dtype="float32") with open(pose_path, "rb") as handle: ego_data: Dict = pkl.load(handle) # location in different coordinates sdc_center_ego = np.array([[0, 0, 0, 1.0]]).transpose() # 4 x 1 sdc_center_lidar = np.linalg.inv(lidar2ego) @ sdc_center_ego # 4 x 1 sdc_center_global = ego2global[:3, 3] can_bus[:3] = sdc_center_global # print("sdc_center_ego\n", sdc_center_ego) # print("sdc_center_lidar\n", sdc_center_lidar) # print("sdc_center_global\n", sdc_center_global) # velocity in different coordinates sdc_vel_global: np.ndarray = ego_data["velocity"] sdc_vel_ego = sdc_vel_global @ np.linalg.inv(e2g_r).T # ego coordinate sdc_vel_lidar: np.ndarray = np.linalg.inv(lidar2ego[:3, :3]) @ sdc_vel_ego # 3 can_bus[13:16] = sdc_vel_ego # print("sdc_vel_ego\n", sdc_vel_ego) # print("sdc_vel_global\n", sdc_vel_global) # print("sdc_vel_lidar\n", sdc_vel_lidar) # zxc # acceleration in ego coordinate sdc_acc_global: np.ndarray = ego_data["acceleration"] sdc_acc_global[-1] = 9.8 # add gravity sdc_acc_ego = sdc_acc_global @ np.linalg.inv(e2g_r).T # ego coordinate sdc_acc_lidar: np.ndarray = np.linalg.inv(lidar2ego[:3, :3]) @ sdc_acc_ego # 3 can_bus[7:10] = sdc_acc_ego # print("sdc_acc_ego\n", sdc_acc_ego) # print("sdc_acc_global\n", sdc_acc_global) # print("sdc_acc_lidar\n", sdc_acc_lidar) # angular vel in ego coordinate sdc_ang_global: np.ndarray = ego_data["angular_velocity"] sdc_ang_ego = sdc_ang_global @ np.linalg.inv(e2g_r).T # ego coordinate sdc_ang_lidar: np.ndarray = np.linalg.inv(lidar2ego[:3, :3]) @ sdc_ang_ego # 3 can_bus[10:13] = sdc_ang_ego # print("sdc_ang_ego\n", sdc_ang_ego) # print("sdc_ang_global\n", sdc_ang_global) # print("sdc_ang_lidar\n", sdc_ang_lidar) # rotation/yaw in different coordinates rot_global_quat = Quaternion( object_rotation.convert_mat2qua(ego2global[:3, :3]) ).elements can_bus[3:7] = rot_global_quat sdc_yaw_global_deg = ego_data["rotation"] # in degree sdc_yaw_global_rad = ego_data["rotation"] / 180 * np.pi # in radian # print('\n') # print("sdc_yaw_global_rad", sdc_yaw_global_rad) # sdc_yaw_lidar = ( # sdc_yaw_global_rad @ np.linalg.inv(lidar2global[:3, :3]).T # ) # lidar coordinate # bbox2lidar = np.linalg.inv(lidar2global) @ ego2global # 4 x 4 yaw_lidar = scipy.spatial.transform.Rotation.from_matrix( np.linalg.inv(lidar2ego)[:3, :3] ).as_euler("xyz", degrees=False)[-1] # print('yaw', yaw) # print('yaw_lidar\n', yaw_lidar) # zxc can_bus[-2] = sdc_yaw_global_rad[1] can_bus[-1] = sdc_yaw_global_deg[1] # print('sdc_yaw_lidar', sdc_yaw_lidar) # print('sdc_yaw_global_rad', sdc_yaw_global_rad) # print('sdc_yaw_global_deg', sdc_yaw_global_deg) # zxc # get ego box in lidar sdc_size: np.ndarray = ego_data["size"] # (3, ) l, w, h = sdc_size.tolist() # sdc's box in lidar coordinate gt_sdc_bbox_lidar = np.array( [ sdc_center_lidar[0, 0], sdc_center_lidar[1, 0], sdc_center_lidar[2, 0], l, w, h, yaw_lidar, sdc_vel_lidar[0], sdc_vel_lidar[1], # sdc_vel_lidar[2], ] ) # 9 # print('gt_sdc_bbox_lidar\n', gt_sdc_bbox_lidar) # load camera calib cam_param_all: Dict[str, Dict] = calib_utils.get_camera_param() cams: Dict[str, Dict] = {} for cam_type in cam_param_all.keys(): cam_intrinsic = calib_utils.get_camera_intrinsics( cam_param_all[cam_type] ) # 3 x 3 sensor2ego = calib_utils.camera_to_ego_transform( cam_param_all[cam_type] ) # 4 x 4 sensor2lidar = np.linalg.inv(lidar2ego) @ sensor2ego # 4 x 4 # convert absolute path to relative path cam_path = f"{scene_root}/image_{cam_type}/{frame}.png" if "carla_1.0" in cam_path: cam_path = cam_path.split("carla_data_0414/")[-1] cam_path = os.path.join(save_root, cam_path) # construct nuScenes-like camera record cams[cam_type] = { "data_path": cam_path, "type": cam_type, "sample_data_token": "fake_cam_token", "cam_intrinsic": cam_intrinsic, "sensor2ego_translation": sensor2ego[:3, 3], "sensor2ego_rotation": object_rotation.convert_mat2qua(sensor2ego[:3, :3]), "sensor2lidar_translation": sensor2lidar[:3, 3], # "sensor2lidar_rotation": object_rotation.convert_mat2qua( # sensor2lidar[:3, :3] # ), "sensor2lidar_rotation": sensor2lidar[:3, :3], "timestamp": anno["timestamp"], "cam_param": cam_param_all[cam_type], } # load lidar data, each frame only has half of the lidar data # so we load both the current frame and one previous frame lidar_cur = f"{scene_root}/lidar/{frame}.npy" frame_int: int = int(float(frame)) pre_frame: str = f"{frame_int - 1:06d}" lidar_pre = f"{scene_root}/lidar/{pre_frame}.npy" points_cur = np.fromfile(lidar_cur, dtype=np.float32) points_cur = points_cur.reshape(-1, 4) points_pre = np.fromfile(lidar_pre, dtype=np.float32) points_pre = points_pre.reshape(-1, 4) points: np.ndarray = np.concatenate((points_cur, points_pre), axis=0) # N x 4 # visualize lidar points only, default color ORANGE if vis: try: save_dir = scene_root.replace("/train/", "/vis_train_lidar/") except: save_dir = scene_root.replace("/val/", "/vis_val_lidar/") save_path: str = os.path.join(save_dir, frame + ".jpg") box_vis.vis_box_on_lidar(points_pre, save_path) # save full-surrounding lidar to disk lidar_path = f"{scene_root}/lidar_full/{frame}.npy" if "carla_1.0" in lidar_path: lidar_path = lidar_path.split("carla_data_0414/")[-1] lidar_path = os.path.join(save_root, lidar_path) if not io_utils.is_path_exists(lidar_path): io_utils.mkdir_if_missing(lidar_path) points.tofile(lidar_path) # get the map string for the whole sequence map_path: str = os.path.join(scene_root, "metadata/hd_map/000000.pkl") command = carla_control.roadoption2int(planning_data["local"][0][1]) # int # update dictionary anno.update( { "lidar_pts": points, "lidar_path": lidar_path, "map_path": map_path, "sweeps": [], "cams": cams, "lidar2ego_translation": lidar2ego[:3, 3], "lidar2ego_rotation": object_rotation.convert_mat2qua( lidar2ego[:3, :3] ), # (4, ) "lidar2ego": lidar2ego, "ego2global_translation": ego2global[:3, 3], "ego2global_rotation": object_rotation.convert_mat2qua( ego2global[:3, :3] ), # (4, ) "ego2global": ego2global, # ego's location in global coordinate "lidar2global": lidar2global, "sdc_vel_global": sdc_vel_global, # sdc's velocity in global coordinate # sdc's information in global/ego coordinate, # 0-3-> loc, 3-7-> rot_quat, 7-10-> acc, 10-13-> ang, # 13-16->vel, -2-> yaw_rad, -1-> yaw_deg "can_bus": can_bus, # sdc's information in lidar coordinate "gt_sdc_bbox_lidar": gt_sdc_bbox_lidar, # 9 "global_plan_short": planning_data["local"], # deque "command": command - 1, # int, convert 1-indexed -> 0-indexed } ) return anno def parse_bbox(anno: Dict, scene_root: str, frame: str, vis: bool = False) -> Dict: """Parse each one of the bounding boxes and compute properties""" # load GT bbox_path = f"{scene_root}/metadata/detection/{frame}.pkl" with open(bbox_path, "rb") as f: bboxes: Dict = pkl.load(f) tracking_path = f"{scene_root}/metadata/tracking/{frame}.pkl" with open(tracking_path, "rb") as f: tracklets: Dict = pkl.load(f) # initialize data infos num_obj: int = bboxes["location"].shape[1] anno.update( { "gt_velocity": np.zeros((num_obj, 2), dtype="float32"), # lidar coordinate "gt_boxes": np.zeros((num_obj, 7), dtype="float32"), # lidar coordinate "gt_bboxes_global": np.zeros((num_obj, 9), dtype="float32"), "gt_names": np.zeros((num_obj,), dtype=object), "gt_inds": np.zeros((num_obj), dtype="int64"), "num_lidar_pts": np.zeros((num_obj,), dtype="float32"), "num_radar_pts": np.zeros((num_obj,), dtype="float32"), "attr_labels": np.asarray([[] for _ in range(num_obj)]), "valid_flag": np.zeros((num_obj,), dtype="bool"), "bbox_ego_matrix": np.zeros((num_obj, 4, 4), dtype="float32"), } ) # get rotation matrix ego2global_rotation_mat: np.ndarray = pyquaternion.Quaternion( anno["ego2global_rotation"] ).rotation_matrix lidar2ego_rotation_mat: np.ndarray = pyquaternion.Quaternion( anno["lidar2ego_rotation"] ).rotation_matrix # go through all bbox to fill in database info bbox_gt_in_ego_list: List[np.ndarray] = list() valid_id_list: List[np.ndarray] = list() for bbox_index in range(num_obj): # retrieve basic property bbox_location: np.ndarray = bboxes["location"][0, bbox_index] # (3, ) bbox_rotation: np.ndarray = bboxes["rotation"][0, bbox_index] # (3, ) bbox_size: np.ndarray = bboxes["size"][0, bbox_index] # (3, ) bbox_cls_vec = bboxes["cls"][0, bbox_index] # (cls, ) # get box in global coordinate bbox2global = calib_utils.create_transform( bbox_location, bbox_rotation ) # 4 x 4 # compute bbox center, convert to LiDAR coordinate bbox_center = np.array([[0, 0, 0, 1.0]]).transpose() # 4 x 1 bbox_center_world: np.ndarray = bbox2global @ bbox_center # 4 x 1 bbox_center_ego = np.linalg.inv(anno["ego2global"]) @ bbox_center_world # 4 x 1 bbox_center_lidar = np.linalg.inv(anno["lidar2ego"]) @ bbox_center_ego # 4 x 1 # retrieve index of the tracklets global_instance_id: int = int(bboxes["id_debug"][0, bbox_index, 0]) tracklet_index: int = ( tracklets["id"][0, :, 0].tolist().index(global_instance_id) ) # get velocity of the most recent frame in lidar coordinate velocity: np.ndarray = tracklets["velocity"][0, tracklet_index, -1, :] # (3, ) velocity_world = np.expand_dims(velocity, axis=1) # 3 x 1 velocity_ego: np.ndarray = ( np.linalg.inv(ego2global_rotation_mat) @ velocity_world ) # 3 x 1 velocity_lidar: np.ndarray = ( np.linalg.inv(lidar2ego_rotation_mat) @ velocity_ego ) # 3 x 1 # get orientation in radian bbox2lidar = np.linalg.inv(anno["lidar2global"]) @ bbox2global # 4 x 4 yaw = scipy.spatial.transform.Rotation.from_matrix(bbox2lidar[:3, :3]).as_euler( "xyz", degrees=False )[-1] # get 7dof representation: xyzlwh + yaw, lidar coordinate l, w, h = bbox_size.tolist() x, y, z = bbox_center_lidar[:3, 0] box_7dof_lidar = np.array( [float(x), float(y), float(z)] + [l, w, h] + [yaw] ) # (7, ) # get 7dof representation: xyzlwh + yaw, global coordinate box_7dof_global = np.array( [ float(bbox_center_world[0]), float(bbox_center_world[1]), float(bbox_center_world[2]), ] + [l, w, h] + [float(bbox_rotation[1]) / 180 * np.pi] ) # (7, ) # extract number of points box3d: Box3D = Box3D.array2bbox_xyzlwhyaw(box_7dof_lidar) box_in_lidar: np.ndarray = Box3D.box2corners3d_lidar(box3d) # 8 x 4 pc_sub: np.ndarray = box_sensor.extract_pc_in_box3d( anno["lidar_pts"], box_in_lidar )[ 0 ] # N x 3 # add data into list anno["num_lidar_pts"][bbox_index] = pc_sub.shape[0] anno["gt_boxes"][bbox_index, :] = box_7dof_lidar # lidar coordinate anno["gt_velocity"][bbox_index, :] = velocity_lidar[ :2, 0 ] # only take xy-plane velocity, in lidar coordinate anno["gt_bboxes_global"][bbox_index, :7] = box_7dof_global anno["gt_bboxes_global"][bbox_index, 7:] = velocity_world[:2, 0] anno["bbox_ego_matrix"][bbox_index] = bbox2global anno["gt_names"][bbox_index] = carla_class.convert_vec2str(bbox_cls_vec) anno["gt_inds"][bbox_index] = global_instance_id # set valid only if there are lidar points inside the box if pc_sub.shape[0] > 0: anno["valid_flag"][bbox_index] = True # convert to the ego coordinate for visualization if vis: box_in_ego: np.ndarray = box_transform.box_in_lidar_to_ego( box_in_lidar ) # 8 x 4 bbox_gt_in_ego_list.append(box_in_ego) valid_id_list.append(global_instance_id) if vis: # get save path for train/val split try: save_dir = scene_root.replace("/train/", "/vis_train_gt/") except: save_dir = scene_root.replace("/val/", "/vis_val_gt/") save_path: str = os.path.join(save_dir, frame + ".jpg") # add ego box box3d: Box3D = Box3D.array2bbox_xyzlwhyaw(anno["gt_sdc_bbox_lidar"][:7]) sdc_box_in_lidar: np.ndarray = Box3D.box2corners3d_lidar(box3d) # 8 x 4 sdc_box_in_ego: np.ndarray = box_transform.box_in_lidar_to_ego( sdc_box_in_lidar ) # 8 x 4 bbox_gt_in_ego_list.append(sdc_box_in_ego) valid_id_list.append(-1) # visualizating boxes box_vis.vis_box_on_lidar( anno["lidar_pts"], save_path, bbox_gt_in_ego_list=bbox_gt_in_ego_list, # bev=False, id_list=valid_id_list, ) # visualizing map from pathlib import Path import matplotlib.pyplot as plt from mmdet3d_plugin.datasets.carla.trajdata_rasterizer import rasterize from trajdata import MapAPI, SceneBatch, VectorMap from trajdata.caching.df_cache import DataFrameCache from trajdata.data_structures import StateTensor from trajdata.dataset_specific.opendrive import parse_maps from trajdata.maps.vec_map_elements import (MapElement, MapElementType, PedCrosswalk, PedWalkway, Polyline, RoadArea, RoadLane) # load map from the disk with open(anno["map_path"], "rb") as handle: opendrive_str = pkl.load(handle) # Parse the ODMap from the opendrive string trajdata_cache_dir = "/home/xweng/trajdata" map_api = MapAPI(trajdata_cache_dir) map_id = f"carla:{anno['town_string']}" parse_maps.init_global_vars() vec_map = parse_maps.parse_opendrive_map( map_filename=None, map_rawstring=opendrive_str, map_id=map_id ) # Save the resulting map to load later DataFrameCache.finalize_and_cache_map( Path(trajdata_cache_dir), vec_map, {"px_per_m": 2} ) # Load map with map api vec_map = map_api.get_map( map_id, incl_road_lanes=True, incl_road_areas=True, incl_ped_crosswalks=True, incl_ped_walkways=True, ) # from bottom to look up, need to flip the world coordinate map_img, polylines, raster_from_world = rasterize( vec_map=vec_map, resolution=5, return_tf_mat=True, incl_centerlines=False, incl_lane_edges=False, # land divider area_color=(255, 255, 255), edge_color=(255, 0, 0), # incl_lane_area=False, # driveable area anno=anno, # debug=True, ) # map_img: H x W x 3, from bottom to look up, right hand coordinate # need to flip in order to get the actual map # polylines: List[Dict] # def get_lane_id(road_id: str, section_idx: int, lane_id: str): # return "_".join((road_id, f"s{section_idx}", lane_id)) # vec_map.visualize_lane_graph( # origin_lane=vec_map.get_road_lane(get_lane_id("13", 0, "1")), # num_hops=5, # raster_from_world=raster_from_world, # ax=ax # # ) return anno def parse_data(scene_root: str, frame: str) -> Dict: """Convert carla data into the collection of path needed by mmdetection3D dataloader Args: scene_root: root of the sequence dir frame: str """ anno = {} anno: Dict = parse_token(anno, scene_root, frame) anno: Dict = parse_ego_sensor_calib(anno, scene_root, frame) anno: Dict = parse_traffic_light_anno(anno, scene_root, frame) anno: Dict = parse_stop_sign_anno(anno, scene_root, frame) anno: Dict = parse_bbox(anno, scene_root, frame) return anno def parse_sequence( scene_root: str, annos: List[Dict], seq_index: List[int], pre_sec: int = 2, fut_sec: int = 6, vis: bool = False, ) -> List[Dict]: """Add past/future trajectory into data at each frame to allow prediction""" # get the name of the sequence seq: str = scene_root.split("/")[-1] anno_seq: List[Dict] = [annos[index] for index in seq_index] print(f"processing: {seq}") # data_frame = [anno['frame_idx'] for anno in annos] # data_frame = [anno['gt_fut_traj'] for anno in annos] # print(data_frame) # sort data by frame ID, as the original data might not be sorted based # on frame index def sort_data(data_dict: Dict): return data_dict["frame_idx"] anno_seq.sort(key=sort_data) min_frame_ID: int = anno_seq[0]["frame_idx"] max_frame_ID: int = anno_seq[-1]["frame_idx"] # data_frame = [anno['frame_idx'] for anno in annos] # print(data_frame) # zxc # loop through each frame in this sequence for index in range(len(seq_index)): anno: Dict = anno_seq[index] # data for the frame frame_ID: int = anno["frame_idx"] # the frame ID # print("current frame is", frame_ID) # check if the data is from the same sequence scene_name: str = anno["scene_token"] # the sequence name assert scene_name == seq, "error, not the same sequence" # retrieve info for other objects # gt_velocity: np.ndarray = anno["gt_velocity"] # N x 2 gt_bboxes_lidar: np.ndarray = anno["gt_boxes"] # N x 7 num_obj: int = gt_bboxes_lidar.shape[0] obj_ids: List[int] = anno["gt_inds"].tolist() # retrieve info for ego and calib l, w, h = anno["gt_sdc_bbox_lidar"][3:6] lidar2global: np.ndarray = anno["lidar2global"] # 4 x 4 ########### get the target data we need for GT pre_frames: int = int(pre_sec * FPS_KEYFRAME) fut_frames: int = int(fut_sec * FPS_KEYFRAME) # the past & future trajectories for objects existing in the current frame # so we know the exact number of objects gt_fut_bbox_lidar: np.ndarray = np.zeros((num_obj, fut_frames, 9)) gt_pre_bbox_lidar: np.ndarray = np.zeros((num_obj, pre_frames, 9)) # initially set all mask as invalid until we identify valid frames gt_fut_bbox_mask: np.ndarray = np.zeros((num_obj, fut_frames, 1)) gt_pre_bbox_mask: np.ndarray = np.zeros((num_obj, pre_frames, 1)) # ALL the past & future trajectories, including objects that appear # from frames to frames, and not existing in the current frame # as a result, the number of objects might not be consistent over frames # can be used to create an Union of all objects for better training gt_fut_bbox_lidar_all: List[np.ndarray] = [ [np.empty([0])] for _ in range(fut_frames) ] gt_pre_bbox_lidar_all: List[np.ndarray] = [ [np.empty([0])] for _ in range(pre_frames) ] # sdc's temporal info gt_pre_bbox_sdc_lidar: np.ndarray = np.zeros((1, pre_frames, 9)) gt_fut_bbox_sdc_lidar: np.ndarray = np.zeros((1, fut_frames, 9)) gt_pre_bbox_sdc_global: np.ndarray = np.zeros((1, pre_frames, 9)) gt_fut_bbox_sdc_global: np.ndarray = np.zeros((1, fut_frames, 9)) gt_pre_bbox_sdc_mask: np.ndarray = np.zeros((1, pre_frames, 1)) gt_fut_bbox_sdc_mask: np.ndarray = np.zeros((1, fut_frames, 1)) gt_pre_command_sdc: np.ndarray = np.zeros((1, pre_frames, 1)) gt_fut_command_sdc: np.ndarray = np.zeros((1, fut_frames, 1)) # get past trajectory, backward order, i.e., frame 4, 3, 2, 1 # start with 1 to not include the current frame for pre_frame_index in range(1, pre_frames + 1): pre_frame_ID = int(frame_ID - pre_frame_index * FRAME_INTERVAL) pre_frame_index_in_seq: int = index - pre_frame_index # skip the initial frame with incomplete lidar and also negative frame if pre_frame_ID < min_frame_ID: continue # retrieve the data in the global coordinate anno_pre_tmp: Dict = anno_seq[pre_frame_index_in_seq] gt_pre_bbox_global_tmp: np.ndarray = anno_pre_tmp[ "gt_bboxes_global" ] # N x 9 num_obj_pre: int = gt_pre_bbox_global_tmp.shape[0] gt_pre_bbox_lidar_tmp = np.zeros((num_obj_pre, 9)) ########## convert the global coordinate to lidar coordinate in current frame # i.e., ego motion compensation # location loc_global = np.concatenate( (gt_pre_bbox_global_tmp[:, :3], np.ones((num_obj_pre, 1))), axis=1 ).T # 4 x N loc_lidar = np.linalg.inv(lidar2global) @ loc_global # 4 x N gt_pre_bbox_lidar_tmp[:, :3] = loc_lidar[:3, :].transpose() # N x 3 # size gt_pre_bbox_lidar_tmp[:, 3:6] = gt_pre_bbox_global_tmp[:, 3:6] # rotation gt_pre_rot_global_rad = np.concatenate( ( np.zeros((num_obj_pre, 1)), gt_pre_bbox_global_tmp[:, [6]], np.zeros((num_obj_pre, 1)), ), axis=1, ) # N x 3 gt_pre_rot_global_deg = gt_pre_rot_global_rad / np.pi * 180 for obj_index in range(num_obj_pre): gt_pre_trans_global = calib_utils.create_transform( gt_pre_bbox_global_tmp[obj_index, :3], gt_pre_rot_global_deg[obj_index], ) # 4 x 4 gt_pre_trans_lidar = ( np.linalg.inv(anno["lidar2global"]) @ gt_pre_trans_global ) # 4 x 4 gt_pre_yaw_lidar = scipy.spatial.transform.Rotation.from_matrix( gt_pre_trans_lidar[:3, :3] ).as_euler("xyz", degrees=False)[-1] gt_pre_bbox_lidar_tmp[obj_index, 6] = gt_pre_yaw_lidar # N x 3 # velocity gt_pre_vel_global = np.concatenate( ( gt_pre_bbox_global_tmp[:, 7:], # N x 2 np.zeros((num_obj_pre, 1)), ), axis=1, ) # N x 3 gt_pre_vel_lidar: np.ndarray = ( np.linalg.inv(lidar2global[:3, :3]) @ gt_pre_vel_global.T ).T # N x 3 gt_pre_bbox_lidar_tmp[:, 7:] = gt_pre_vel_lidar[:, :2] # N x 2 # dump the data into the set of all objects in the future gt_pre_bbox_lidar_all[pre_frame_index - 1] = gt_pre_bbox_lidar_tmp # N x 9 # now check the IDs that exist in the current frame # in order to produce the mask for future frames obj_ids_pre: List[int] = anno_pre_tmp["gt_inds"].tolist() ( obj_ids_common, index_cur, index_past, ) = miscell_utils.find_unique_common_from_lists(obj_ids, obj_ids_pre) # possible that we get 0 object in future frame matching with GT object currint if len(index_cur) > 0: gt_pre_bbox_mask[np.array(index_cur), pre_frame_index - 1] = 1 # also assign the actual gt boxes into the array gt_pre_bbox_lidar[ np.array(index_cur), pre_frame_index - 1, : ] = gt_pre_bbox_lidar_tmp[np.array(index_past), :] ############### get past of the sdc box in lidar coordinate sdc_loc_global, _ = calib_utils.transform_matrix_to_vector( anno_pre_tmp["ego2global"] ) sdc_loc_global = np.concatenate((sdc_loc_global, np.array([1]))) # 4 sdc_loc_lidar = np.linalg.inv(lidar2global) @ sdc_loc_global # 4 sdc_vel_global: np.ndarray = anno_pre_tmp["sdc_vel_global"] # 3 sdc_vel_lidar: np.ndarray = ( np.linalg.inv(lidar2global[:3, :3]) @ sdc_vel_global ) # 3 sdc_trans_lidar = ( np.linalg.inv(lidar2global) @ anno_pre_tmp["ego2global"] ) # 4 x 4 yaw_lidar = scipy.spatial.transform.Rotation.from_matrix( sdc_trans_lidar[:3, :3] ).as_euler("xyz", degrees=False)[-1] yaw_global = scipy.spatial.transform.Rotation.from_matrix( anno_pre_tmp["ego2global"][:3, :3] ).as_euler("xyz", degrees=False)[-1] gt_pre_bbox_sdc_mask[0, pre_frame_index - 1] = 1 # put things into bbox, 9 dof gt_sdc_bbox_lidar = np.array( [ sdc_loc_lidar[0], sdc_loc_lidar[1], sdc_loc_lidar[2], l, w, h, yaw_lidar, sdc_vel_lidar[0], sdc_vel_lidar[1], ] ) gt_pre_bbox_sdc_lidar[0, pre_frame_index - 1] = gt_sdc_bbox_lidar gt_sdc_bbox_global = np.array( [ sdc_loc_global[0], sdc_loc_global[1], sdc_loc_global[2], l, w, h, yaw_global, sdc_vel_global[0], sdc_vel_global[1], ] ) gt_pre_bbox_sdc_global[0, pre_frame_index - 1] = gt_sdc_bbox_global # get command gt_pre_command_sdc[0, pre_frame_index - 1]: int = anno_pre_tmp["command"] # get future trajectory # start with 1 to not include the current frame for fut_frame_index in range(1, fut_frames + 1): fut_frame_ID = int(frame_ID + fut_frame_index * FRAME_INTERVAL) fut_frame_index_in_seq: int = index + fut_frame_index # beyond the last timestamp if fut_frame_ID > max_frame_ID: continue # retrieve the data in the global coordinate anno_fut_tmp: Dict = anno_seq[fut_frame_index_in_seq] gt_fut_bbox_global_tmp: np.ndarray = anno_fut_tmp[ "gt_bboxes_global" ] # N x 9 num_obj_fut: int = gt_fut_bbox_global_tmp.shape[0] gt_fut_bbox_lidar_tmp = np.zeros((num_obj_fut, 9)) ########## convert the global coordinate to lidar coordinate in current frame # i.e., ego motion compensation # location loc_global = np.concatenate( (gt_fut_bbox_global_tmp[:, :3], np.ones((num_obj_fut, 1))), axis=1, ).T # 4 x N loc_lidar = np.linalg.inv(lidar2global) @ loc_global # 4 x N gt_fut_bbox_lidar_tmp[:, :3] = loc_lidar[:3, :].transpose() # N x 3 # size gt_fut_bbox_lidar_tmp[:, 3:6] = gt_fut_bbox_global_tmp[:, 3:6] # rotation gt_fut_rot_global_rad = np.concatenate( ( np.zeros((num_obj_fut, 1)), gt_fut_bbox_global_tmp[:, [6]], np.zeros((num_obj_fut, 1)), ), axis=1, ) # N x 3 gt_fut_rot_global_deg = gt_fut_rot_global_rad / np.pi * 180 for obj_index in range(num_obj_fut): gt_trans_global_future = calib_utils.create_transform( gt_fut_bbox_global_tmp[obj_index, :3], gt_fut_rot_global_deg[obj_index], ) # 4 x 4 gt_fut_trans_lidar = ( np.linalg.inv(anno["lidar2global"]) @ gt_trans_global_future ) # 4 x 4 gt_fut_yaw_lidar = scipy.spatial.transform.Rotation.from_matrix( gt_fut_trans_lidar[:3, :3] ).as_euler("xyz", degrees=False)[-1] gt_fut_bbox_lidar_tmp[obj_index, 6] = gt_fut_yaw_lidar # N x 3 # velocity gt_fut_vel_global = np.concatenate( ( gt_fut_bbox_global_tmp[:, 7:], # N x 2 np.zeros((num_obj_fut, 1)), ), axis=1, ) # N x 3 gt_fut_vel_lidar: np.ndarray = ( np.linalg.inv(lidar2global[:3, :3]) @ gt_fut_vel_global.T ).T # N x 3 gt_fut_bbox_lidar_tmp[:, 7:] = gt_fut_vel_lidar[:, :2] # N x 2 # gt_vel_future_tmp: np.ndarray = anno_future_tmp["gt_velocity"] # N x 2 # gt_box_data_all: np.ndarray = np.concatenate( # (gt_boxes_future_tmp, gt_vel_future_tmp), axis=-1 # ) # N x 9 # print("\nfuture frame is", frame_idx) # print(gt_boxes_future_tmp) # dump the data into the set of all objects in the future gt_fut_bbox_lidar_all[fut_frame_index - 1] = gt_fut_bbox_lidar_tmp # N x 9 # now check the IDs that exist in the current frame # in order to produce the mask for future frames obj_ids_fut: List[int] = anno_fut_tmp["gt_inds"].tolist() ( obj_ids_common, index_cur, index_fut, ) = miscell_utils.find_unique_common_from_lists(obj_ids, obj_ids_fut) # possible that we get 0 object in future frame matching with GT object currint if len(index_cur) > 0: gt_fut_bbox_mask[np.array(index_cur), fut_frame_index - 1] = 1 # also assign the actual gt boxes into the array gt_fut_bbox_lidar[ np.array(index_cur), fut_frame_index - 1, : ] = gt_fut_bbox_lidar_tmp[np.array(index_fut), :] ############## get future of the sdc traj # gt_fut_sdc_global: np.ndarray = anno["can_bus"][:3] # gt_fut_sdc_global = np.concatenate( # (gt_fut_sdc_global, np.array([1])) # ) # gt_fut_sdc_lidar = ( # np.linalg.inv(anno["lidar2global"]) @ gt_fut_sdc_global # ) # 4 x 1 # gt_fut_traj_sdc_lidar[0, future_frame_index - 1, :] = gt_fut_sdc_lidar[:3] ############### get future of the sdc box in lidar coordinate sdc_loc_global, _ = calib_utils.transform_matrix_to_vector( anno_fut_tmp["ego2global"] ) sdc_loc_global = np.concatenate((sdc_loc_global, np.array([1]))) # 4 sdc_loc_lidar = np.linalg.inv(lidar2global) @ sdc_loc_global # 4 sdc_vel_global: np.ndarray = anno_fut_tmp["sdc_vel_global"] # 3 sdc_vel_lidar: np.ndarray = ( np.linalg.inv(lidar2global[:3, :3]) @ sdc_vel_global ) # 3 sdc_trans_lidar = ( np.linalg.inv(lidar2global) @ anno_fut_tmp["ego2global"] ) # 4 x 4 yaw_lidar = scipy.spatial.transform.Rotation.from_matrix( sdc_trans_lidar[:3, :3] ).as_euler("xyz", degrees=False)[-1] yaw_global = scipy.spatial.transform.Rotation.from_matrix( anno_fut_tmp["ego2global"][:3, :3] ).as_euler("xyz", degrees=False)[-1] gt_fut_bbox_sdc_mask[0, fut_frame_index - 1] = 1 # put things into bbox, 9 dof gt_sdc_bbox_lidar = np.array( [ sdc_loc_lidar[0], sdc_loc_lidar[1], sdc_loc_lidar[2], l, w, h, yaw_lidar, sdc_vel_lidar[0], sdc_vel_lidar[1], ] ) gt_fut_bbox_sdc_lidar[0, fut_frame_index - 1] = gt_sdc_bbox_lidar gt_sdc_bbox_global = np.array( [ sdc_loc_global[0], sdc_loc_global[1], sdc_loc_global[2], l, w, h, yaw_global, sdc_vel_global[0], sdc_vel_global[1], ] ) gt_fut_bbox_sdc_global[0, fut_frame_index - 1] = gt_sdc_bbox_global # get command gt_fut_command_sdc[0, fut_frame_index - 1]: int = anno_fut_tmp["command"] # flip array to allow time in forward order for the past trajectory gt_pre_bbox_lidar = np.flip(gt_pre_bbox_lidar, axis=1) gt_pre_bbox_mask = np.flip(gt_pre_bbox_mask, axis=1) gt_pre_bbox_sdc_lidar = np.flip(gt_pre_bbox_sdc_lidar, axis=1) gt_pre_bbox_sdc_global = np.flip(gt_pre_bbox_sdc_global, axis=1) gt_pre_bbox_sdc_mask = np.flip(gt_pre_bbox_sdc_mask, axis=1) gt_pre_command_sdc = np.flip(gt_pre_command_sdc, axis=1) # assign the value back into the dictionary # in-place assignment to the sorted anno anno["gt_pre_bbox_lidar"] = gt_pre_bbox_lidar # N x 4 x 9 anno["gt_fut_bbox_lidar"] = gt_fut_bbox_lidar # N x 12 x 9 anno["gt_pre_bbox_mask"] = gt_pre_bbox_mask # N x 4 x 1 anno["gt_fut_bbox_mask"] = gt_fut_bbox_mask # N x 12 x 1 anno["gt_pre_bbox_sdc_lidar"] = gt_pre_bbox_sdc_lidar # 1 x 4 x 9 anno["gt_fut_bbox_sdc_lidar"] = gt_fut_bbox_sdc_lidar # 1 x 12 x 9 anno["gt_pre_bbox_sdc_global"] = gt_pre_bbox_sdc_global # 1 x 4 x 9 anno["gt_fut_bbox_sdc_global"] = gt_fut_bbox_sdc_global # 1 x 12 x 9 anno["gt_pre_bbox_sdc_mask"] = gt_pre_bbox_sdc_mask # 1 x 4 x 1 anno["gt_fut_bbox_sdc_mask"] = gt_fut_bbox_sdc_mask # 1 x 12 x 1 anno["gt_pre_command_sdc"] = gt_pre_command_sdc # 1 x 4 x 1 anno["gt_fut_command_sdc"] = gt_fut_command_sdc # 1 x 12 x 1 # debug other object's trajectory # print('\nobjects') # # index = 6 # # obj_id = obj_ids[index] # # print(obj_id) # obj_id = 373 # index = obj_ids.index(obj_id) # print(index) # gt_bboxes_lidar = np.expand_dims(gt_bboxes_lidar, axis=1) # gt_box_curfut = np.concatenate( # (gt_bboxes_lidar, gt_fut_traj), axis=1 # ) # N x 13 x 9 # print(gt_past_traj[index]) # print(gt_box_curfut[index]) # print(gt_past_traj_mask[index]) # print(gt_fut_traj_mask[index]) # zxc # debug ego trajectory gt_sdc_bbox_lidar_all = np.concatenate( ( gt_pre_bbox_sdc_lidar[0], # 4 x 9 anno["gt_sdc_bbox_lidar"].reshape((1, -1)), # 1 x 9 gt_fut_bbox_sdc_lidar[0], # 12 x 9 ), axis=0, ) # gt_sdc_mask_all = np.concatenate( # ( # gt_pre_bbox_sdc_mask, # 1 x 4 x 1 # np.array([1]).reshape(1, -1, 1), # gt_fut_bbox_sdc_mask, # ), # axis=1, # ) # gt_sdc_command_all = np.concatenate( # ( # gt_pre_command_sdc, # np.array([anno["command"]]).reshape(1, -1, 1), # gt_fut_command_sdc), # axis=1, # ) # print(gt_fut_traj_sdc_lidar) # print("\nego") # print('gt_sdc_bbox_lidar_all\n', gt_sdc_bbox_lidar_all) # print(gt_sdc_mask_all) # print(gt_sdc_command_all) # zxc # data_frame = [anno['frame_idx'] for anno in annos] # print(data_frame) # data_frame = [anno['gt_fut_traj'].shape for anno in annos] # print(data_frame) # print(obj_ids) # print(obj_ids_fut) # print(obj_ids_common) # print(index_cur) # print(index_fut) # print(gt_fut_traj_mask[:, future_frame_index - 1]) # print(gt_fut_traj[:, future_frame_index - 1]) # # zxc # zxc # zxc if vis: # get save path for train/val split try: save_dir = scene_root.replace("/train/", "/vis_train_gt/") except: save_dir = scene_root.replace("/val/", "/vis_val_gt/") save_path: str = os.path.join(save_dir, "%06d.jpg" % frame_ID) # go through all bboxes bbox_gt_in_ego_list: List[np.ndarray] = list() for bbox_index in range(num_obj): box_7dof_lidar: np.ndarray = anno["gt_boxes"][bbox_index, :] box3d: Box3D = Box3D.array2bbox_xyzlwhyaw(box_7dof_lidar) box_in_lidar: np.ndarray = Box3D.box2corners3d_lidar(box3d) # 8 x 4 box_in_ego: np.ndarray = box_transform.box_in_lidar_to_ego( box_in_lidar ) # 8 x 4 bbox_gt_in_ego_list.append(box_in_ego) # add ego box box3d: Box3D = Box3D.array2bbox_xyzlwhyaw(anno["gt_sdc_bbox_lidar"][:7]) sdc_box_in_lidar: np.ndarray = Box3D.box2corners3d_lidar(box3d) # 8 x 4 sdc_box_in_ego: np.ndarray = box_transform.box_in_lidar_to_ego( sdc_box_in_lidar ) # 8 x 4 bbox_gt_in_ego_list.append(sdc_box_in_ego) # aggregate traj bbox_fut_lidar_all = np.concatenate( (anno["gt_fut_bbox_lidar"], anno["gt_fut_bbox_sdc_lidar"]), axis=0 ) # N x 12 x 9 bbox_fut_mask_all = np.concatenate( (anno["gt_fut_bbox_mask"], anno["gt_fut_bbox_sdc_mask"]), axis=0 ) # N x 12 x 1 bbox_pre_lidar_all = np.concatenate( (anno["gt_pre_bbox_lidar"], anno["gt_pre_bbox_sdc_lidar"]), axis=0 ) # N x 12 x 9 bbox_pre_mask_all = np.concatenate( (anno["gt_pre_bbox_mask"], anno["gt_pre_bbox_sdc_mask"]), axis=0 ) # N x 12 x 1 # visualization box_vis.vis_box_on_lidar( anno["lidar_pts"], save_path, bbox_gt_in_ego_list=bbox_gt_in_ego_list, bev=False, id_list=obj_ids + [-1], fut_traj=bbox_fut_lidar_all, fut_traj_mask=bbox_fut_mask_all, pre_traj=bbox_pre_lidar_all, pre_traj_mask=bbox_pre_mask_all, ) # delete lidar points in the dicionary to reduce file size prior to saving del anno["lidar_pts"] return annos if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument( "--data_root", type=str, default="/mnt/hdd2/datasets/carla_1.0/carla_data_0414", # default="/home/xweng/ngc/workspace/diffstack/experiments/carla/2023-04-09-11-49-06_smallscale_datacollection", help="root directory of raw carla data", ) parser.add_argument( "--output_dir", type=str, default="/mnt/hdd2/datasets/carla_1.0/carla_data_0414", # default="/home/xweng/ngc/workspace/diffstack/experiments/carla/2023-04-09-11-49-06_smallscale_datacollection", help="path of output file", ) parser.add_argument( "--mini", action="store_true", help="generate mini pkl file", ) # parser.add_argument( # "--partial", # action='store_true', # help="partial set of data by sampling to make the dataset smaller", # ) parser.add_argument( "--tiny", action="store_true", help="for debugging purpose", ) parser.add_argument("--split", type=str, default="val", help="train/val") args = parser.parse_args() # nuScenes: train: 28136 frames # nuScenes: train_new (excluding OOD): 27334 frames # 2023/01/15 dataset statistics # train: 114464 (2 runs, 50 x 2 = 100 routes) # val: 37833 # 2023/04/15 dataset statistics (1 run, 173 routes, dynamic weather) # train: 72236 # val: 41305 # trainval: 113541 # 2023/04/14 dataset statistics (1 run, 173 routes, normal weather) # train: 78470 # val: 42404 # val_partial: 10601 # mini: 888 # trainval: 120874 keyframes -> 1208740 total frames (20FPS) = 16.8 hours of driving # go through all sequences annos: List[Dict] = [] num_frames = 0 scene_name: str for scene_name in glob.glob(f"{args.data_root}/{args.split}/*"): seq_index: List[int] = [] for idx in glob.glob(f"{scene_name}/image_front/*.png"): frame: str = idx.split("/")[-1].split(".")[0] frame_int: int = int(float(frame)) # skip the first frame if frame_int == 0: continue # # only process the first 100 frames for debugging # if frame_int > 1000: # continue # only process the first frame ego moving for debugging # if frame_int < 680: # continue # if frame_int > 700: # continue # print(frame) # collect the index of frames that belong to the same sequence seq_index.append(num_frames) anno: Dict = parse_data(scene_name, frame) annos.append(anno) num_frames += 1 if len(annos) % 10 == 0: print("finished: ", len(annos)) # collect temporal data after pre-processing for the entire sequence # e.g., add future trajectory into every frame of data annos: List[Dict] = parse_sequence(scene_name, annos, seq_index) # only process the first sequence for mini if args.mini or args.tiny: break # # reduce frames by random sub-sampling, the order is random # not good doing this as it will change the data frequency at test time # e.g., from 2 Hz to 0.5 Hz, past trajectory data does not make sense # print(f"number of total frames is {len(annos)}") # if args.partial: # def sort_seq(data_dict: Dict): # return data_dict["token"] # annos.sort(key=sort_seq) # annos = annos[0::4] # print(f"number of total frames after sampling is {len(annos)}") if args.tiny: annos = annos[:10] # for anno in annos: # print(anno['token']) print(f"number of total frames after sampling is {len(annos)}") carla = {"infos": annos, "metadata": {"version": "v1.0"}} # save if args.mini: output_path = os.path.join( args.output_dir, f"data_{args.split}_nusc_format_mini.pkl" ) else: # if args.partial: # output_path = os.path.join(args.output_dir, f"data_{args.split}_nusc_format_partial.pkl") if args.tiny: output_path = os.path.join( args.output_dir, f"data_{args.split}_nusc_format_tiny.pkl" ) else: output_path = os.path.join( args.output_dir, f"data_{args.split}_nusc_format.pkl" ) with open(output_path, "wb") as f: pkl.dump(carla, f)