From ddd3c3d2eeb6d17fa03a0b1895233358c6b90d3e Mon Sep 17 00:00:00 2001 From: hkzhang95 Date: Mon, 7 Sep 2020 22:43:43 +0800 Subject: [PATCH 01/11] add RandomRotate for transforms --- mmseg/datasets/pipelines/transforms.py | 68 ++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/mmseg/datasets/pipelines/transforms.py b/mmseg/datasets/pipelines/transforms.py index 2b314a810f..66866070b9 100644 --- a/mmseg/datasets/pipelines/transforms.py +++ b/mmseg/datasets/pipelines/transforms.py @@ -1,3 +1,4 @@ +import cv2 import mmcv import numpy as np from numpy import random @@ -463,6 +464,73 @@ def __repr__(self): return self.__class__.__name__ + f'(crop_size={self.crop_size})' +@PIPELINES.register_module() +class RandomRotate(object): + """Random rotate the image & seg. + + Args: + max_degree (float): The maximum rotation degree (range from -x to x). + rotation_ratio (float, optional): The rotation probability. + Default: None. + """ + + def __init__(self, max_degree, rotation_ratio=None): + self.rotation_ratio = rotation_ratio + if rotation_ratio is not None: + assert rotation_ratio >= 0 and rotation_ratio <= 1 + self.max_degree = max_degree + + def get_rotation_degree(self): + """Randomly get a rotation degree.""" + rotation_degree = random.uniform(-1 * self.max_degree, self.max_degree) + return rotation_degree + + def rotate(self, + img, + rotation_degree, + flags=cv2.INTER_LINEAR, + borderValue=0): + """Rotate ``img``""" + h, w = img.shape[:2] + center = ((w - 1) * 0.5, (h - 1) * 0.5) + matrix = cv2.getRotationMatrix2D(center, rotation_degree, 1) + img = cv2.warpAffine( + img, matrix, (w, h), flags=flags, borderValue=borderValue) + return img + + def __call__(self, results): + """Call function to randomly rotate images, semantic segmentation maps. + + Args: + results (dict): Result dict from loading pipeline. + + Returns: + dict: Randomly rotated results. + """ + + if 'rotation' not in results: + rotation = True if np.random.rand( + ) < self.rotation_ratio else False + results['rotation'] = rotation + if results['rotation']: + img = results['img'] + rotation_degree = self.get_rotation_degree() + + # rotate the image and semantic segmentation map + img = self.rotate(img, rotation_degree) + results['img'] = img + for key in results.get('seg_fields', []): + results[key] = self.rotate( + results[key], + rotation_degree, + flags=cv2.INTER_NEAREST, + borderValue=255) + return results + + def __repr__(self): + return self.__class__.__name__ + f'(max_degree={self.max_degree})' + + @PIPELINES.register_module() class SegRescale(object): """Rescale semantic segmentation maps. From e2d00bbc3fa0a04061bd4bfd53ca22c74b068dba Mon Sep 17 00:00:00 2001 From: hkzhang95 Date: Thu, 10 Sep 2020 21:09:18 +0800 Subject: [PATCH 02/11] change rotation function to mmcv.imrotate --- mmseg/datasets/pipelines/transforms.py | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/mmseg/datasets/pipelines/transforms.py b/mmseg/datasets/pipelines/transforms.py index 66866070b9..4ceabcd1f7 100644 --- a/mmseg/datasets/pipelines/transforms.py +++ b/mmseg/datasets/pipelines/transforms.py @@ -1,4 +1,3 @@ -import cv2 import mmcv import numpy as np from numpy import random @@ -485,19 +484,6 @@ def get_rotation_degree(self): rotation_degree = random.uniform(-1 * self.max_degree, self.max_degree) return rotation_degree - def rotate(self, - img, - rotation_degree, - flags=cv2.INTER_LINEAR, - borderValue=0): - """Rotate ``img``""" - h, w = img.shape[:2] - center = ((w - 1) * 0.5, (h - 1) * 0.5) - matrix = cv2.getRotationMatrix2D(center, rotation_degree, 1) - img = cv2.warpAffine( - img, matrix, (w, h), flags=flags, borderValue=borderValue) - return img - def __call__(self, results): """Call function to randomly rotate images, semantic segmentation maps. @@ -517,14 +503,14 @@ def __call__(self, results): rotation_degree = self.get_rotation_degree() # rotate the image and semantic segmentation map - img = self.rotate(img, rotation_degree) + img = mmcv.imrotate(img, rotation_degree) results['img'] = img for key in results.get('seg_fields', []): results[key] = self.rotate( results[key], rotation_degree, - flags=cv2.INTER_NEAREST, - borderValue=255) + borderValue=255, + interpolation='nearest') return results def __repr__(self): From b790a27bd3566f1b5bdb152cc9680fd3fad20548 Mon Sep 17 00:00:00 2001 From: Jiarui XU Date: Wed, 28 Oct 2020 10:45:54 -0700 Subject: [PATCH 03/11] refactor --- mmseg/datasets/pipelines/transforms.py | 95 +++++++++++++++++--------- 1 file changed, 64 insertions(+), 31 deletions(-) diff --git a/mmseg/datasets/pipelines/transforms.py b/mmseg/datasets/pipelines/transforms.py index 4ceabcd1f7..09f74bec5f 100644 --- a/mmseg/datasets/pipelines/transforms.py +++ b/mmseg/datasets/pipelines/transforms.py @@ -465,56 +465,89 @@ def __repr__(self): @PIPELINES.register_module() class RandomRotate(object): - """Random rotate the image & seg. + """Rotate the image & seg. Args: - max_degree (float): The maximum rotation degree (range from -x to x). - rotation_ratio (float, optional): The rotation probability. - Default: None. + rotate_ratio (float): The rotation probability. + degree (float, tuple[float]): Range of degrees to select from. If + degrees is a number instead of tuple like (min, max), + the range of degrees will be (-degrees, +degrees) + pad_val (float, optional): Padding value. Default: 0. + seg_pad_val (float, optional): Padding value of segmentation map. + Default: 255. + center (tuple[float], optional): Center point (w, h) of the rotation in + the source image. If not specified, the center of the image will be + used. Default: None. + auto_bound (bool): Whether to adjust the image size to cover the whole + rotated image. Default: False """ - def __init__(self, max_degree, rotation_ratio=None): - self.rotation_ratio = rotation_ratio - if rotation_ratio is not None: - assert rotation_ratio >= 0 and rotation_ratio <= 1 - self.max_degree = max_degree - - def get_rotation_degree(self): - """Randomly get a rotation degree.""" - rotation_degree = random.uniform(-1 * self.max_degree, self.max_degree) - return rotation_degree + def __init__(self, + rotate_ratio, + degree, + pad_val=0, + seg_pad_val=255, + center=None, + auto_bound=False): + self.rotate_ratio = rotate_ratio + assert rotate_ratio >= 0 and rotate_ratio <= 1 + if isinstance(degree, float): + assert degree > 0, f'degree {degree} should be positive' + self.degree = (-degree, degree) + else: + self.degree = degree + assert mmcv.is_tuple_of(self.degree, float) + assert len( + self.degree + ) == 2, f'degree {self.degree} should be a tuple of (min, max)' + self.pal_val = pad_val + self.seg_pad_val = seg_pad_val + self.center = center + self.auto_bound = auto_bound def __call__(self, results): - """Call function to randomly rotate images, semantic segmentation maps. + """Call function to flip bounding boxes, masks, semantic segmentation + maps. Args: results (dict): Result dict from loading pipeline. Returns: - dict: Randomly rotated results. + dict: Flipped results, 'flip', 'flip_direction' keys are added into + result dict. """ - if 'rotation' not in results: - rotation = True if np.random.rand( - ) < self.rotation_ratio else False - results['rotation'] = rotation - if results['rotation']: - img = results['img'] - rotation_degree = self.get_rotation_degree() - - # rotate the image and semantic segmentation map - img = mmcv.imrotate(img, rotation_degree) - results['img'] = img + rotate = True if np.random.rand() < self.rotate_ratio else False + degree = np.random.uniform(min(*self.degree), max(*self.degree)) + if rotate: + # rotate image + results['img'] = mmcv.imrotate( + results['img'], + angle=degree, + border_value=self.pal_val, + center=self.center, + auto_bound=self.auto_bound) + + # rotate segs for key in results.get('seg_fields', []): - results[key] = self.rotate( + results[key] = mmcv.imrotate( results[key], - rotation_degree, - borderValue=255, + angle=degree, + border_value=self.seg_pad_val, + center=self.center, + auto_bound=self.auto_bound, interpolation='nearest') return results def __repr__(self): - return self.__class__.__name__ + f'(max_degree={self.max_degree})' + repr_str = self.__class__.__name__ + repr_str += f'(rotate_ratio={self.rotate_ratio}, ' \ + f'degree={self.degree}, ' \ + f'pad_val={self.pal_val}, ' \ + f'seg_pad_val={self.seg_pad_val}, ' \ + f'center={self.center}, ' \ + f'auto_bound={self.auto_bound})' + return repr_str @PIPELINES.register_module() From 4f917d277828f13c8fe031f80514898fb75df337 Mon Sep 17 00:00:00 2001 From: Jiarui XU Date: Wed, 28 Oct 2020 11:03:02 -0700 Subject: [PATCH 04/11] add unittest --- mmseg/datasets/pipelines/transforms.py | 5 ++-- tests/test_data/test_transform.py | 33 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/mmseg/datasets/pipelines/transforms.py b/mmseg/datasets/pipelines/transforms.py index 09f74bec5f..1dfcdfed19 100644 --- a/mmseg/datasets/pipelines/transforms.py +++ b/mmseg/datasets/pipelines/transforms.py @@ -497,9 +497,8 @@ def __init__(self, else: self.degree = degree assert mmcv.is_tuple_of(self.degree, float) - assert len( - self.degree - ) == 2, f'degree {self.degree} should be a tuple of (min, max)' + assert len(self.degree) == 2, f'degree {self.degree} should be a ' \ + f'tuple of (min, max)' self.pal_val = pad_val self.seg_pad_val = seg_pad_val self.center = center diff --git a/tests/test_data/test_transform.py b/tests/test_data/test_transform.py index 7a1ca0dde3..f407f6f101 100644 --- a/tests/test_data/test_transform.py +++ b/tests/test_data/test_transform.py @@ -197,6 +197,39 @@ def test_pad(): assert img_shape[1] % 32 == 0 +def test_rotate(): + # test assertion degree should be tuple[float] or float + with pytest.raises(AssertionError): + transform = dict(type='RandomRotate', degree='x') + build_from_cfg(transform, PIPELINES) + # test assertion degree should be tuple[float] or float + with pytest.raises(AssertionError): + transform = dict(type='RandomRotate', degree=(10., 20., 30.)) + build_from_cfg(transform, PIPELINES) + + transform = dict(type='RandomRotate', degree=10) + transform = build_from_cfg(transform, PIPELINES) + + results = dict() + img = mmcv.imread( + osp.join(osp.dirname(__file__), '../data/color.jpg'), 'color') + h, w, _ = img.shape + seg = np.array( + Image.open(osp.join(osp.dirname(__file__), '../data/seg.png'))) + results['img'] = img + results['gt_semantic_seg'] = seg + results['seg_fields'] = ['gt_semantic_seg'] + results['img_shape'] = img.shape + results['ori_shape'] = img.shape + # Set initial values for default meta_keys + results['pad_shape'] = img.shape + results['scale_factor'] = 1.0 + + results = transform(results) + assert results['img'].shape[:2] == (h, w) + assert results['gt_semantic_seg'].shape[:2] == (h, w) + + def test_normalize(): img_norm_cfg = dict( mean=[123.675, 116.28, 103.53], From 1f5d504b55909a4fa849df53eaf37d0a86f39e54 Mon Sep 17 00:00:00 2001 From: Jiarui XU Date: Wed, 28 Oct 2020 11:09:34 -0700 Subject: [PATCH 05/11] fixed test --- tests/test_data/test_transform.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_data/test_transform.py b/tests/test_data/test_transform.py index f407f6f101..5620db7327 100644 --- a/tests/test_data/test_transform.py +++ b/tests/test_data/test_transform.py @@ -200,14 +200,15 @@ def test_pad(): def test_rotate(): # test assertion degree should be tuple[float] or float with pytest.raises(AssertionError): - transform = dict(type='RandomRotate', degree='x') + transform = dict(type='RandomRotate', rotate_ratio=0.5, degree='x') build_from_cfg(transform, PIPELINES) # test assertion degree should be tuple[float] or float with pytest.raises(AssertionError): - transform = dict(type='RandomRotate', degree=(10., 20., 30.)) + transform = dict( + type='RandomRotate', rotate_ratio=0.5, degree=(10., 20., 30.)) build_from_cfg(transform, PIPELINES) - transform = dict(type='RandomRotate', degree=10) + transform = dict(type='RandomRotate', degree=10, rotate_ratio=0.5) transform = build_from_cfg(transform, PIPELINES) results = dict() From 2c3745868630555c280c84c071328414da2df211 Mon Sep 17 00:00:00 2001 From: Jiarui XU Date: Wed, 28 Oct 2020 11:13:01 -0700 Subject: [PATCH 06/11] fixed docstring --- mmseg/datasets/pipelines/transforms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmseg/datasets/pipelines/transforms.py b/mmseg/datasets/pipelines/transforms.py index 1dfcdfed19..8aa6fed094 100644 --- a/mmseg/datasets/pipelines/transforms.py +++ b/mmseg/datasets/pipelines/transforms.py @@ -470,8 +470,8 @@ class RandomRotate(object): Args: rotate_ratio (float): The rotation probability. degree (float, tuple[float]): Range of degrees to select from. If - degrees is a number instead of tuple like (min, max), - the range of degrees will be (-degrees, +degrees) + degree is a number instead of tuple like (min, max), + the range of degree will be (``-degree``, ``+degree``) pad_val (float, optional): Padding value. Default: 0. seg_pad_val (float, optional): Padding value of segmentation map. Default: 255. From ff59d26e966ee07b6f8d417181d778adc79ae1fe Mon Sep 17 00:00:00 2001 From: Jiarui XU Date: Wed, 28 Oct 2020 11:19:43 -0700 Subject: [PATCH 07/11] fixed test --- mmseg/datasets/pipelines/transforms.py | 3 +-- tests/test_data/test_transform.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/mmseg/datasets/pipelines/transforms.py b/mmseg/datasets/pipelines/transforms.py index 8aa6fed094..d3e63ef50c 100644 --- a/mmseg/datasets/pipelines/transforms.py +++ b/mmseg/datasets/pipelines/transforms.py @@ -491,12 +491,11 @@ def __init__(self, auto_bound=False): self.rotate_ratio = rotate_ratio assert rotate_ratio >= 0 and rotate_ratio <= 1 - if isinstance(degree, float): + if isinstance(degree, (float, int)): assert degree > 0, f'degree {degree} should be positive' self.degree = (-degree, degree) else: self.degree = degree - assert mmcv.is_tuple_of(self.degree, float) assert len(self.degree) == 2, f'degree {self.degree} should be a ' \ f'tuple of (min, max)' self.pal_val = pad_val diff --git a/tests/test_data/test_transform.py b/tests/test_data/test_transform.py index 5620db7327..afb5413493 100644 --- a/tests/test_data/test_transform.py +++ b/tests/test_data/test_transform.py @@ -200,7 +200,7 @@ def test_pad(): def test_rotate(): # test assertion degree should be tuple[float] or float with pytest.raises(AssertionError): - transform = dict(type='RandomRotate', rotate_ratio=0.5, degree='x') + transform = dict(type='RandomRotate', rotate_ratio=0.5, degree=-10) build_from_cfg(transform, PIPELINES) # test assertion degree should be tuple[float] or float with pytest.raises(AssertionError): @@ -208,7 +208,7 @@ def test_rotate(): type='RandomRotate', rotate_ratio=0.5, degree=(10., 20., 30.)) build_from_cfg(transform, PIPELINES) - transform = dict(type='RandomRotate', degree=10, rotate_ratio=0.5) + transform = dict(type='RandomRotate', degree=10., rotate_ratio=0.5) transform = build_from_cfg(transform, PIPELINES) results = dict() From 26aa84df31a2c2d9a95b58b26470ee5400b56dcd Mon Sep 17 00:00:00 2001 From: Jiarui XU Date: Wed, 28 Oct 2020 12:02:28 -0700 Subject: [PATCH 08/11] add more test --- tests/test_data/test_transform.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/test_data/test_transform.py b/tests/test_data/test_transform.py index afb5413493..f27d031fa7 100644 --- a/tests/test_data/test_transform.py +++ b/tests/test_data/test_transform.py @@ -208,9 +208,17 @@ def test_rotate(): type='RandomRotate', rotate_ratio=0.5, degree=(10., 20., 30.)) build_from_cfg(transform, PIPELINES) - transform = dict(type='RandomRotate', degree=10., rotate_ratio=0.5) + transform = dict(type='RandomRotate', degree=10., rotate_ratio=1.) transform = build_from_cfg(transform, PIPELINES) + assert str(transform) == f'RandomRotate(' \ + f'rotate_ratio={1.}, ' \ + f'degree={10.}, ' \ + f'pad_val={0}, ' \ + f'seg_pad_val={255}, ' \ + f'center={None}, ' \ + f'auto_bound={False})' + results = dict() img = mmcv.imread( osp.join(osp.dirname(__file__), '../data/color.jpg'), 'color') From 0badb9159687fa5ff34cdcb2a80de00c92d36d3b Mon Sep 17 00:00:00 2001 From: Jiarui XU Date: Wed, 28 Oct 2020 12:08:24 -0700 Subject: [PATCH 09/11] fixed repr --- tests/test_data/test_transform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_data/test_transform.py b/tests/test_data/test_transform.py index f27d031fa7..b1d4ef1538 100644 --- a/tests/test_data/test_transform.py +++ b/tests/test_data/test_transform.py @@ -213,7 +213,7 @@ def test_rotate(): assert str(transform) == f'RandomRotate(' \ f'rotate_ratio={1.}, ' \ - f'degree={10.}, ' \ + f'degree=({-10.}, {10.}), ' \ f'pad_val={0}, ' \ f'seg_pad_val={255}, ' \ f'center={None}, ' \ From dd7100547a005fec584600691c35e5df73ad2a95 Mon Sep 17 00:00:00 2001 From: Jiarui XU Date: Wed, 4 Nov 2020 21:58:27 -0800 Subject: [PATCH 10/11] rename to prob --- configs/_base_/datasets/ade20k.py | 2 +- configs/_base_/datasets/cityscapes.py | 2 +- configs/_base_/datasets/cityscapes_769x769.py | 2 +- configs/_base_/datasets/pascal_context.py | 2 +- configs/_base_/datasets/pascal_voc12.py | 2 +- mmseg/datasets/pipelines/transforms.py | 36 +++++++++---------- tests/test_data/test_dataset.py | 2 +- tests/test_data/test_transform.py | 9 +++-- 8 files changed, 28 insertions(+), 29 deletions(-) diff --git a/configs/_base_/datasets/ade20k.py b/configs/_base_/datasets/ade20k.py index a1d9baba7c..efc8b4bb20 100644 --- a/configs/_base_/datasets/ade20k.py +++ b/configs/_base_/datasets/ade20k.py @@ -9,7 +9,7 @@ dict(type='LoadAnnotations', reduce_zero_label=True), dict(type='Resize', img_scale=(2048, 512), ratio_range=(0.5, 2.0)), dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75), - dict(type='RandomFlip', flip_ratio=0.5), + dict(type='RandomFlip', prob=0.5), dict(type='PhotoMetricDistortion'), dict(type='Normalize', **img_norm_cfg), dict(type='Pad', size=crop_size, pad_val=0, seg_pad_val=255), diff --git a/configs/_base_/datasets/cityscapes.py b/configs/_base_/datasets/cityscapes.py index 21cf5c3958..f21867c63e 100644 --- a/configs/_base_/datasets/cityscapes.py +++ b/configs/_base_/datasets/cityscapes.py @@ -9,7 +9,7 @@ dict(type='LoadAnnotations'), dict(type='Resize', img_scale=(2048, 1024), ratio_range=(0.5, 2.0)), dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75), - dict(type='RandomFlip', flip_ratio=0.5), + dict(type='RandomFlip', prob=0.5), dict(type='PhotoMetricDistortion'), dict(type='Normalize', **img_norm_cfg), dict(type='Pad', size=crop_size, pad_val=0, seg_pad_val=255), diff --git a/configs/_base_/datasets/cityscapes_769x769.py b/configs/_base_/datasets/cityscapes_769x769.py index a5bcff3710..336c7b254f 100644 --- a/configs/_base_/datasets/cityscapes_769x769.py +++ b/configs/_base_/datasets/cityscapes_769x769.py @@ -7,7 +7,7 @@ dict(type='LoadAnnotations'), dict(type='Resize', img_scale=(2049, 1025), ratio_range=(0.5, 2.0)), dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75), - dict(type='RandomFlip', flip_ratio=0.5), + dict(type='RandomFlip', prob=0.5), dict(type='PhotoMetricDistortion'), dict(type='Normalize', **img_norm_cfg), dict(type='Pad', size=crop_size, pad_val=0, seg_pad_val=255), diff --git a/configs/_base_/datasets/pascal_context.py b/configs/_base_/datasets/pascal_context.py index a00e474cf6..ff65bad1b8 100644 --- a/configs/_base_/datasets/pascal_context.py +++ b/configs/_base_/datasets/pascal_context.py @@ -12,7 +12,7 @@ dict(type='LoadAnnotations'), dict(type='Resize', img_scale=img_scale, ratio_range=(0.5, 2.0)), dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75), - dict(type='RandomFlip', flip_ratio=0.5), + dict(type='RandomFlip', prob=0.5), dict(type='PhotoMetricDistortion'), dict(type='Normalize', **img_norm_cfg), dict(type='Pad', size=crop_size, pad_val=0, seg_pad_val=255), diff --git a/configs/_base_/datasets/pascal_voc12.py b/configs/_base_/datasets/pascal_voc12.py index 6a367c7f1d..ba1d42d0c5 100644 --- a/configs/_base_/datasets/pascal_voc12.py +++ b/configs/_base_/datasets/pascal_voc12.py @@ -9,7 +9,7 @@ dict(type='LoadAnnotations'), dict(type='Resize', img_scale=(2048, 512), ratio_range=(0.5, 2.0)), dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75), - dict(type='RandomFlip', flip_ratio=0.5), + dict(type='RandomFlip', prob=0.5), dict(type='PhotoMetricDistortion'), dict(type='Normalize', **img_norm_cfg), dict(type='Pad', size=crop_size, pad_val=0, seg_pad_val=255), diff --git a/mmseg/datasets/pipelines/transforms.py b/mmseg/datasets/pipelines/transforms.py index d3e63ef50c..592854ab42 100644 --- a/mmseg/datasets/pipelines/transforms.py +++ b/mmseg/datasets/pipelines/transforms.py @@ -1,5 +1,6 @@ import mmcv import numpy as np +from mmcv.utils import deprecated_api_warning from numpy import random from ..builder import PIPELINES @@ -232,16 +233,17 @@ class RandomFlip(object): method. Args: - flip_ratio (float, optional): The flipping probability. Default: None. + prob (float, optional): The flipping probability. Default: None. direction(str, optional): The flipping direction. Options are 'horizontal' and 'vertical'. Default: 'horizontal'. """ - def __init__(self, flip_ratio=None, direction='horizontal'): - self.flip_ratio = flip_ratio + @deprecated_api_warning({'flip_ratio': 'prob'}, cls_name='RandomFlip') + def __init__(self, prob=None, direction='horizontal'): + self.prob = prob self.direction = direction - if flip_ratio is not None: - assert flip_ratio >= 0 and flip_ratio <= 1 + if prob is not None: + assert prob >= 0 and prob <= 1 assert direction in ['horizontal', 'vertical'] def __call__(self, results): @@ -257,7 +259,7 @@ def __call__(self, results): """ if 'flip' not in results: - flip = True if np.random.rand() < self.flip_ratio else False + flip = True if np.random.rand() < self.prob else False results['flip'] = flip if 'flip_direction' not in results: results['flip_direction'] = self.direction @@ -274,7 +276,7 @@ def __call__(self, results): return results def __repr__(self): - return self.__class__.__name__ + f'(flip_ratio={self.flip_ratio})' + return self.__class__.__name__ + f'(prob={self.prob})' @PIPELINES.register_module() @@ -468,11 +470,11 @@ class RandomRotate(object): """Rotate the image & seg. Args: - rotate_ratio (float): The rotation probability. + prob (float): The rotation probability. degree (float, tuple[float]): Range of degrees to select from. If degree is a number instead of tuple like (min, max), the range of degree will be (``-degree``, ``+degree``) - pad_val (float, optional): Padding value. Default: 0. + pad_val (float, optional): Padding value of image. Default: 0. seg_pad_val (float, optional): Padding value of segmentation map. Default: 255. center (tuple[float], optional): Center point (w, h) of the rotation in @@ -483,14 +485,14 @@ class RandomRotate(object): """ def __init__(self, - rotate_ratio, + prob, degree, pad_val=0, seg_pad_val=255, center=None, auto_bound=False): - self.rotate_ratio = rotate_ratio - assert rotate_ratio >= 0 and rotate_ratio <= 1 + self.prob = prob + assert prob >= 0 and prob <= 1 if isinstance(degree, (float, int)): assert degree > 0, f'degree {degree} should be positive' self.degree = (-degree, degree) @@ -504,18 +506,16 @@ def __init__(self, self.auto_bound = auto_bound def __call__(self, results): - """Call function to flip bounding boxes, masks, semantic segmentation - maps. + """Call function to rotate image, semantic segmentation maps. Args: results (dict): Result dict from loading pipeline. Returns: - dict: Flipped results, 'flip', 'flip_direction' keys are added into - result dict. + dict: Rotated results. """ - rotate = True if np.random.rand() < self.rotate_ratio else False + rotate = True if np.random.rand() < self.prob else False degree = np.random.uniform(min(*self.degree), max(*self.degree)) if rotate: # rotate image @@ -539,7 +539,7 @@ def __call__(self, results): def __repr__(self): repr_str = self.__class__.__name__ - repr_str += f'(rotate_ratio={self.rotate_ratio}, ' \ + repr_str += f'(prob={self.prob}, ' \ f'degree={self.degree}, ' \ f'pad_val={self.pal_val}, ' \ f'seg_pad_val={self.seg_pad_val}, ' \ diff --git a/tests/test_data/test_dataset.py b/tests/test_data/test_dataset.py index d7e44f50ec..e933c200cc 100644 --- a/tests/test_data/test_dataset.py +++ b/tests/test_data/test_dataset.py @@ -69,7 +69,7 @@ def test_custom_dataset(): dict(type='LoadAnnotations'), dict(type='Resize', img_scale=(128, 256), ratio_range=(0.5, 2.0)), dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75), - dict(type='RandomFlip', flip_ratio=0.5), + dict(type='RandomFlip', prob=0.5), dict(type='PhotoMetricDistortion'), dict(type='Normalize', **img_norm_cfg), dict(type='Pad', size=crop_size, pad_val=0, seg_pad_val=255), diff --git a/tests/test_data/test_transform.py b/tests/test_data/test_transform.py index b1d4ef1538..b15f2a0bfa 100644 --- a/tests/test_data/test_transform.py +++ b/tests/test_data/test_transform.py @@ -94,18 +94,17 @@ def test_resize(): def test_flip(): - # test assertion for invalid flip_ratio + # test assertion for invalid prob with pytest.raises(AssertionError): - transform = dict(type='RandomFlip', flip_ratio=1.5) + transform = dict(type='RandomFlip', prob=1.5) build_from_cfg(transform, PIPELINES) # test assertion for invalid direction with pytest.raises(AssertionError): - transform = dict( - type='RandomFlip', flip_ratio=1, direction='horizonta') + transform = dict(type='RandomFlip', prob=1, direction='horizonta') build_from_cfg(transform, PIPELINES) - transform = dict(type='RandomFlip', flip_ratio=1) + transform = dict(type='RandomFlip', prob=1) flip_module = build_from_cfg(transform, PIPELINES) results = dict() From 27e619760651e552440aa747dc165709aab418d0 Mon Sep 17 00:00:00 2001 From: Jiarui XU Date: Sat, 7 Nov 2020 09:21:52 -0800 Subject: [PATCH 11/11] fixed unittest --- tests/test_data/test_transform.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/test_data/test_transform.py b/tests/test_data/test_transform.py index b15f2a0bfa..ff06375c66 100644 --- a/tests/test_data/test_transform.py +++ b/tests/test_data/test_transform.py @@ -199,19 +199,18 @@ def test_pad(): def test_rotate(): # test assertion degree should be tuple[float] or float with pytest.raises(AssertionError): - transform = dict(type='RandomRotate', rotate_ratio=0.5, degree=-10) + transform = dict(type='RandomRotate', prob=0.5, degree=-10) build_from_cfg(transform, PIPELINES) # test assertion degree should be tuple[float] or float with pytest.raises(AssertionError): - transform = dict( - type='RandomRotate', rotate_ratio=0.5, degree=(10., 20., 30.)) + transform = dict(type='RandomRotate', prob=0.5, degree=(10., 20., 30.)) build_from_cfg(transform, PIPELINES) - transform = dict(type='RandomRotate', degree=10., rotate_ratio=1.) + transform = dict(type='RandomRotate', degree=10., prob=1.) transform = build_from_cfg(transform, PIPELINES) assert str(transform) == f'RandomRotate(' \ - f'rotate_ratio={1.}, ' \ + f'prob={1.}, ' \ f'degree=({-10.}, {10.}), ' \ f'pad_val={0}, ' \ f'seg_pad_val={255}, ' \