Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added CoarseDropout Augmentation #14

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,32 @@ the contents of the repository folder:

<tr>

<td style="width: 20%">
<b><a href="doc/discolight.md#CoarseDropout">CoarseDropout</a></b>
<br/>
Randomly erases a percentage of the given image using squares.
</td>

<td style="width: 20%; vertical-align: bottom">
<img src="doc/images/CoarseDropout-input.jpg" width="100px" height="75px" style="display: block; width: 100%"/>
</td>

<td style="width: 20%; vertical-align: bottom">
<img src="doc/images/CoarseDropout.jpg" width="100px" height="75px" style="display: block; width: 100%"/>
</td>

<td style="width: 20%; vertical-align: bottom">
<img src="doc/images/CoarseDropout-input-bboxes.jpg" width="100px" height="75px" style="display: block; width: 100%"/>
</td>

<td style="width: 20%; vertical-align: bottom">
<img src="doc/images/CoarseDropout-bboxes.jpg" width="100px" height="75px" style="display: block; width: 100%"/>
</td>

</tr>

<tr>

<td style="width: 20%">
<b><a href="doc/discolight.md#ColorTemperature">ColorTemperature</a></b>
<br/>
Expand Down
56 changes: 56 additions & 0 deletions doc/discolight.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,62 @@ the directory to save images to
# Augmentations


## CoarseDropout

Randomly erases a percentage of the given image using squares\.

### Example
<table style="width: 100%">
<tr>
<td><b>Input Image</b></td>
<td><b>Augmented Image</b></td>
<td><b>Input Image<br/>(with Bounding Boxes)</b></td>
<td><b>Augmented Image<br/>(with Bounding Boxes)</b></td>
</tr>
<tr>
<td style="vertical-align: bottom">
<img src="images/CoarseDropout-input.jpg" width="235px" height="176px" style="display: block; width: 100%"/>
</td>

<td style="vertical-align: bottom">
<img src="images/CoarseDropout.jpg" width="235px" height="176px" style="display: block; width: 100%"/>
</td>

<td style="vertical-align: bottom">
<img src="images/CoarseDropout-input-bboxes.jpg" width="235px" height="176px" style="display: block; width: 100%"/>
</td>

<td style="vertical-align: bottom">
<img src="images/CoarseDropout-bboxes.jpg" width="235px" height="176px" style="display: block; width: 100%"/>
</td>

</tr>
</table>

### Parameters


**deleted\_area** *(float)* = 0\.1<br/>
The percentage of image that will be dropped



**num\_rectangles** *(int)* = 25<br/>
The number of rectangles that will be dropped



**probs** *(float in range \[0\.0, 1\.0\])* = 1\.0<br/>
The probability that this augmentation will be applied









## ColorTemperature

Changes the color temperature of the input image\.
Expand Down
Binary file added doc/images/CoarseDropout-bboxes.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/CoarseDropout-input-bboxes.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/CoarseDropout-input.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/CoarseDropout.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions snapshots/augmentations/CoarseDropout-bboxes
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
image_name,x_min,y_min,x_max,y_max,label
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please untrack this file. It has been superseded by CoarseDropout-bboxes.npy.

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
Binary file added snapshots/augmentations/CoarseDropout-bboxes.npy
Binary file not shown.
Binary file added snapshots/augmentations/CoarseDropout-image.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions src/discolight/augmentations/coarsedropout.py
Original file line number Diff line number Diff line change
@@ -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,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should probably have type BoundedNumber, since you are enforcing some bounds in your augment_img function.

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 \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to randomly select deleted_area only if the initial value is 0, and have deleted_area take the type BoundedNumber(float, minimum=0).

Additionally, I think it's better to perform the entire initialization process in __init__ rather than in augment_img. The way you have written it self.deleted_area will only be randomly initialized at most once (because after a value is picked it will be between 0 and 1). This is a fine choice, but to make it more clear that this is your intent the initialization should be done in the constructor.

else random.uniform(
0, 1)
self.num_rectangles = self.num_rectangles \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comments as for the deleted_area parameter. In addition, is there a reason for not wanting num_rectangles to be less than 10?

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
35 changes: 35 additions & 0 deletions tests/augmentations/test_coarsedropout.py
Original file line number Diff line number Diff line change
@@ -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 <= (
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to consider using the built-in function math.isclose instead: https://docs.python.org/dev/library/math.html#math.isclose.

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"