BEVerse のデータセット前処理コードの分析
主に、BEVerse プロジェクトの Nuscenes データセットの前処理部分を分析します。
1. データセット生成スクリプト
詳細なリファレンス:BEVerse/docs/data_preparation.md
- 1.1 データ構造
BEVerse
├── mmdet3d
├── tools
├── configs
├── projects
├── data
│ ├── nuscenes
│ │ ├── maps
│ │ ├── samples
│ │ ├── sweeps
│ │ ├── v1.0-test
| | ├── v1.0-trainval
- 1.2 data_info 生成スクリプト
python tools/create_data.py nuscenes --root-path ./data/nuscenes --out-dir ./data/nuscenes --extra-tag nuscenes
2. 生成されたスクリプトを詳しく見る
ファイルの場所:BEVerse/tools/create_data.py
コア処理: main 関数では、「kitti」、「nuscenes」などのデータセットのさまざまなデータ型に応じて、さまざまなデータ前処理が実行され、キーと値のペアの情報ファイルにパッケージ化され、保管されています。この記事では主に nuscenes_data_prep() 関数の分析に焦点を当てます。
メインコード:
def nuscenes_data_prep(root_path,
info_prefix,
version,
dataset_name,
out_dir,
max_sweeps=10):
"""Prepare data related to nuScenes dataset.
Related data consists of '.pkl' files recording basic infos,
2D annotations and groundtruth database.
Args:
root_path (str): Path of dataset root.
info_prefix (str): The prefix of info filenames.
version (str): Dataset version.
dataset_name (str): The dataset class name.
out_dir (str): Output directory of the groundtruth database info.
max_sweeps (int): Number of input consecutive frames. Default: 10
"""
import os
info_save_path = 'data/nuscenes_infos'
os.makedirs(info_save_path, exist_ok=True)
nuscenes_converter.create_nuscenes_infos(
root_path, info_prefix, version=version, max_sweeps=max_sweeps, info_save_path=info_save_path)
if version == 'v1.0-test':
info_test_path = osp.join(
info_save_path, f'{info_prefix}_infos_test.pkl')
nuscenes_converter.export_2d_annotation(
root_path, info_test_path, version=version)
return
info_train_path = osp.join(
info_save_path, f'{info_prefix}_infos_train.pkl')
info_val_path = osp.join(info_save_path, f'{info_prefix}_infos_val.pkl')
nuscenes_converter.export_2d_annotation(
root_path, info_train_path, version=version)
nuscenes_converter.export_2d_annotation(
root_path, info_val_path, version=version)
Nuscenes データの前処理には主に、ストレージ パスの確立、データ情報の確立 (create_nuscenes_infos)、2D 注釈のエクスポート (export_2d_annotation) などが含まれます。
3. コア機能
3.1 データ情報の作成
1. 関数プロトタイプ
ファイルの場所:BEVerse/tools/data_converter/nuscenes_converter.py
def create_nuscenes_infos(root_path,
info_prefix,
version='v1.0-trainval',
max_sweeps=10,
info_save_path=None):
"""Create info file of nuscene dataset.
Given the raw data, generate its related info file in pkl format.
Args:
root_path (str): Path of the data root.
info_prefix (str): Prefix of the info file to be generated.
version (str): Version of the data.
Default: 'v1.0-trainval'
max_sweeps (int): Max number of sweeps.
Default: 10
"""
## 1. 利用Nuscenes工具导入scene场景
from nuscenes.nuscenes import NuScenes
nusc = NuScenes(version=version, dataroot=root_path, verbose=True)
from nuscenes.utils import splits
available_vers = ['v1.0-trainval', 'v1.0-test', 'v1.0-mini']
assert version in available_vers
if version == 'v1.0-trainval':
train_scenes = splits.train
val_scenes = splits.val
elif version == 'v1.0-test':
train_scenes = splits.test
val_scenes = []
elif version == 'v1.0-mini':
train_scenes = splits.mini_train
val_scenes = splits.mini_val
else:
raise ValueError('unknown')
# 2. filter existing scenes.
available_scenes = get_available_scenes(nusc)
available_scene_names = [s['name'] for s in available_scenes]
train_scenes = list(
filter(lambda x: x in available_scene_names, train_scenes))
val_scenes = list(filter(lambda x: x in available_scene_names, val_scenes))
train_scenes = set([
available_scenes[available_scene_names.index(s)]['token']
for s in train_scenes
])
val_scenes = set([
available_scenes[available_scene_names.index(s)]['token']
for s in val_scenes
])
test = 'test' in version
if test:
print('test scene: {}'.format(len(train_scenes)))
else:
print('train scene: {}, val scene: {}'.format(
len(train_scenes), len(val_scenes)))
## 3. 填充训练集验证集信息
train_nusc_infos, val_nusc_infos = _fill_trainval_infos(
nusc, train_scenes, val_scenes, test, max_sweeps=max_sweeps)
info_save_path = info_save_path if info_save_path else root_path
metadata = dict(version=version)
if test:
print('test sample: {}'.format(len(train_nusc_infos)))
data = dict(infos=train_nusc_infos, metadata=metadata)
info_path = osp.join(info_save_path,
'{}_infos_test.pkl'.format(info_prefix))
mmcv.dump(data, info_path)
else:
print('train sample: {}, val sample: {}'.format(
len(train_nusc_infos), len(val_nusc_infos)))
# train infos
data = dict(infos=train_nusc_infos, metadata=metadata)
info_path = osp.join(info_save_path,
'{}_infos_train.pkl'.format(info_prefix))
mmcv.dump(data, info_path)
# val infos
data['infos'] = val_nusc_infos
info_val_path = osp.join(info_save_path,
'{}_infos_val.pkl'.format(info_prefix))
mmcv.dump(data, info_val_path)
# trainval infos
trainval_nusc_infos = train_nusc_infos + val_nusc_infos
data['infos'] = trainval_nusc_infos
info_trainval_path = osp.join(info_save_path,
'{}_infos_trainval.pkl'.format(info_prefix))
mmcv.dump(data, info_trainval_path)
2. プロセス分析
1) ミニ データセットを例に挙げると、まず Nuscenes の組み込みツールを使用して train_scenes (8 つのトレーニング シーン) と val_scenes (2 つの検証シーン) を生成します。
2) 次に、既存のシーンをフィルタリングし、既存のトレーニング シーンと検証シーンからトークンを抽出し、セットを再構成して、それぞれ と に保存しtrain_scenes
ますval_scenes
。3) 元のデータからトレーニング セットと検証セットの情報 (_fill_trainval_infos) を生成し、さまざまなデータと属性を抽出して、キーと値のペア
の形式で保存します。4) 最後に、train_nusc_infos/val_nusc_infos とメタデータ (バージョンのキーと値のペア) をまとめてパックし、 に配置し、mmcv.dump を通じて pkl ファイルとして保存します。train_nusc_infos
val_nusc_infos
data
3.2 2D 注釈のエクスポート
1. 関数プロトタイプ
def export_2d_annotation(root_path, info_path, version, mono3d=True):
"""Export 2d annotation from the info file and raw data.
Args:
root_path (str): Root path of the raw data.
info_path (str): Path of the info file.
version (str): Dataset version.
mono3d (bool): Whether to export mono3d annotation. Default: True.
"""
# get bbox annotations for camera
camera_types = [
'CAM_FRONT',
'CAM_FRONT_RIGHT',
'CAM_FRONT_LEFT',
'CAM_BACK',
'CAM_BACK_LEFT',
'CAM_BACK_RIGHT',
]
nusc_infos = mmcv.load(info_path)['infos']
nusc = NuScenes(version=version, dataroot=root_path, verbose=True)
# info_2d_list = []
cat2Ids = [
dict(id=nus_categories.index(cat_name), name=cat_name)
for cat_name in nus_categories
]
coco_ann_id = 0
coco_2d_dict = dict(annotations=[], images=[], categories=cat2Ids)
for info in mmcv.track_iter_progress(nusc_infos):
for cam in camera_types:
cam_info = info['cams'][cam]
coco_infos = get_2d_boxes(
nusc,
cam_info['sample_data_token'],
visibilities=['', '1', '2', '3', '4'],
mono3d=mono3d)
(height, width, _) = mmcv.imread(cam_info['data_path']).shape
coco_2d_dict['images'].append(
dict(
file_name=cam_info['data_path'].split('data/nuscenes/')
[-1],
id=cam_info['sample_data_token'],
token=info['token'],
cam2ego_rotation=cam_info['sensor2ego_rotation'],
cam2ego_translation=cam_info['sensor2ego_translation'],
ego2global_rotation=info['ego2global_rotation'],
ego2global_translation=info['ego2global_translation'],
cam_intrinsic=cam_info['cam_intrinsic'],
width=width,
height=height))
for coco_info in coco_infos:
if coco_info is None:
continue
# add an empty key for coco format
coco_info['segmentation'] = []
coco_info['id'] = coco_ann_id
coco_2d_dict['annotations'].append(coco_info)
coco_ann_id += 1
if mono3d:
json_prefix = f'{info_path[:-4]}_mono3d'
else:
json_prefix = f'{info_path[:-4]}'
mmcv.dump(coco_2d_dict, f'{json_prefix}.coco.json')
2. プロセス分析
1) まず、3.1 で格納した infos 情報である nusc_infos を取得します。
2) 10 個のカテゴリを ID インデックス値に配置します。
3) infos 情報を走査し、複数のカメラを個別に走査し、sample_data_token、さまざまな回転行列、ラベル情報などの各カメラの属性情報を coco_2d_dict に保存します。
4. 生成されるファイルとその内容の説明
詳細についてはdocs/datasets/nuscenes_det.md
英語版のドキュメントを参照してください データのディレクトリ構成は以下のとおりですが、ここでは.pkl
点群を用いた手法で使用されるファイルを中心に説明します。.json
画像ベースの 2D および 3D 検出など、Coco スタイルの画像ベースのアプローチです。
├── data
│ ├── nuscenes
│ │ ├── maps
│ │ ├── samples
│ │ ├── sweeps
│ │ ├── v1.0-test
| | ├── v1.0-trainval
│ │ ├── nuscenes_database
│ │ ├── nuscenes_infos_train.pkl
│ │ ├── nuscenes_infos_val.pkl
│ │ ├── nuscenes_infos_test.pkl
│ │ ├── nuscenes_dbinfos_train.pkl
│ │ ├── nuscenes_infos_train_mono3d.coco.json
│ │ ├── nuscenes_infos_val_mono3d.coco.json
│ │ ├── nuscenes_infos_test_mono3d.coco.json
- nuscenes_database/xxxxx.bin: トレーニング データセットの各 3D バウンディング ボックスに含まれる点群データ。
- nuscenes_infos_train.pkl: トレーニング データ セット情報。次の 2 つのキー値が含まれます
metadata 和 infos
。メタデータはデータセット自体の基本情報 ({'version': 'v1.0-trainval'} など) であり、infos には詳細情報が含まれます。- info['lidar_path']: LIDAR 点群データのファイル パス。
- info['token']: サンプル データ トークン。
- info['スイープ']: スキャン情報。
有别于samples关键帧
。- info['スイープ'][i]['data_path']: i 番目のスキャンのデータ パス。
- info['sweets'][i]['type']: スキャン データのタイプ (「lidar」など)。
- info['スイープs'][i]['sample_data_token']: スイープ サンプル データ トークン。
- info['スイープ'][i]['sensor2ego_translation']: 現在のセンサーから自我車両への変換 (1x3 リスト)。
- info['スイープ'][i]['sensor2ego_rotation']: 現在のセンサーから自我車両までの回転 (クォータニオン形式の 1x4 リスト)。
- info['スイープ'][i]['ego2global_translation']: 自我車両からグローバル座標への変換 (1x3 リスト)。
- info['スイープ'][i]['ego2global_rotation']: 自我車両からグローバル座標への回転 (クォータニオン形式の 1x4 リスト)。
- info['スイープ'][i]['タイムスタンプ']: スキャンされたデータのタイムスタンプ。
- info['スイープ'][i]['sensor2lidar_translation']: 現在のセンサー (スキャン データの収集に使用) から LIDAR への変換 (1x3 リスト)。
- info['スイープ'][i]['sensor2lidar_rotation']: 現在のセンサー (スキャン データの収集に使用) から LIDAR (クォータニオン形式の 1x4 リスト) への回転。
- info['cams']: カメラのキャリブレーション情報。これには、各カメラに対応する 6 つのキー値 (「CAM_FRONT」、「CAM_FRONT_RIGHT」、「CAM_FRONT_LEFT」、「CAM_BACK」、「CAM_BACK_LEFT」、「CAM_BACK_RIGHT」) が含まれています。
- info['lidar2ego_translation']: Lidar からエゴへの変換 (1x3 リスト)。
- info['lidar2ego_rotation']: LIDAR から自我車両への回転 (クォータニオン形式の 1x4 リスト)。
- info['ego2global_translation']: エゴからグローバル座標への変換 (1x3 リスト)。
- info['ego2global_rotation']: 自我車両からグローバル座標への回転 (四元数形式の 1x4 リスト)。
- info['timestamp']: サンプル データのタイムスタンプ。
- info['gt_boxes']: 7 自由度の 3D バウンディング ボックス、Nx7 配列。
- info['gt_names']: 3D バウンディング ボックスのカテゴリ、1xN 配列。
- info['gt_velocity']: 3D バウンディング ボックスの速度 (不正確のため垂直方向の測定はありません)、Nx2 配列。
- info['num_lidar_pts']: 各 3D バウンディング ボックスに含まれる LIDAR ポイントの数。
- info['num_radar_pts']: 各 3D 境界ボックスに含まれるレーダー ポイントの数。
- info['valid_flag']: 各境界ボックスが有効かどうか。一般に、
至少一个
LIDAR またはミリ波レーダー ポイントを含む 3D ボックスのみが有効なボックスと見なされます。