File size: 14,219 Bytes
0034848
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
try:
    import imgaug as ia
except ImportError as e:
    raise ImportError(
        "You are trying to import an augmentation that depends on the imgaug library, but imgaug is not installed. To "
        "install a version of Albumentations that contains imgaug please run 'pip install -U albumentations[imgaug]'"
    ) from e

try:
    from imgaug import augmenters as iaa
except ImportError:
    import imgaug.imgaug.augmenters as iaa

import warnings

from custom_albumentations.core.bbox_utils import (
    convert_bboxes_from_albumentations,
    convert_bboxes_to_albumentations,
)
from custom_albumentations.core.keypoints_utils import (
    convert_keypoints_from_albumentations,
    convert_keypoints_to_albumentations,
)

from ..augmentations import Perspective
from ..core.transforms_interface import (
    BasicTransform,
    DualTransform,
    ImageOnlyTransform,
    to_tuple,
)

__all__ = [
    "BasicIAATransform",
    "DualIAATransform",
    "ImageOnlyIAATransform",
    "IAAEmboss",
    "IAASuperpixels",
    "IAASharpen",
    "IAAAdditiveGaussianNoise",
    "IAACropAndPad",
    "IAAFliplr",
    "IAAFlipud",
    "IAAAffine",
    "IAAPiecewiseAffine",
    "IAAPerspective",
]


class BasicIAATransform(BasicTransform):
    def __init__(self, always_apply=False, p=0.5):
        super(BasicIAATransform, self).__init__(always_apply, p)

    @property
    def processor(self):
        return iaa.Noop()

    def update_params(self, params, **kwargs):
        params = super(BasicIAATransform, self).update_params(params, **kwargs)
        params["deterministic_processor"] = self.processor.to_deterministic()
        return params

    def apply(self, img, deterministic_processor=None, **params):
        return deterministic_processor.augment_image(img)


class DualIAATransform(DualTransform, BasicIAATransform):
    def apply_to_bboxes(self, bboxes, deterministic_processor=None, rows=0, cols=0, **params):
        if len(bboxes) > 0:
            bboxes = convert_bboxes_from_albumentations(bboxes, "pascal_voc", rows=rows, cols=cols)

            bboxes_t = ia.BoundingBoxesOnImage([ia.BoundingBox(*bbox[:4]) for bbox in bboxes], (rows, cols))
            bboxes_t = deterministic_processor.augment_bounding_boxes([bboxes_t])[0].bounding_boxes
            bboxes_t = [
                [bbox.x1, bbox.y1, bbox.x2, bbox.y2] + list(bbox_orig[4:])
                for (bbox, bbox_orig) in zip(bboxes_t, bboxes)
            ]

            bboxes = convert_bboxes_to_albumentations(bboxes_t, "pascal_voc", rows=rows, cols=cols)
        return bboxes

    """Applies transformation to keypoints.
    Notes:
        Since IAA supports only xy keypoints, scale and orientation will remain unchanged.
    TODO:
        Emit a warning message if child classes of DualIAATransform are instantiated
        inside Compose with keypoints format other than 'xy'.
    """

    def apply_to_keypoints(self, keypoints, deterministic_processor=None, rows=0, cols=0, **params):
        if len(keypoints) > 0:
            keypoints = convert_keypoints_from_albumentations(keypoints, "xy", rows=rows, cols=cols)
            keypoints_t = ia.KeypointsOnImage([ia.Keypoint(*kp[:2]) for kp in keypoints], (rows, cols))
            keypoints_t = deterministic_processor.augment_keypoints([keypoints_t])[0].keypoints

            bboxes_t = [[kp.x, kp.y] + list(kp_orig[2:]) for (kp, kp_orig) in zip(keypoints_t, keypoints)]

            keypoints = convert_keypoints_to_albumentations(bboxes_t, "xy", rows=rows, cols=cols)
        return keypoints


class ImageOnlyIAATransform(ImageOnlyTransform, BasicIAATransform):
    pass


class IAACropAndPad(DualIAATransform):
    """This augmentation is deprecated. Please use CropAndPad instead."""

    def __init__(self, px=None, percent=None, pad_mode="constant", pad_cval=0, keep_size=True, always_apply=False, p=1):
        super(IAACropAndPad, self).__init__(always_apply, p)
        self.px = px
        self.percent = percent
        self.pad_mode = pad_mode
        self.pad_cval = pad_cval
        self.keep_size = keep_size
        warnings.warn("IAACropAndPad is deprecated. Please use CropAndPad instead", FutureWarning)

    @property
    def processor(self):
        return iaa.CropAndPad(self.px, self.percent, self.pad_mode, self.pad_cval, self.keep_size)

    def get_transform_init_args_names(self):
        return ("px", "percent", "pad_mode", "pad_cval", "keep_size")


