Shortcuts

自定义数据变换和数据增强

数据变换

OpenMMLab算法库中,数据集的构建和数据的准备是相互解耦的,通常,数据集的构建只对数据集进行解析,记录每个样本的基本信息,而数据的准备则是通过一系列的数据变换,根据样本的基本信息进行数据加载、预处理、格式化等操作。

数据变换的使用

MMPose中的数据变换数据增强类定义在$MMPose/datasets/transforms目录中,对应的文件结构如下:

mmpose
|----datasets
    |----transforms
        |----bottomup_transforms    # 自底向上
        |----common_transforms      # 常用变换
        |----converting             # 关键点转换
        |----formatting             # 输入数据格式化
        |----loading                # 原始数据加载
        |----pose3d_transforms      # 三维变换
        |----topdown_transforms     # 自顶向下

MMPose中,数据增强数据变换是使用者经常需要考虑的一个阶段,可参考如下流程进行相关阶段的设计:

common_transforms组件提供了常用的RandomFlip,RandomHalfBody数据增强算法。

MMPose对于Top-DownButtom-Uppose-3d都提供了对应的数据变换接口。通过采用仿射变换,将图像和坐标标注从原始图片空间变换到输入图片空间

RandomFlip为例,该方法随机的对原始图片进行变换,并转换为输入图像中间图像。要定义一个数据变换的过程,需要继承BaseTransform类,并进行TRANSFORM注册:

from mmcv.transforms import BaseTransform
from mmpose.registry import TRANSFORMS

@TRANSFORMS.register_module()
class RandomFlip(BaseTransform):
      """Randomly flip the image, bbox and keypoints.

    Required Keys:

        - img
        - img_shape
        - flip_indices
        - input_size (optional)
        - bbox (optional)
        - bbox_center (optional)
        - keypoints (optional)
        - keypoints_visible (optional)
        - img_mask (optional)

    Modified Keys:

        - img
        - bbox (optional)
        - bbox_center (optional)
        - keypoints (optional)
        - keypoints_visible (optional)
        - img_mask (optional)

    Added Keys:

        - flip
        - flip_direction

    Args:
        prob (float | list[float]): The flipping probability. If a list is
            given, the argument `direction` should be a list with the same
            length. And each element in `prob` indicates the flipping
            probability of the corresponding one in ``direction``. Defaults
            to 0.5
        direction (str | list[str]): The flipping direction. Options are
            ``'horizontal'``, ``'vertical'`` and ``'diagonal'``. If a list is
            is given, each data sample's flipping direction will be sampled
            from a distribution determined by the argument ``prob``. Defaults
            to ``'horizontal'``.
    """
    def __init__(self,
                prob: Union[float, List[float]] = 0.5,
                direction: Union[str, List[str]] = 'horizontal') -> None:
      if isinstance(prob, list):
          assert is_list_of(prob, float)
          assert 0 <= sum(prob) <= 1
      elif isinstance(prob, float):
          assert 0 <= prob <= 1
      else:
          raise ValueError(f'probs must be float or list of float, but \
                            got `{type(prob)}`.')
      self.prob = prob

      valid_directions = ['horizontal', 'vertical', 'diagonal']
      if isinstance(direction, str):
          assert direction in valid_directions
      elif isinstance(direction, list):
          assert is_list_of(direction, str)
          assert set(direction).issubset(set(valid_directions))
      else:
          raise ValueError(f'direction must be either str or list of str, \
                              but got `{type(direction)}`.')
      self.direction = direction

      if isinstance(prob, list):
          assert len(prob) == len(self.direction)

输入

  • prob指定了在水平,垂直,斜向等变换的概率,是一个范围在[0,1]之间的浮点数list

  • direction指定了数据变换的方向:

    • horizontal水平变换

    • vertical垂直变换

    • diagonal对角变换

输出

  • 输出一个经过数据变换后的dict数据

RandomFliptransform实现了对输入图像的以给定的prob概率进行水平、垂直或是对角方向的数据翻转,并返回输出图像。

以下是使用对角翻转变换的一个简单示例:

from mmpose.datasets.transforms import LoadImage, RandomFlip
import mmcv

# 从路径中加载原始图片
results = dict(
  img_path='data/test/multi-person.jpeg'
  )
transform = LoadImage()
results = transform(results)
# 此时,加载的原始图片是一个包含以下属性的`dict`:
# - `img_path`: 图片的绝对路径
# - `img`: 图片的像素点
# - `img_shape`: 图片的形状
# - `ori_shape`: 图片的原始形状

# 对原始图像进行对角翻转变换
transform = RandomFlip(prob=1., direction='diagonal')
results = transform(results)
# 此时,加载的原始图片是一个包含以下属性的`dict`:
# - `img_path`: 图片的绝对路径
# - `img`: 图片的像素点
# - `img_shape`: 图片的形状
# - `ori_shape`: 图片的原始形状
# - `flip`: 图片是否进行翻转变换
# - `flip_direction`: 图片进行翻转变换的方向

# 取出经过翻转变换后的图片
mmcv.imshow(results['img'])

更多有关自定义数据变换和增强的使用方法,可以参考$MMPose/test/test_datasets/test_transforms/test_common_transforms等。

RandomHalfBody

RandomHalfBody数据增强算法概率的进行上半身或下半身的数据变换输入

  • min_total_keypoints最小总关键点数

  • min_half_keypoints最小半身关键点数

  • paddingbbox的填充比例

  • prob在关键点数目符合要求下,接受半身变换的概率

输出

  • 输出一个经过数据变换后的dict数据

TopdownAffine

TopdownAffine数据变换算法通过仿射变换将原始图片变换为输入图片

输入

  • input_sizebbox区域将会被裁剪和修正到的[w,h]大小

  • use_udp是否使用公正的数据过程UDP

输出

  • 输出一个经过数据变换后的dict数据

在流水线中使用数据增强和变换

配置文件中的数据增强数据变换过程可以是如下示例:

train_pipeline_stage2 = [
    ...
    dict(type='RandomFlip', direction='horizontal'),
    dict(type='RandomHalfBody'),
    dict(
        type='RandomBBoxTransform',
        shift_factor=0.,
        scale_factor=[0.75, 1.25],
        rotate_factor=60),
    dict(
         type='TopdownAffine',
         input_size=codec['input_size']),
    ...
]

示例中的流水线对输入数据进行数据增强,进行随机的水平增强和半身增强, 并进行Top-DownShiftRotateResize操作,通过TopdownAffine操作实现仿射变换,变换至输入图片空间