diff --git a/README.md b/README.md index 366debd..f7c7548 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,32 @@ the contents of the repository folder: + +CoarseDropout +
+Randomly erases a percentage of the given image using squares. + + + + + + + + + + + + + + + + + + + + + + ColorTemperature
diff --git a/doc/discolight.md b/doc/discolight.md index 926e7ce..8ec9114 100644 --- a/doc/discolight.md +++ b/doc/discolight.md @@ -151,6 +151,62 @@ the directory to save images to # Augmentations +## CoarseDropout + +Randomly erases a percentage of the given image using squares\. + +### Example + + + + + + + + + + + + + + + + + +
Input ImageAugmented ImageInput Image
(with Bounding Boxes)
Augmented Image
(with Bounding Boxes)
+ + + + + + + +
+ +### Parameters + + +**deleted\_area** *(float)* = 0\.1
+The percentage of image that will be dropped + + + +**num\_rectangles** *(int)* = 25
+The number of rectangles that will be dropped + + + +**probs** *(float in range \[0\.0, 1\.0\])* = 1\.0
+The probability that this augmentation will be applied + + + + + + + + + ## ColorTemperature Changes the color temperature of the input image\. diff --git a/doc/images/CoarseDropout-bboxes.jpg b/doc/images/CoarseDropout-bboxes.jpg new file mode 100644 index 0000000..548d99b Binary files /dev/null and b/doc/images/CoarseDropout-bboxes.jpg differ diff --git a/doc/images/CoarseDropout-input-bboxes.jpg b/doc/images/CoarseDropout-input-bboxes.jpg new file mode 100644 index 0000000..199e437 Binary files /dev/null and b/doc/images/CoarseDropout-input-bboxes.jpg differ diff --git a/doc/images/CoarseDropout-input.jpg b/doc/images/CoarseDropout-input.jpg new file mode 100644 index 0000000..dbd30ce Binary files /dev/null and b/doc/images/CoarseDropout-input.jpg differ diff --git a/doc/images/CoarseDropout.jpg b/doc/images/CoarseDropout.jpg new file mode 100644 index 0000000..90680cb Binary files /dev/null and b/doc/images/CoarseDropout.jpg differ diff --git a/snapshots/augmentations/CoarseDropout-bboxes b/snapshots/augmentations/CoarseDropout-bboxes new file mode 100644 index 0000000..0fded4a --- /dev/null +++ b/snapshots/augmentations/CoarseDropout-bboxes @@ -0,0 +1,42 @@ +image_name,x_min,y_min,x_max,y_max,label +CoarseDropout-image.jpg,0.0,0.799805,0.037109,0.94043,1 +CoarseDropout-image.jpg,0.064453,0.892578,0.181641,0.949219,1 +CoarseDropout-image.jpg,0.050781,0.513672,0.123047,0.629883,1 +CoarseDropout-image.jpg,0.039062,0.033203,0.169922,0.149414,1 +CoarseDropout-image.jpg,0.073242,0.144531,0.211914,0.232422,1 +CoarseDropout-image.jpg,0.186523,0.178711,0.324219,0.237305,1 +CoarseDropout-image.jpg,0.163086,0.0,0.238281,0.087891,1 +CoarseDropout-image.jpg,0.207031,0.0,0.255859,0.039062,1 +CoarseDropout-image.jpg,0.505859,0.011719,0.598633,0.079102,1 +CoarseDropout-image.jpg,0.383789,0.011719,0.503906,0.121094,1 +CoarseDropout-image.jpg,0.386719,0.207031,0.44043,0.277344,1 +CoarseDropout-image.jpg,0.44043,0.272461,0.536133,0.337891,1 +CoarseDropout-image.jpg,0.755859,0.142578,0.87207,0.239258,1 +CoarseDropout-image.jpg,0.705078,0.079102,0.779297,0.140625,1 +CoarseDropout-image.jpg,0.917969,0.0,0.99707,0.072266,1 +CoarseDropout-image.jpg,0.525391,0.37793,0.601562,0.456055,1 +CoarseDropout-image.jpg,0.630859,0.357422,0.722656,0.506836,1 +CoarseDropout-image.jpg,0.730469,0.371094,0.789062,0.448242,1 +CoarseDropout-image.jpg,0.901367,0.248047,0.978516,0.339844,1 +CoarseDropout-image.jpg,0.87793,0.554688,0.977539,0.625977,1 +CoarseDropout-image.jpg,0.069336,0.427734,0.170898,0.506836,1 +CoarseDropout-image.jpg,0.112305,0.327148,0.229492,0.394531,1 +CoarseDropout-image.jpg,0.25,0.469727,0.325195,0.555664,1 +CoarseDropout-image.jpg,0.265625,0.549805,0.324219,0.649414,1 +CoarseDropout-image.jpg,0.177734,0.625977,0.24707,0.78418,1 +CoarseDropout-image.jpg,0.213867,0.617188,0.318359,0.783203,1 +CoarseDropout-image.jpg,0.338867,0.623047,0.417969,0.737305,1 +CoarseDropout-image.jpg,0.452148,0.583984,0.533203,0.693359,1 +CoarseDropout-image.jpg,0.405273,0.404297,0.507812,0.549805,1 +CoarseDropout-image.jpg,0.571289,0.514648,0.625977,0.624023,1 +CoarseDropout-image.jpg,0.642578,0.49707,0.714844,0.604492,1 +CoarseDropout-image.jpg,0.640625,0.629883,0.805664,0.744141,1 +CoarseDropout-image.jpg,0.845703,0.688477,0.922852,0.963867,1 +CoarseDropout-image.jpg,0.743164,0.728516,0.833984,0.967773,1 +CoarseDropout-image.jpg,0.447266,0.878906,0.499023,0.93457,1 +CoarseDropout-image.jpg,0.297852,0.889648,0.371094,0.977539,1 +CoarseDropout-image.jpg,0.005859,0.825195,0.083984,0.882812,1 +CoarseDropout-image.jpg,0.427734,0.478516,0.53418,0.547852,1 +CoarseDropout-image.jpg,0.422852,0.647461,0.49707,0.711914,1 +CoarseDropout-image.jpg,0.461914,0.570312,0.611328,0.772461,1 +CoarseDropout-image.jpg,0.196289,0.777344,0.291992,0.966797,1 diff --git a/snapshots/augmentations/CoarseDropout-bboxes.npy b/snapshots/augmentations/CoarseDropout-bboxes.npy new file mode 100644 index 0000000..1858752 Binary files /dev/null and b/snapshots/augmentations/CoarseDropout-bboxes.npy differ diff --git a/snapshots/augmentations/CoarseDropout-image.jpg b/snapshots/augmentations/CoarseDropout-image.jpg new file mode 100644 index 0000000..fdcd4bd Binary files /dev/null and b/snapshots/augmentations/CoarseDropout-image.jpg differ diff --git a/src/discolight/augmentations/coarsedropout.py b/src/discolight/augmentations/coarsedropout.py new file mode 100644 index 0000000..c27fe5e --- /dev/null +++ b/src/discolight/augmentations/coarsedropout.py @@ -0,0 +1,61 @@ +"""A CoarseDropout augmentation.""" +import random +import math +from discolight.params.params import Params +from .augmentation.types import ColorAugmentation +from .decorators.accepts_probs import accepts_probs + + +@accepts_probs +class CoarseDropout(ColorAugmentation): + + """Randomly erases a percentage of the given image using squares.""" + + def __init__(self, deleted_area, num_rectangles): + """Construct a CoarseDropout augmenation. + + You should probably use the augmentation factory or Discolight + library interface to construct augmentations. Only invoke + this constructor directly if you know what you are doing. + """ + super().__init__() + self.deleted_area = deleted_area + self.num_rectangles = num_rectangles + + @staticmethod + def params(): + """Return a Params object describing constructor parameters.""" + return Params().add("deleted_area", "", float, + 0.1).add("num_rectangles", "", int, + 25) + + def augment_img(self, img, bboxes): + """Augment an image.""" + width, height = img.shape[1], img.shape[0] + self.deleted_area = self.deleted_area \ + if self.deleted_area <= 1 and self.deleted_area >= 0 \ + else random.uniform( + 0, 1) + self.num_rectangles = self.num_rectangles \ + if self.num_rectangles >= 10 and self.num_rectangles <= 100 \ + else random.uniform( + 10, 100) + + eraser_area = width * height * self.deleted_area + eraser_rectangle = int( + eraser_area / self.num_rectangles) + + # here must be int, because if not img[eraser_width etc] + # does not take in float or decimals. + eraser_width = int(math.sqrt(eraser_rectangle)) + eraser_height = int(eraser_rectangle / eraser_width) + + # Iterate and Apply Eraser + for _ in range(1, self.num_rectangles): + x = int(random.uniform(0, width - eraser_width)) + y = int(random.uniform(0, height - eraser_height)) + + for row_idx in range(y, y + eraser_height): + for col_idx in range(x, x + eraser_width): + img[row_idx, col_idx] = [0, 0, 0] + return img diff --git a/tests/augmentations/test_coarsedropout.py b/tests/augmentations/test_coarsedropout.py new file mode 100644 index 0000000..8c3c46e --- /dev/null +++ b/tests/augmentations/test_coarsedropout.py @@ -0,0 +1,35 @@ +import pytest +import numpy as np + +from discolight.annotations import (annotations_to_numpy_array) +from discolight.augmentations.coarsedropout import CoarseDropout + + +@pytest.mark.usefixtures("sample_image") +def test_coarsedropout(sample_image): + + img, annotations = sample_image + + bboxes = annotations_to_numpy_array(annotations) + + augmentation = CoarseDropout(deleted_area=0.1, num_rectangles=25) + + aug_img, aug_bboxes = augmentation.augment(img.copy(), bboxes.copy()) + + width, height = aug_img.shape[1], aug_img.shape[0] + deleted_area = 0 + for row_idx in range(0, height): + for col_idx in range(0, width): + if np.array_equal(aug_img[row_idx, col_idx], [0, 0, 0]): + deleted_area += 1 + aug_p = deleted_area / (width * height) + margin = 0.02 + print(aug_p) + + assert aug_p <= ( + 0.1 + margin) and aug_p >= ( + 0.1 - margin + ), "Performing augmentation does not yield expected erased area" + assert np.array_equal( + bboxes, aug_bboxes + ), "Performing augmentation does not yield original augmentation"