class IAAFliplr(DualIAATransform):
    """This augmentation is deprecated. Please use HorizontalFlip instead."""

    def __init__(self, always_apply=False, p=0.5):
        super().__init__(always_apply, p)
        warnings.warn("IAAFliplr is deprecated. Please use HorizontalFlip instead.", FutureWarning)

    @property
    def processor(self):
        return iaa.Fliplr(1)

    def get_transform_init_args_names(self):
        return ()


class IAAFlipud(DualIAATransform):
    """This augmentation is deprecated. Please use VerticalFlip instead."""

    def __init__(self, always_apply=False, p=0.5):
        super().__init__(always_apply, p)
        warnings.warn("IAAFlipud is deprecated. Please use VerticalFlip instead.", FutureWarning)

    @property
    def processor(self):
        return iaa.Flipud(1)

    def get_transform_init_args_names(self):
        return ()


class IAAEmboss(ImageOnlyIAATransform):
    """Emboss the input image and overlays the result with the original image.
    This augmentation is deprecated. Please use Emboss instead.

    Args:
        alpha ((float, float)): range to choose the visibility of the embossed image. At 0, only the original image is
            visible,at 1.0 only its embossed version is visible. Default: (0.2, 0.5).
        strength ((float, float)): strength range of the embossing. Default: (0.2, 0.7).
        p (float): probability of applying the transform. Default: 0.5.

    Targets:
        image
    """

    def __init__(self, alpha=(0.2, 0.5), strength=(0.2, 0.7), always_apply=False, p=0.5):
        super(IAAEmboss, self).__init__(always_apply, p)
        self.alpha = to_tuple(alpha, 0.0)
        self.strength = to_tuple(strength, 0.0)
        warnings.warn("This augmentation is deprecated. Please use Emboss instead", FutureWarning)

    @property
    def processor(self):
        return iaa.Emboss(self.alpha, self.strength)

    def get_transform_init_args_names(self):
        return ("alpha", "strength")


class IAASuperpixels(ImageOnlyIAATransform):
    """Completely or partially transform the input image to its superpixel representation. Uses skimage's version
    of the SLIC algorithm. May be slow.

    This augmentation is deprecated. Please use Superpixels instead.

    Args:
        p_replace (float): defines the probability of any superpixel area being replaced by the superpixel, i.e. by
            the average pixel color within its area. Default: 0.1.
        n_segments (int): target number of superpixels to generate. Default: 100.
        p (float): probability of applying the transform. Default: 0.5.

    Targets:
        image
    """

    def __init__(self, p_replace=0.1, n_segments=100, always_apply=False, p=0.5):
        super(IAASuperpixels, self).__init__(always_apply, p)
        self.p_replace = p_replace
        self.n_segments = n_segments
        warnings.warn("IAASuperpixels is deprecated. Please use Superpixels instead.", FutureWarning)

    @property
    def processor(self):
        return iaa.Superpixels(p_replace=self.p_replace, n_segments=self.n_segments)

    def get_transform_init_args_names(self):
        return ("p_replace", "n_segments")


class IAASharpen(ImageOnlyIAATransform):
    """Sharpen the input image and overlays the result with the original image.
    This augmentation is deprecated. Please use Sharpen instead
    Args:
        alpha ((float, float)): range to choose the visibility of the sharpened image. At 0, only the original image is
            visible, at 1.0 only its sharpened version is visible. Default: (0.2, 0.5).
        lightness ((float, float)): range to choose the lightness of the sharpened image. Default: (0.5, 1.0).
        p (float): probability of applying the transform. Default: 0.5.

    Targets:
        image
    """

    def __init__(self, alpha=(0.2, 0.5), lightness=(0.5, 1.0), always_apply=False, p=0.5):
        super(IAASharpen, self).__init__(always_apply, p)
        self.alpha = to_tuple(alpha, 0)
        self.lightness = to_tuple(lightness, 0)
        warnings.warn("IAASharpen is deprecated. Please use Sharpen instead", FutureWarning)

    @property
    def processor(self):
        return iaa.Sharpen(self.alpha, self.lightness)

    def get_transform_init_args_names(self):
        return ("alpha", "lightness")


