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

feat: Added random noise augmentation to object detection #654

Merged
merged 30 commits into from
Dec 29, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
327c244
chore: Added rotations as augmentations
SiddhantBahuguna Nov 24, 2021
77402de
chore: Added miinor augmentations
SiddhantBahuguna Nov 29, 2021
d82786f
fix: Added the height, width of the image for random-horizontal/verti…
SiddhantBahuguna Nov 29, 2021
1ee4810
Merge branch 'main' into minor_aug
SiddhantBahuguna Nov 29, 2021
41b9dd8
chore: added rotations
SiddhantBahuguna Dec 2, 2021
1c71c3c
Merge branch 'main' into minor_aug
SiddhantBahuguna Dec 2, 2021
e8e3791
feat: Added shadows as augmentations
SiddhantBahuguna Dec 7, 2021
e513c04
feat: Added shadows as augmentations
SiddhantBahuguna Dec 7, 2021
349ea72
chore: Used numpy for random bool response
SiddhantBahuguna Dec 7, 2021
d3e537b
fix: FIxed the conflicts with the main
SiddhantBahuguna Dec 17, 2021
fad5b7b
fix: Merged main with this PR fixing timeouts in CI
SiddhantBahuguna Dec 18, 2021
2617e27
feat: Removed geometric augmentations.
SiddhantBahuguna Dec 20, 2021
76cffad
chore: Added photometric augmentation in dataloader
SiddhantBahuguna Dec 23, 2021
49a2a56
fix: Fixed .gitignore
SiddhantBahuguna Dec 23, 2021
2581ca8
chore: Merged main with the current branch
SiddhantBahuguna Dec 23, 2021
287ee76
chore: Removed unnecessary functions related to photometric augmentat…
SiddhantBahuguna Dec 23, 2021
7507cd5
chore: Reverted last commit
SiddhantBahuguna Dec 23, 2021
d4985ab
feat: Removed shadows and added randomgaussian noise
SiddhantBahuguna Dec 24, 2021
2492ab5
chore: Merged main with the PR
SiddhantBahuguna Dec 27, 2021
db8fe38
fix: Fixed style
SiddhantBahuguna Dec 27, 2021
ecff1c8
fix: Fixed the distribution range
SiddhantBahuguna Dec 28, 2021
ad9cf4a
test: Added unittest for GaussianNoise
SiddhantBahuguna Dec 28, 2021
6161e25
fix: Reverted to original script
SiddhantBahuguna Dec 28, 2021
bacbfb5
fix: Reverted to old train script
SiddhantBahuguna Dec 28, 2021
89d5be2
chore: Merged main with the PR
SiddhantBahuguna Dec 29, 2021
5f21008
Merge branch 'main' into minor_aug
SiddhantBahuguna Dec 29, 2021
55d984a
fix: Updated the new checkpoint path
SiddhantBahuguna Dec 29, 2021
76adc41
chore: Merged with main
SiddhantBahuguna Dec 29, 2021
2f260ae
fix: Fixed typo
SiddhantBahuguna Dec 29, 2021
94535b1
style: Fixed brackets indentation
SiddhantBahuguna Dec 29, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 36 additions & 0 deletions references/obj_detection/channels.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import cv2


# interesting channels: B G R V L
def get_bgr_channels(image):
if is_monochannel(image):
image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)

return cv2.split(image)


def get_gray_image(image):
if is_monochannel(image):
return image

return cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)


def get_hls_channels(image):
if is_monochannel(image):
image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)

image = cv2.cvtColor(image, cv2.COLOR_BGR2HLS)
return cv2.split(image)


def get_hsv_channels(image):
if is_monochannel(image):
image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)

image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
return cv2.split(image)


def is_monochannel(image):
return len(image.shape) < 3
151 changes: 151 additions & 0 deletions references/obj_detection/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import random
SiddhantBahuguna marked this conversation as resolved.
Show resolved Hide resolved

from enum import Enum

N_FILES_OUTPUT = 100

# allowed input images extensions
IMAGE_EXTENSIONS = [".jpg",
".jpeg",
".png",
".bmp",
".jp2",
".dib",
".webp",
".sr",
".ras",
".tiff",
".tif",
".pbm",
".pgm",
".ppm",
]

# default input files path
FILES_INPUT_PATH = "./input/"

# default output files path
FILES_OUTPUT_PATH = "./output/"

'''
max number of transformations
that are randomly applied for each output image.
If N_TRANSFORMATIONS > total number of transformations
specified in the MaxTransformation field
N_TRANSFORMATIONS will be reset as sum_MaxTransformation_fields
'''
N_TRANSFORMATIONS = 3

'''
MaxTransformation contains, for each transformation,
the maximum number of times that each transformation is performed.
Useful to apply some transformations more often ( n > 1 )
or to exclude them` altogether ( n = 0 )
'''


