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:
+
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 Image |
+Augmented Image |
+Input 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"
|