from nuscenes.nuscenes import NuScenes
nusc = NuScenes(version='v1.0-trainval', dataroot=dataroot, verbose=True)
1. Scene
nuScenes는 20초 가량 길이의 scene이 1000개가 존재. 이 중 850개만을 공개.
# load first scene
my_scene = nusc.scene[0]
2. Sample
scene에는 여러개의 sample이 존재. 하나의 sample이 특정 시각에 수집된 각종 데이터 (camera, lidar, radar 등)를 의미. nuScene은 annotation을 2Hz로 했으므로, 두 sample 사이의 시간차는 약 0.5초 이며 하나의 scene에는 약 40개의 sample들이 존재
# load first sample of first scene
first_sample_token = my_scene['first_sample_token']
my_sample = nusc.get('sample', first_sample_token)
위 그림에서 보듯 sample에는 'data'와 'anns'가 존재. 여기서 'data'는 camera, lidar, radar 데이터를 의미. 'anns'은 주변 객체의 2D/3D annotation 정보.
3. Sensor
특정 sample로 부터 해당 시각의 특정 sensor와 연관된 정보를 sample의 형태로 얻을 수 있음.
# obtain a camera sample from the corresponding sample from the scene
nusc.get('sample_data', my_sample['data']['CAM_FRONT'])
# obtain a lidar sample from the corrseponding sample from the scene
nusc.get('sample_data', my_sample['data']['LIDAR_TOP'])
camera sample과 lidar sample의 'sample_token'이 같으며 이는 my_sample의 'token'과 같음을 알 수 있다.
3. Ego Pose
Ego pose는 자율차의 위치 및 자세를 의미한다. 위의 두 그림에서 알 수 있듯이 서로 다른 sensor는 서로 다른 ego_pose_token을 제공한다. 결국 각 센서로 부터 추정한 ego pose가 서로 다름을 알 수 있다. 그 이유는 각 센서가 데이터를 수집한 시점이 100% 일치 할 수 없기 때문이다. 예를 들어, lidar point cloud가 수집된 시점이 1800100ms 이고 image가 수집된 시점이 1800110ms라면 두 센서 수집 시점은 10ms의 차이가 발생하게 되고 그 사이 ego vehicle 의 위치와 자세가 변할 수 있다.
a) egolidar_to_world transformation matrix
lidar_record = self.nusc.get('sample_data', sample_record['data']['LIDAR_TOP'])
egolidar = self.nusc.get('ego_pose', lidar_record['ego_pose_token'])
EL2W = get_pose(egolidar['rotation'], egolidar['translation'], flat=False)
b) egocam_to_world transformation matrix
cam_record = self.nusc.get('sample_data', sample_record['data'][cam])
egocam = self.nusc.get('ego_pose', cam_record['ego_pose_token'])
EC2W = get_pose(egocam['rotation'], egocam['translation'], flat=False) # world_to_egocam
4. Sensor Coordinate System
Sensor에 의해 정의되는 ego centrinc coordinate system과 Sensor coordinate system이 별도로 존재함.
예를 들어, Lidar의 point clould를 image에 사영시키기 위해서는 다음의 과정을 거쳐야 함.
point_clould >> lidar_sensor_to_ego_lidar_pose >> ego_lidar_pose_to_global >> global_to_ego_camera_pose >> ego_camera_pose_to_camera_sensor >> camera_intrinsic >> pixel
아래 코드는 예시를 보여주고 있음.
cam = self.nusc.get('sample_data', camera_token)
pointsensor = self.nusc.get('sample_data', pointsensor_token)
# First step: transform the pointcloud to the ego vehicle frame for the timestamp of the sweep.-------------------------
cs_record = self.nusc.get('calibrated_sensor', pointsensor['calibrated_sensor_token'])
pc.rotate(Quaternion(cs_record['rotation']).rotation_matrix)
pc.translate(np.array(cs_record['translation']))
# Second step: transform from ego to the global frame.------------------------------------------------------------------
poserecord = self.nusc.get('ego_pose', pointsensor['ego_pose_token'])
pc.rotate(Quaternion(poserecord['rotation']).rotation_matrix)
pc.translate(np.array(poserecord['translation']))
# lidar_record = self.nusc.get('sample_data', sample_record['data']['LIDAR_TOP'])
# egolidar = self.nusc.get('ego_pose', lidar_record['ego_pose_token'])
# EL2W = get_pose(egolidar['rotation'], egolidar['translation'], flat=True) # egolidar_to_world
# Third step: transform from global into the ego vehicle frame for the timestamp of the image.--------------------------
poserecord = self.nusc.get('ego_pose', cam['ego_pose_token'])
pc.translate(-np.array(poserecord['translation']))
pc.rotate(Quaternion(poserecord['rotation']).rotation_matrix.T)
# cam_token = sample_record['data'][cam]
# cam_record = self.nusc.get('sample_data', cam_token)
# egocam = self.nusc.get('ego_pose', cam_record['ego_pose_token'])
# W2EC = get_pose(egocam['rotation'], egocam['translation'], flat=False, inv=True) # world_to_egocam
# Fourth step: transform from ego into the camera. ---------------------------------------------------------------------
cs_record = self.nusc.get('calibrated_sensor', cam['calibrated_sensor_token'])
pc.translate(-np.array(cs_record['translation']))
pc.rotate(Quaternion(cs_record['rotation']).rotation_matrix.T)
# cam_token = sample_record['data'][cam]
# cam_record = self.nusc.get('sample_data', cam_token)
# cam = self.nusc.get('calibrated_sensor', cam_record['calibrated_sensor_token'])
# EC2C = get_pose(cam['rotation'], cam['translation'], flat=False, inv=True) # egocam_to_cam
# extrinsic
EL2C = EC2C @ W2EC @ EL2W
'Python' 카테고리의 다른 글
PIL.image 라이브러리 사용법 (0) | 2023.05.31 |
---|---|
Change working directory to current location (0) | 2023.05.18 |
[matplotlib] Creating multiple figures in one plot (0) | 2023.05.08 |
ImportError: cannot import name '_NewEmptyTensorOp' from 'torchvision.ops.misc' (0) | 2023.05.03 |
Resize and crop images in a specific directory (0) | 2023.04.25 |