class MaxTransformation:
SALT_PEPPER_NOISE = 1
SPECKLE_NOISE = 1
GAUSS_NOISE = 1
BLUR = 1

SHADOW = 1
ENHANCEMENTS = 1
SHADE_COLOR = 1

# The following transformations
# will alter pixel coordinates
SHEAR = 1
SKEW = 1
WARP = 1
ROTATION = 1


# MIN/MAX AVG BLURRING
MIN_BLUR = 1
MAX_BLUR = 3

# MIN/MAX GAUSS NOISE
MIN_GAUSS_NOISE = 1
MAX_GAUSS_NOISE = 100

# MIN/MAX SALT AND PEPPER NOISE
MIN_SALT_PEPPER_NOISE = 0.0001
MAX_SALTPEPPER_NOISE = 0.001

# MIN/MAX SPECKLE
MIN_SPECKLE_NOISE = 0.01
MAX_SPECKLE_NOISE = 0.3

# MIN/MAX SHADOW
MIN_SHADOW = 0.3
MAX_SHADOW = 0.7

# MIN/MAX IMAGE BRIGHTNESS
MIN_BRIGHTNESS = 0.6
MAX_BRIGHTNESS = 1.4

# MIN/MAX IMAGE CONTRAST
MIN_CONTRAST = 0.5
MAX_CONTRAST = 1.7

# MIN/MAX IMAGE SHARPNESS
MIN_SHARPNESS = 0.1
MAX_SHARPNESS = 5.0

# MIN/MAX COLOR SHADING
MIN_COLOR_SHADE = 0.06
MAX_COLOR_SHADE = 0.35

# MAX SHEAR DISTORTION
MAX_SHEAR = 0.05

# MAX SKEW DISTORTION
MAX_SKEW = 0.05

# MIN/MAX WARP DISTORTION
MIN_WARP = 14
MAX_WARP = 51

# MIN/MAX ROTATION ANGLE
MAX_ANGLE = 0.02

# By default salt&pepper and speckle noise
# is followed by blurring
ADD_BLUR_AFTER_SPECKLE_NOISE = True
ADD_BLUR_AFTER_SP_NOISE = True

READ_IMAGE_AS_GRAYSCALE = False

BLACK = 0
LIGHT_BLACK = 50
DARK_GRAY = 100
GRAY = 150
LIGHT_GRAY = 200
DARK_WHITE = 250
WHITE = 255

SEED = random.random()
# Max integer value for Python 2. Integers in Python 3 are unbounded
MAX_RANDOM = 2147483648


class Enhancement(Enum):
brightness = 0
contrast = 1
sharpness = 2

@staticmethod
def get_random():
return random.choice(list(Enhancement))


class Channels(Enum):
bgr = 0
hsv = 1
hls = 2

@staticmethod
def get_random():
return random.choice(list(Channels))
137 changes: 137 additions & 0 deletions references/obj_detection/noise.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
from random import randint

import cv2
import numpy as np

import constants as const


def add_n_random_blur(image, n=randint(1, 4)):
for i in range(n):
choice = np.random.uniform(0, 4)
if choice < 1:
image = blur(image, randint(1, 3))
elif choice < 2:
image = get_gauss_noise(image, randint(1, 100))
elif choice < 3:
image = get_saltpepper_noise(image, np.random.uniform(0.0001, 0.001))
elif choice < 4:
image = get_speckle_noise(image, np.random.uniform(0.01, 0.3))

return image


def add_random_blur(image):
max_blur = const.MAX_BLUR
max_dimension = max(image.shape)
if max_dimension < 2000 and max_blur > 2:
max_blur -= 1
if max_dimension < 1000 and max_blur > 1:
max_blur -= 1

intensity = randint(const.MIN_BLUR, max_blur)
return blur(image, width=intensity)


def blur(image, width=9):
for i in range(0, width):
size = 2 ** i + 1
image = cv2.blur(image, (size, size))

return image


def get_blur_given_intensity(intensity, blur_scale):
intensity = intensity * blur_scale
if intensity < 0.4:
return 5
elif intensity < 0.5:
return 6
return 7


def add_random_gauss_noise(image):
intensity = randint(const.MIN_GAUSS_NOISE, const.MAX_GAUSS_NOISE)
return get_gauss_noise(image, intensity)


def get_gauss_noise(image, intensity=1):
mean = 0
sigma = intensity ** 0.5

if len(image.shape) > 2:
h, w, ch = image.shape
gauss = np.random.normal(mean, sigma, (h, w, ch))
gauss = gauss.reshape(h, w, ch)

else:
h, w = image.shape
gauss = np.random.normal(mean, sigma, (h, w))
gauss = gauss.reshape(h, w)

gauss = image + gauss
gauss = __get_normalized_image(gauss)
return gauss


