-
Notifications
You must be signed in to change notification settings - Fork 297
Add random_erasing #558
base: master
Are you sure you want to change the base?
Add random_erasing #558
Changes from 21 commits
82e1b06
0eebc97
8dd6a42
5033569
f7e6390
5aa696c
dfb1712
f0dc4e9
4220892
58037c3
c5dd0e5
b527229
6612b8b
9f2d327
9269d96
8fe9235
15a1610
6024db8
01b6672
39b93d8
e170fa5
78cb847
6bf2ef6
1ee30f1
d5efc32
26b0f0e
2f4fc64
4dfd64b
c76eb27
4033e52
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| from __future__ import division | ||
|
|
||
| import numpy as np | ||
| import random | ||
|
|
||
| from chainercv.transforms.image.random_sized_crop import random_sized_crop | ||
|
|
||
|
|
||
| def random_erasing(img, prob=0.5, | ||
| scale_ratio_range=(0.02, 0.4), | ||
| aspect_ratio_range=(0.3, 1 / 0.3), | ||
| random_value=True, | ||
| scale=1.0, | ||
| fixed_value=np.array((0.4914, 0.4822, 0.4465)), | ||
| return_param=False, copy=False): | ||
| """Erase a rectangle region in an image with random or fixed values. | ||
|
|
||
| The size :math:`(H_{erase}, W_{erase})` and the left top coordinate | ||
| :math:`(y_{start}, x_{start})` of the region are calculated as follows: | ||
|
|
||
| + :math:`H_{erase} = \\lfloor{\\sqrt{s \\times H \\times W \ | ||
| \\times a}}\\rfloor` | ||
| + :math:`W_{erase} = \\lfloor{\\sqrt{s \\times H \\times W \ | ||
| \\div a}}\\rfloor` | ||
| + :math:`y_{start} \\sim Uniform\\{0, H - H_{erase}\\}` | ||
| + :math:`x_{start} \\sim Uniform\\{0, W - W_{erase}\\}` | ||
| + :math:`s \\sim Uniform(s_1, s_2)` | ||
| + :math:`b \\sim Uniform(a_1, a_2)` and \ | ||
| :math:`a = b` or :math:`a = \\frac{1}{b}` in 50/50 probability. | ||
|
|
||
| Here, :math:`s_1, s_2` are the two floats in | ||
| :obj:`scale_ratio_range` and :math:`a_1, a_2` are the two floats | ||
| in :obj:`aspect_ratio_range`. | ||
| Also, :math:`H` and :math:`W` are the height and the width of the image. | ||
| Note that :math:`s \\approx \\frac{H_{erase} \\times | ||
| W_{erase}}{H \\times W}` and | ||
| :math:`a \\approx \\frac{H_{erase}}{W_{erase}}`. | ||
| The approximations come from flooring floats to integers. | ||
|
|
||
| .. note:: | ||
|
|
||
| When it fails to sample a valid scale and aspect ratio for a hundred | ||
| times, it picks values in a non-uniform way. | ||
| If this happens, the selected scale ratio can be smaller | ||
| than :obj:`scale_ratio_range[0]`. | ||
|
|
||
| Args: | ||
| img (~numpy.ndarray): An image array. This is in CHW format. | ||
| prob (float): Erasing probability. | ||
| scale_ratio_range (tuple of two floats): Determines | ||
| the distribution from which a scale ratio is sampled. | ||
| aspect_ratio_range (tuple of two floats): Determines | ||
| the distribution from which an aspect ratio is sampled. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| random_value (bool): Fill the rectangle region with random values. | ||
| scale (float): Pixel value scale. | ||
| fixed_value (~numpy.ndarray): Determines pixel values | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the consistency with other functions, how about using
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about using random value when
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changing from
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to specify the range of random value? The range of pixel is always
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understood the situation. I'll fix the point. The difference seems inconvenient when using Chainer and ChainerCV at the same time.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This is not true. Chainer sometimes uses
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mismatch of the pixel range in Chainer seems awkward. |
||
| to fill the rectangle region. | ||
| The default value is the ImageNet mean value. | ||
| return_param (bool): Returns parameters if :obj:`True`. | ||
|
|
||
| Returns: | ||
| ~numpy.ndarray or (~numpy.ndarray, dict): | ||
|
|
||
| If :obj:`return_param = False`, | ||
| returns only the cropped image. | ||
|
|
||
| If :obj:`return_param = True`, | ||
| returns a tuple of erased image and :obj:`param`. | ||
| :obj:`param` is a dictionary of intermediate parameters whose | ||
| contents are listed below with key, value-type and the description | ||
| of the value. | ||
|
|
||
| * **y_slice** (*slice*): A slice used to erase a region in the input | ||
| image. The relation below holds together with :obj:`x_slice`. | ||
| * **x_slice** (*slice*): Similar to :obj:`y_slice`. | ||
| * **scale_ratio** (float): :math:`s` in the description (see above). | ||
| * **aspect_ratio** (float): :math:`a` in the description. | ||
|
|
||
| """ | ||
| if random.uniform(0.0, 1.0) > prob: | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| crop, params = random_sized_crop(img, scale_ratio_range, | ||
| aspect_ratio_range, return_param=True) | ||
| if random_value: | ||
| crop[:] = np.random.random(crop.shape) * scale | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This line modifies the input image. |
||
| else: | ||
| crop[:] = fixed_value[:, None, None] | ||
| y_slice = params['y_slice'] | ||
| x_slice = params['x_slice'] | ||
| scale_ratio = params['scale_ratio'] | ||
| aspect_ratio = params['aspect_ratio'] | ||
|
|
||
| else: | ||
| y_slice = None | ||
| x_slice = None | ||
| scale_ratio = None | ||
| aspect_ratio = None | ||
|
|
||
| if copy: | ||
| img = img.copy() | ||
| if return_param: | ||
| params = {'y_slice': y_slice, 'x_slice': x_slice, | ||
| 'scale_ratio': scale_ratio, 'aspect_ratio': aspect_ratio} | ||
| return img, params | ||
| else: | ||
| return img | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| from __future__ import division | ||
|
|
||
| import unittest | ||
|
|
||
| import numpy as np | ||
|
|
||
| from chainer import testing | ||
| from chainercv.transforms import random_erasing | ||
|
|
||
|
|
||
| @testing.parameterize(*testing.product_dict( | ||
| [ | ||
| {'H': 256, 'W': 256}, | ||
| {'H': 129, 'W': 352}, | ||
| {'H': 352, 'W': 129}, | ||
| {'H': 35, 'W': 500}, | ||
| ], | ||
| [ | ||
| {'prob': 0.0}, | ||
| {'prob': 0.5}, | ||
| {'prob': 1.0}, | ||
| ], | ||
| [ | ||
| {'random_value': True}, | ||
| {'random_value': False}, | ||
| ] | ||
| )) | ||
| class TestRandomErasing(unittest.TestCase): | ||
|
|
||
| def test_random_sized_crop(self): | ||
| img = np.random.uniform(size=(3, self.H, self.W)) | ||
| prob = self.prob | ||
| scale_ratio_range = (0.02, 0.4) | ||
| aspect_ratio_range = (0.3, 1 / 0.3) | ||
| scale = 1.0 | ||
| fixed_value = np.array((0.4914, 0.4822, 0.4465)) | ||
| out, params = random_erasing(img, prob, scale_ratio_range, | ||
| aspect_ratio_range, self.random_value, | ||
| scale, fixed_value, | ||
| return_param=True) | ||
|
|
||
| scale_ratio = params['scale_ratio'] | ||
| aspect_ratio = params['aspect_ratio'] | ||
|
|
||
| if scale_ratio is not None: | ||
| self.assertTrue( | ||
| (aspect_ratio_range[0] <= aspect_ratio) and | ||
| (aspect_ratio <= aspect_ratio_range[1])) | ||
| self.assertTrue( | ||
| scale_ratio <= scale_ratio_range[1]) | ||
| scale_ratio_max = min((scale_ratio_range[1], | ||
| self.H / (self.W * aspect_ratio), | ||
| (aspect_ratio * self.W) / self.H)) | ||
| self.assertTrue( | ||
| min((scale_ratio_max, scale_ratio_range[0])) <= scale_ratio) | ||
|
|
||
|
|
||
| testing.run_module(__name__, __file__) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be 255 since we use
[0, 255]as the default range of images.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can remove this option.