启明办公

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 102|回复: 0

MMDetection3D:NuScenes数据集加载

[复制链接]

1

主题

7

帖子

9

积分

新手上路

Rank: 1

积分
9
发表于 2023-1-17 03:33:48 | 显示全部楼层 |阅读模式


一、创建流程

mmdet3d将nuscenes数据加载的流程进一步进行了标准化,以前的各类模型(e.g. CRFNet CenterFusion)等对于nuscenes数据集处理各不相同,就导致我们使用时需要重复造轮子,尤其是在进行多相机视图,多帧雷达点云融合时,各种各样的坐标转换等工作会增加前期工作难度。MMDetection3D对于数据的加载有以下优点:可修改性强、数据加载流程标准、源码书写规范,基于以上原因,深入源码阅读并总结数据加载的方式。
首先,数据通过一行命令完成转换,这个过程中做了以下工作: 1. 将数据信息读入并将其转换为pkl格式方便mmcv.load读取 2. 在读取过程中完成多视图图像的整合、多帧雷达的融合等工作 3. 将保存的pkl文件生成json的annotation文件
python tools/create_data.py nuscenes --root-path ./data/nuscenes --out-dir ./data/nuscenes --extra-tag nuscenes其中,tools/create_data.py完成了数据的格式转换工作
二、主干部分:create_data.py文件

工作流: 1. nuscenes_converter是mmdet3d定义的一系列基于官方提供的NuScenes接口改进的数据操作接口; 2. create_nuscenes_infos()完成从原始的官方数据格式到pkl数据格式的转换,过程中完成数据的规格化工作(e.g.坐标矩阵对齐、多帧雷达数据对齐、多视角的图像数据对齐等) 3. export_2d_annotation()读取pkl数据并生成 '.json‘ 格式的标注数据 4. create_ground_truth_database()
按照这三个函数的顺序逐步拆解create_data.py的数据转换流程
def nuscenes_data_prep(root_path,
                       info_prefix,
                       version,
                       dataset_name,
                       out_dir,
                       max_sweeps=10):
    '''
    root_path:./your_dir_name/data/nuscenes
    info_prefix:自定义的数据集前缀:nuscenes
    version:v1.0-trainval
    max_sweeps:合并的过去雷达帧数
    '''
    # 读入原始数据并生成.pkl文件
    nuscenes_converter.create_nuscenes_infos(
        root_path, info_prefix, version=version, max_sweeps=max_sweeps)

    if version == 'v1.0-test':
        info_test_path = osp.join(root_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(root_path, f'{info_prefix}_infos_train.pkl')
    info_val_path = osp.join(root_path, f'{info_prefix}_infos_val.pkl')
    # export annotation '.json' files separately
    nuscenes_converter.export_2d_annotation(
        root_path, info_train_path, version=version)
    nuscenes_converter.export_2d_annotation(
        root_path, info_val_path, version=version)
    create_groundtruth_database(dataset_name, root_path, info_prefix,
                                f'{out_dir}/{info_prefix}_infos_train.pkl')2.1 nuscenes_converter.py:create_nuscenes_infos()生成规格化数据

def create_nuscenes_infos(root_path,
                          info_prefix,
                          version='v1.0-trainval',
                          max_sweeps=10):
    from nuscenes.nuscenes import NuScenes
    # return nuscenes devkit
    nusc = NuScenes(version=version, dataroot=root_path, verbose=True)
    # split dataset return index of scenes in NusScenes separately
    from nuscenes.utils import splits
    available_vers = ['v1.0-trainval', 'v1.0-test', 'v1.0-mini']
    # 选择有效的scenes index token:train_scenes, val_scenes, test
    # 根据上一步的scenes index生成所有场景的数据以dict列表返回
    train_nusc_infos, val_nusc_infos = _fill_trainval_infos(
        nusc, train_scenes, val_scenes, test, max_sweeps=max_sweeps)

    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(root_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)))
        data = dict(infos=train_nusc_infos, metadata=metadata)
        info_path = osp.join(root_path,
                             '{}_infos_train.pkl'.format(info_prefix))
        mmcv.dump(data, info_path)
        data['infos'] = val_nusc_infos
        info_val_path = osp.join(root_path,
                                 '{}_infos_val.pkl'.format(info_prefix))
        mmcv.dump(data, info_val_path)其中,保存的train_nusc_infos信息如下,其中所有的传感器坐标以lidar为中心计算之间的转移矩阵:
info = {
            'lidar_path': lidar_path,
            'token': sample['token'],
            'sweeps': [], # 上n帧的lidar到当前帧的转换矩阵
            'cams': dict(), # 每个相机到lidar的转换矩阵
            'lidar2ego_translation': cs_record['translation'],
            'lidar2ego_rotation': cs_record['rotation'],
            'ego2global_translation': pose_record['translation'],
            'ego2global_rotation': pose_record['rotation'],
            'timestamp': sample['timestamp'],
        }经过以上步骤,mmcv.dump()把规格化的数据转化成pkl格式的文件。但是,这里没有加载radar数据。
2.2 nuscenes_converter.py:export_2d_annotation规格化标注数据

参数传入:info_train_path是上一步生成的pkl数据规格化文件
nuscenes_converter.export_2d_annotation(
        root_path, info_train_path, version=version)具体介绍: 1. 标注格式,以coco的数据格式存储
coco_2d_dict = dict(annotations=[], images=[], categories=cat2Ids)

  • 标注流程
def export_2d_annotation(root_path, info_path, version, mono3d=True):

    camera_types = [
        'CAM_FRONT',
        'CAM_FRONT_RIGHT',
        'CAM_FRONT_LEFT',
        'CAM_BACK',
        'CAM_BACK_LEFT',
        'CAM_BACK_RIGHT',
    ]
    # 加载上一步生成的pkl文件
    nusc_infos = mmcv.load(info_path)['infos']
    nusc = NuScenes(version=version, dataroot=root_path, verbose=True)
    # category & index的转化
    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)
    # 每个info对应一个sample也就是关键帧
    for info in mmcv.track_iter_progress(nusc_infos):
        # 遍历每个sample的六个相机
        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')
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|天恒办公

Copyright © 2001-2013 Comsenz Inc.Template by Comsenz Inc.All Rights Reserved.

Powered by Discuz!X3.4

快速回复 返回顶部 返回列表