def __get_normalized_image(image):
min_matrix = 0 * image
max_matrix = min_matrix + 255
image = np.minimum(image, max_matrix)
image = np.maximum(image, min_matrix)
return image.astype(np.uint8)


def add_random_saltpepper_noise(image):
intensity = np.random.uniform(const.MIN_SALT_PEPPER_NOISE,
const.MAX_SALTPEPPER_NOISE)
return get_saltpepper_noise(image, intensity)


# tip: use it as first transformation, apply other noises afterwards
def get_saltpepper_noise(image, intensity=0.0001, add_blur=const.ADD_BLUR_AFTER_SP_NOISE):
s_vs_p = 0.5
saltpepper = np.copy(image)
num_salt = np.ceil(intensity * image.size * s_vs_p)
coords = __get_coordinates_saltpepper(image, num_salt)
saltpepper[coords] = 255
num_pepper = np.ceil(intensity * image.size * (1. - s_vs_p))
coords = __get_coordinates_saltpepper(image, num_pepper)
saltpepper[coords] = 0

if add_blur:
return blur(saltpepper, width=1)

return saltpepper


def __get_coordinates_saltpepper(image, num_salt):
return tuple([np.random.randint(0, i - 1, int(num_salt))
for i in image.shape[: 2]])


def get_random_speckle_noise(image):
intensity = np.random.uniform(const.MIN_SPECKLE_NOISE, const.MAX_SPECKLE_NOISE)
return get_speckle_noise(image, intensity)


# tip: use it as first transformation, apply other noises afterwards
def get_speckle_noise(image, intensity=0.1, add_blur=const.ADD_BLUR_AFTER_SPECKLE_NOISE):
intensity *= 127.5

# -intensity/2 <= speckle <= intensity/2
if len(image.shape) > 2:
h, w, ch = image.shape
speckle = -intensity / 2 + np.random.randn(h, w, ch) * intensity
speckle = speckle.reshape(h, w, ch)
else:
h, w = image.shape
speckle = -intensity / 2 + np.random.randn(h, w) * intensity
speckle = speckle.reshape(h, w)

speckle = image + speckle
speckle = __get_normalized_image(speckle)
if add_blur and intensity > 26:
return blur(speckle, width=1)

return speckle
66 changes: 66 additions & 0 deletions references/obj_detection/shadow_ellipse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import cv2
import numpy as np

import constants as const
import shadow_mask as mask


def add_n_ellipses_light(image, intensity=0.5, blur_width=6, n=1):
inverted_colors = const.WHITE - image
inverted_shadow = add_n_ellipses_shadow(inverted_colors, intensity, blur_width, n)

return const.WHITE - inverted_shadow


def add_n_ellipses_shadow(image, intensity=0.5, blur_width=6, n=1):
for i in range(n):
image = add_ellipse_shadow(image,
intensity=intensity,
blur_width=blur_width,
)

return image


def add_ellipse_light(image, intensity=0.5, blur_width=6):
inverted_colors = const.WHITE - image
inverted_shadow = add_ellipse_shadow(inverted_colors, intensity, blur_width)

return const.WHITE - inverted_shadow


def add_ellipse_shadow(image, intensity=0.5, blur_width=6):
shadow_mask = np.zeros(image.shape[: 2], dtype=np.uint8)
shadow_mask.fill(const.WHITE)
ellipse = __get_multiple_ellipses(shadow_mask)

return mask.apply_shadow_mask(image, blur_width, intensity, ellipse)


def __get_multiple_ellipses(image):
h, w = image.shape[: 2]
center = int(w * np.random.uniform()), int(h * np.random.uniform())
random_h = np.random.uniform() * h
random_w = np.random.uniform() * w
axes1 = int(random_h * 0.2), int(random_w * 0.2)
axes2 = int(random_h * 0.4), int(random_w * 0.4)
axes3 = int(random_h * 0.6), int(random_w * 0.6)
axes4 = int(random_h * 0.8), int(random_w * 0.8)
axes5 = int(random_h), int(random_w)
angle = 360 * np.random.uniform()

ellipse = get_single_ellipse(image, center, axes5, angle, const.DARK_WHITE)
ellipse = get_single_ellipse(ellipse, center, axes4, angle, const.LIGHT_GRAY)
ellipse = get_single_ellipse(ellipse, center, axes3, angle, const.GRAY)
ellipse = get_single_ellipse(ellipse, center, axes2, angle, const.DARK_GRAY)

return get_single_ellipse(ellipse, center, axes1, angle, const.LIGHT_BLACK)


def get_single_ellipse(image, center, axes, angle, color):
start_angle = 0
end_angle = 360
thickness = -1

return cv2.ellipse(image, center, axes, angle, start_angle, end_angle,
color, thickness)
Loading