|
# 自定义数据预处理流程 |
|
|
|
## 数据预处理流程的设计 |
|
|
|
遵循一般惯例,我们使用 `Dataset` 和 `DataLoader` 来调用多个进程进行数据的加载。`Dataset` 将会返回与模型前向传播的参数所对应的数据项构成的字典。因为目标检测中的数据的尺寸可能无法保持一致(如点云中点的数量、真实标注框的尺寸等),我们在 MMCV 中引入一个 `DataContainer` 类型,来帮助收集和分发不同尺寸的数据。请参考[此处](https://github.com/open-mmlab/mmcv/blob/master/mmcv/parallel/data_container.py)获取更多细节。 |
|
|
|
数据预处理流程和数据集之间是互相分离的两个部分,通常数据集定义了如何处理标注信息,而数据预处理流程定义了准备数据项字典的所有步骤。数据集预处理流程包含一系列的操作,每个操作将一个字典作为输入,并输出应用于下一个转换的一个新的字典。 |
|
|
|
我们将在下图中展示一个最经典的数据集预处理流程,其中蓝色框表示预处理流程中的各项操作。随着预处理的进行,每一个操作都会添加新的键值(图中标记为绿色)到输出字典中,或者更新当前存在的键值(图中标记为橙色)。 |
|
|
|
![](../../../resources/data_pipeline.png) |
|
|
|
预处理流程中的各项操作主要分为数据加载、预处理、格式化、测试时的数据增强。 |
|
|
|
接下来将展示一个用于 PointPillars 模型的数据集预处理流程的例子。 |
|
|
|
```python |
|
train_pipeline = [ |
|
dict( |
|
type='LoadPointsFromFile', |
|
load_dim=5, |
|
use_dim=5, |
|
backend_args=backend_args), |
|
dict( |
|
type='LoadPointsFromMultiSweeps', |
|
sweeps_num=10, |
|
backend_args=backend_args), |
|
dict(type='LoadAnnotations3D', with_bbox_3d=True, with_label_3d=True), |
|
dict( |
|
type='GlobalRotScaleTrans', |
|
rot_range=[-0.3925, 0.3925], |
|
scale_ratio_range=[0.95, 1.05], |
|
translation_std=[0, 0, 0]), |
|
dict(type='RandomFlip3D', flip_ratio_bev_horizontal=0.5), |
|
dict(type='PointsRangeFilter', point_cloud_range=point_cloud_range), |
|
dict(type='ObjectRangeFilter', point_cloud_range=point_cloud_range), |
|
dict(type='ObjectNameFilter', classes=class_names), |
|
dict(type='PointShuffle'), |
|
dict(type='DefaultFormatBundle3D', class_names=class_names), |
|
dict(type='Collect3D', keys=['points', 'gt_bboxes_3d', 'gt_labels_3d']) |
|
] |
|
test_pipeline = [ |
|
dict( |
|
type='LoadPointsFromFile', |
|
load_dim=5, |
|
use_dim=5, |
|
backend_args=backend_args), |
|
dict( |
|
type='LoadPointsFromMultiSweeps', |
|
sweeps_num=10, |
|
backend_args=backend_args), |
|
dict( |
|
type='MultiScaleFlipAug', |
|
img_scale=(1333, 800), |
|
pts_scale_ratio=1.0, |
|
flip=False, |
|
pcd_horizontal_flip=False, |
|
pcd_vertical_flip=False, |
|
transforms=[ |
|
dict( |
|
type='GlobalRotScaleTrans', |
|
rot_range=[0, 0], |
|
scale_ratio_range=[1., 1.], |
|
translation_std=[0, 0, 0]), |
|
dict(type='RandomFlip3D'), |
|
dict( |
|
type='PointsRangeFilter', point_cloud_range=point_cloud_range), |
|
dict( |
|
type='DefaultFormatBundle3D', |
|
class_names=class_names, |
|
with_label=False), |
|
dict(type='Collect3D', keys=['points']) |
|
]) |
|
] |
|
``` |
|
|
|
对于每项操作,我们将列出相关的被添加/更新/移除的字典项。 |
|
|
|
### 数据加载 |
|
|
|
`LoadPointsFromFile` |
|
|
|
- 添加:points |
|
|
|
`LoadPointsFromMultiSweeps` |
|
|
|
- 更新:points |
|
|
|
`LoadAnnotations3D` |
|
|
|
- 添加:gt_bboxes_3d, gt_labels_3d, gt_bboxes, gt_labels, pts_instance_mask, pts_semantic_mask, bbox3d_fields, pts_mask_fields, pts_seg_fields |
|
|
|
### 预处理 |
|
|
|
`GlobalRotScaleTrans` |
|
|
|
- 添加:pcd_trans, pcd_rotation, pcd_scale_factor |
|
- 更新:points, \*bbox3d_fields |
|
|
|
`RandomFlip3D` |
|
|
|
- 添加:flip, pcd_horizontal_flip, pcd_vertical_flip |
|
- 更新:points, \*bbox3d_fields |
|
|
|
`PointsRangeFilter` |
|
|
|
- 更新:points |
|
|
|
`ObjectRangeFilter` |
|
|
|
- 更新:gt_bboxes_3d, gt_labels_3d |
|
|
|
`ObjectNameFilter` |
|
|
|
- 更新:gt_bboxes_3d, gt_labels_3d |
|
|
|
`PointShuffle` |
|
|
|
- 更新:points |
|
|
|
`PointsRangeFilter` |
|
|
|
- 更新:points |
|
|
|
### 格式化 |
|
|
|
`DefaultFormatBundle3D` |
|
|
|
- 更新:points, gt_bboxes_3d, gt_labels_3d, gt_bboxes, gt_labels |
|
|
|
`Collect3D` |
|
|
|
- 添加:img_meta (由 `meta_keys` 指定的键值构成的 img_meta) |
|
- 移除:所有除 `keys` 指定的键值以外的其他键值 |
|
|
|
### 测试时的数据增强 |
|
|
|
`MultiScaleFlipAug` |
|
|
|
- 更新: scale, pcd_scale_factor, flip, flip_direction, pcd_horizontal_flip, pcd_vertical_flip (与这些指定的参数对应的增强后的数据列表) |
|
|
|
## 扩展并使用自定义数据集预处理方法 |
|
|
|
1. 在任意文件中写入新的数据集预处理方法,如 `my_pipeline.py`,该预处理方法的输入和输出均为字典 |
|
|
|
```python |
|
from mmdet.datasets import PIPELINES |
|
|
|
@PIPELINES.register_module() |
|
class MyTransform: |
|
|
|
def __call__(self, results): |
|
results['dummy'] = True |
|
return results |
|
``` |
|
|
|
2. 导入新的预处理方法类 |
|
|
|
```python |
|
from .my_pipeline import MyTransform |
|
``` |
|
|
|
3. 在配置文件中使用该数据集预处理方法 |
|
|
|
```python |
|
train_pipeline = [ |
|
dict( |
|
type='LoadPointsFromFile', |
|
load_dim=5, |
|
use_dim=5, |
|
backend_args=backend_args), |
|
dict( |
|
type='LoadPointsFromMultiSweeps', |
|
sweeps_num=10, |
|
backend_args=backend_args), |
|
dict(type='LoadAnnotations3D', with_bbox_3d=True, with_label_3d=True), |
|
dict( |
|
type='GlobalRotScaleTrans', |
|
rot_range=[-0.3925, 0.3925], |
|
scale_ratio_range=[0.95, 1.05], |
|
translation_std=[0, 0, 0]), |
|
dict(type='RandomFlip3D', flip_ratio_bev_horizontal=0.5), |
|
dict(type='PointsRangeFilter', point_cloud_range=point_cloud_range), |
|
dict(type='ObjectRangeFilter', point_cloud_range=point_cloud_range), |
|
dict(type='ObjectNameFilter', classes=class_names), |
|
dict(type='MyTransform'), |
|
dict(type='PointShuffle'), |
|
dict(type='DefaultFormatBundle3D', class_names=class_names), |
|
dict(type='Collect3D', keys=['points', 'gt_bboxes_3d', 'gt_labels_3d']) |
|
] |
|
``` |
|
|