본문 바로가기

Python

nuScenes 데이터셋의 이해

반응형
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