class IAAAdditiveGaussianNoise(ImageOnlyIAATransform):
    """Add gaussian noise to the input image.

    This augmentation is deprecated. Please use GaussNoise instead.

    Args:
        loc (int): mean of the normal distribution that generates the noise. Default: 0.
        scale ((float, float)): standard deviation of the normal distribution that generates the noise.
            Default: (0.01 * 255, 0.05 * 255).
        p (float): probability of applying the transform. Default: 0.5.

    Targets:
        image
    """

    def __init__(self, loc=0, scale=(0.01 * 255, 0.05 * 255), per_channel=False, always_apply=False, p=0.5):
        super(IAAAdditiveGaussianNoise, self).__init__(always_apply, p)
        self.loc = loc
        self.scale = to_tuple(scale, 0.0)
        self.per_channel = per_channel
        warnings.warn("IAAAdditiveGaussianNoise is deprecated. Please use GaussNoise instead", FutureWarning)

    @property
    def processor(self):
        return iaa.AdditiveGaussianNoise(self.loc, self.scale, self.per_channel)

    def get_transform_init_args_names(self):
        return ("loc", "scale", "per_channel")


class IAAPiecewiseAffine(DualIAATransform):
    """Place a regular grid of points on the input and randomly move the neighbourhood of these point around
    via affine transformations.

    This augmentation is deprecated. Please use PiecewiseAffine instead.

    Note: This class introduce interpolation artifacts to mask if it has values other than {0;1}

    Args:
        scale ((float, float): factor range that determines how far each point is moved. Default: (0.03, 0.05).
        nb_rows (int): number of rows of points that the regular grid should have. Default: 4.
        nb_cols (int): number of columns of points that the regular grid should have. Default: 4.
        p (float): probability of applying the transform. Default: 0.5.

    Targets:
        image, mask
    """

    def __init__(
        self, scale=(0.03, 0.05), nb_rows=4, nb_cols=4, order=1, cval=0, mode="constant", always_apply=False, p=0.5
    ):
        super(IAAPiecewiseAffine, self).__init__(always_apply, p)
        self.scale = to_tuple(scale, 0.0)
        self.nb_rows = nb_rows
        self.nb_cols = nb_cols
        self.order = order
        self.cval = cval
        self.mode = mode
        warnings.warn("This IAAPiecewiseAffine is deprecated. Please use PiecewiseAffine instead", FutureWarning)

    @property
    def processor(self):
        return iaa.PiecewiseAffine(self.scale, self.nb_rows, self.nb_cols, self.order, self.cval, self.mode)

    def get_transform_init_args_names(self):
        return ("scale", "nb_rows", "nb_cols", "order", "cval", "mode")


class IAAAffine(DualIAATransform):
    """Place a regular grid of points on the input and randomly move the neighbourhood of these point around
    via affine transformations.

    This augmentation is deprecated. Please use Affine instead.

    Note: This class introduce interpolation artifacts to mask if it has values other than {0;1}

    Args:
        p (float): probability of applying the transform. Default: 0.5.

    Targets:
        image, mask
    """

    def __init__(
        self,
        scale=1.0,
        translate_percent=None,
        translate_px=None,
        rotate=0.0,
        shear=0.0,
        order=1,
        cval=0,
        mode="reflect",
        always_apply=False,
        p=0.5,
    ):
        super(IAAAffine, self).__init__(always_apply, p)
        self.scale = to_tuple(scale, 1.0)
        self.translate_percent = to_tuple(translate_percent, 0)
        self.translate_px = to_tuple(translate_px, 0)
        self.rotate = to_tuple(rotate)
        self.shear = to_tuple(shear)
        self.order = order
        self.cval = cval
        self.mode = mode
        warnings.warn("This IAAAffine is deprecated. Please use Affine instead", FutureWarning)

    @property
    def processor(self):
        return iaa.Affine(
            self.scale,
            self.translate_percent,
            self.translate_px,
            self.rotate,
            self.shear,
            self.order,
            self.cval,
            self.mode,
        )

    def get_transform_init_args_names(self):
        return ("scale", "translate_percent", "translate_px", "rotate", "shear", "order", "cval", "mode")


class IAAPerspective(Perspective):
    """Perform a random four point perspective transform of the input.
    This augmentation is deprecated. Please use Perspective instead.

    Note: This class introduce interpolation artifacts to mask if it has values other than {0;1}

    Args:
        scale ((float, float): standard deviation of the normal distributions. These are used to sample
            the random distances of the subimage's corners from the full image's corners. Default: (0.05, 0.1).
        p (float): probability of applying the transform. Default: 0.5.

    Targets:
        image, mask
    """

    def __init__(self, scale=(0.05, 0.1), keep_size=True, always_apply=False, p=0.5):
        super(IAAPerspective, self).__init__(always_apply, p)
        self.scale = to_tuple(scale, 1.0)
        self.keep_size = keep_size
        warnings.warn("This IAAPerspective is deprecated. Please use Perspective instead", FutureWarning)

    @property
    def processor(self):
        return iaa.PerspectiveTransform(self.scale, keep_size=self.keep_size)

    def get_transform_init_args_names(self):
        return ("scale", "keep_size")