yacwc
This commit is contained in:
856
data_aug/data_aug.py
Normal file
856
data_aug/data_aug.py
Normal file
@@ -0,0 +1,856 @@
|
||||
import random
|
||||
import numpy as np
|
||||
import cv2
|
||||
import matplotlib.pyplot as plt
|
||||
import sys
|
||||
import os
|
||||
from bbox_util import *
|
||||
|
||||
lib_path = os.path.join(os.path.realpath("."), "data_aug")
|
||||
sys.path.append(lib_path)
|
||||
|
||||
|
||||
class RandomHorizontalFlip(object):
|
||||
|
||||
"""Randomly horizontally flips the Image with the probability *p*
|
||||
|
||||
Parameters
|
||||
----------
|
||||
p: float
|
||||
The probability with which the image is flipped
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndaaray
|
||||
Flipped image in the numpy format of shape `HxWxC`
|
||||
|
||||
numpy.ndarray
|
||||
Tranformed bounding box co-ordinates of the format `n x 4` where n is
|
||||
number of bounding boxes and 4 represents `x1,y1,x2,y2` of the box
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, p=0.5):
|
||||
self.p = p
|
||||
|
||||
def __call__(self, img, bboxes):
|
||||
img_center = np.array(img.shape[:2])[::-1]/2
|
||||
img_center = np.hstack((img_center, img_center))
|
||||
if random.random() < self.p:
|
||||
img = img[:, ::-1, :]
|
||||
bboxes[:, [0, 2]] += 2*(img_center[[0, 2]] - bboxes[:, [0, 2]])
|
||||
|
||||
box_w = abs(bboxes[:, 0] - bboxes[:, 2])
|
||||
|
||||
bboxes[:, 0] -= box_w
|
||||
bboxes[:, 2] += box_w
|
||||
|
||||
return img, bboxes
|
||||
|
||||
|
||||
class HorizontalFlip(object):
|
||||
|
||||
"""Randomly horizontally flips the Image with the probability *p*
|
||||
|
||||
Parameters
|
||||
----------
|
||||
p: float
|
||||
The probability with which the image is flipped
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndaaray
|
||||
Flipped image in the numpy format of shape `HxWxC`
|
||||
|
||||
numpy.ndarray
|
||||
Tranformed bounding box co-ordinates of the format `n x 4` where n is
|
||||
number of bounding boxes and 4 represents `x1,y1,x2,y2` of the box
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __call__(self, img, bboxes):
|
||||
img_center = np.array(img.shape[:2])[::-1]/2
|
||||
img_center = np.hstack((img_center, img_center))
|
||||
|
||||
img = img[:, ::-1, :]
|
||||
bboxes[:, [0, 2]] += 2*(img_center[[0, 2]] - bboxes[:, [0, 2]])
|
||||
|
||||
box_w = abs(bboxes[:, 0] - bboxes[:, 2])
|
||||
|
||||
bboxes[:, 0] -= box_w
|
||||
bboxes[:, 2] += box_w
|
||||
|
||||
return img, bboxes
|
||||
|
||||
|
||||
class RandomScale(object):
|
||||
"""Randomly scales an image
|
||||
|
||||
|
||||
Bounding boxes which have an area of less than 25% in the remaining in the
|
||||
transformed image is dropped. The resolution is maintained, and the remaining
|
||||
area if any is filled by black color.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scale: float or tuple(float)
|
||||
if **float**, the image is scaled by a factor drawn
|
||||
randomly from a range (1 - `scale` , 1 + `scale`). If **tuple**,
|
||||
the `scale` is drawn randomly from values specified by the
|
||||
tuple
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndaaray
|
||||
Scaled image in the numpy format of shape `HxWxC`
|
||||
|
||||
numpy.ndarray
|
||||
Tranformed bounding box co-ordinates of the format `n x 4` where n is
|
||||
number of bounding boxes and 4 represents `x1,y1,x2,y2` of the box
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, scale = 0.2, diff = False):
|
||||
self.scale = scale
|
||||
|
||||
|
||||
if type(self.scale) == tuple:
|
||||
assert len(self.scale) == 2, "Invalid range"
|
||||
assert self.scale[0] > -1, "Scale factor can't be less than -1"
|
||||
assert self.scale[1] > -1, "Scale factor can't be less than -1"
|
||||
else:
|
||||
assert self.scale > 0, "Please input a positive float"
|
||||
self.scale = (max(-1, -self.scale), self.scale)
|
||||
|
||||
self.diff = diff
|
||||
|
||||
|
||||
|
||||
def __call__(self, img, bboxes):
|
||||
|
||||
|
||||
#Chose a random digit to scale by
|
||||
|
||||
img_shape = img.shape
|
||||
|
||||
if self.diff:
|
||||
scale_x = random.uniform(*self.scale)
|
||||
scale_y = random.uniform(*self.scale)
|
||||
else:
|
||||
scale_x = random.uniform(*self.scale)
|
||||
scale_y = scale_x
|
||||
|
||||
|
||||
|
||||
resize_scale_x = 1 + scale_x
|
||||
resize_scale_y = 1 + scale_y
|
||||
|
||||
img= cv2.resize(img, None, fx = resize_scale_x, fy = resize_scale_y)
|
||||
|
||||
bboxes[:,:4] *= [resize_scale_x, resize_scale_y, resize_scale_x, resize_scale_y]
|
||||
|
||||
|
||||
|
||||
canvas = np.zeros(img_shape, dtype = np.uint8)
|
||||
|
||||
y_lim = int(min(resize_scale_y,1)*img_shape[0])
|
||||
x_lim = int(min(resize_scale_x,1)*img_shape[1])
|
||||
|
||||
|
||||
canvas[:y_lim,:x_lim,:] = img[:y_lim,:x_lim,:]
|
||||
|
||||
img = canvas
|
||||
bboxes = clip_box(bboxes, [0,0,1 + img_shape[1], img_shape[0]], 0.25)
|
||||
|
||||
|
||||
return img, bboxes
|
||||
|
||||
|
||||
class Scale(object):
|
||||
"""Scales the image
|
||||
|
||||
Bounding boxes which have an area of less than 25% in the remaining in the
|
||||
transformed image is dropped. The resolution is maintained, and the remaining
|
||||
area if any is filled by black color.
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scale_x: float
|
||||
The factor by which the image is scaled horizontally
|
||||
|
||||
scale_y: float
|
||||
The factor by which the image is scaled vertically
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndaaray
|
||||
Scaled image in the numpy format of shape `HxWxC`
|
||||
|
||||
numpy.ndarray
|
||||
Tranformed bounding box co-ordinates of the format `n x 4` where n is
|
||||
number of bounding boxes and 4 represents `x1,y1,x2,y2` of the box
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, scale_x = 0.2, scale_y = 0.2):
|
||||
self.scale_x = scale_x
|
||||
self.scale_y = scale_y
|
||||
|
||||
|
||||
def __call__(self, img, bboxes):
|
||||
|
||||
|
||||
#Chose a random digit to scale by
|
||||
|
||||
img_shape = img.shape
|
||||
|
||||
|
||||
resize_scale_x = 1 + self.scale_x
|
||||
resize_scale_y = 1 + self.scale_y
|
||||
|
||||
img= cv2.resize(img, None, fx = resize_scale_x, fy = resize_scale_y)
|
||||
|
||||
bboxes[:,:4] *= [resize_scale_x, resize_scale_y, resize_scale_x, resize_scale_y]
|
||||
|
||||
|
||||
|
||||
canvas = np.zeros(img_shape, dtype = np.uint8)
|
||||
|
||||
y_lim = int(min(resize_scale_y,1)*img_shape[0])
|
||||
x_lim = int(min(resize_scale_x,1)*img_shape[1])
|
||||
|
||||
|
||||
canvas[:y_lim,:x_lim,:] = img[:y_lim,:x_lim,:]
|
||||
|
||||
img = canvas
|
||||
bboxes = clip_box(bboxes, [0,0,1 + img_shape[1], img_shape[0]], 0.25)
|
||||
|
||||
|
||||
return img, bboxes
|
||||
|
||||
|
||||
class RandomTranslate(object):
|
||||
"""Randomly Translates the image
|
||||
|
||||
|
||||
Bounding boxes which have an area of less than 25% in the remaining in the
|
||||
transformed image is dropped. The resolution is maintained, and the remaining
|
||||
area if any is filled by black color.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
translate: float or tuple(float)
|
||||
if **float**, the image is translated by a factor drawn
|
||||
randomly from a range (1 - `translate` , 1 + `translate`). If **tuple**,
|
||||
`translate` is drawn randomly from values specified by the
|
||||
tuple
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndaaray
|
||||
Translated image in the numpy format of shape `HxWxC`
|
||||
|
||||
numpy.ndarray
|
||||
Tranformed bounding box co-ordinates of the format `n x 4` where n is
|
||||
number of bounding boxes and 4 represents `x1,y1,x2,y2` of the box
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, translate = 0.2, diff = False):
|
||||
self.translate = translate
|
||||
|
||||
if type(self.translate) == tuple:
|
||||
assert len(self.translate) == 2, "Invalid range"
|
||||
assert self.translate[0] > 0 & self.translate[0] < 1
|
||||
assert self.translate[1] > 0 & self.translate[1] < 1
|
||||
|
||||
|
||||
else:
|
||||
assert self.translate > 0 and self.translate < 1
|
||||
self.translate = (-self.translate, self.translate)
|
||||
|
||||
|
||||
self.diff = diff
|
||||
|
||||
def __call__(self, img, bboxes):
|
||||
#Chose a random digit to scale by
|
||||
img_shape = img.shape
|
||||
|
||||
#translate the image
|
||||
|
||||
#percentage of the dimension of the image to translate
|
||||
translate_factor_x = random.uniform(*self.translate)
|
||||
translate_factor_y = random.uniform(*self.translate)
|
||||
|
||||
if not self.diff:
|
||||
translate_factor_y = translate_factor_x
|
||||
|
||||
canvas = np.zeros(img_shape).astype(np.uint8)
|
||||
|
||||
|
||||
corner_x = int(translate_factor_x*img.shape[1])
|
||||
corner_y = int(translate_factor_y*img.shape[0])
|
||||
|
||||
|
||||
|
||||
#change the origin to the top-left corner of the translated box
|
||||
orig_box_cords = [max(0,corner_y), max(corner_x,0), min(img_shape[0], corner_y + img.shape[0]), min(img_shape[1],corner_x + img.shape[1])]
|
||||
|
||||
|
||||
|
||||
|
||||
mask = img[max(-corner_y, 0):min(img.shape[0], -corner_y + img_shape[0]), max(-corner_x, 0):min(img.shape[1], -corner_x + img_shape[1]),:]
|
||||
canvas[orig_box_cords[0]:orig_box_cords[2], orig_box_cords[1]:orig_box_cords[3],:] = mask
|
||||
img = canvas
|
||||
|
||||
bboxes[:,:4] += [corner_x, corner_y, corner_x, corner_y]
|
||||
|
||||
|
||||
bboxes = clip_box(bboxes, [0,0,img_shape[1], img_shape[0]], 0.25)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return img, bboxes
|
||||
|
||||
|
||||
class Translate(object):
|
||||
"""Randomly Translates the image
|
||||
|
||||
|
||||
Bounding boxes which have an area of less than 25% in the remaining in the
|
||||
transformed image is dropped. The resolution is maintained, and the remaining
|
||||
area if any is filled by black color.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
translate: float or tuple(float)
|
||||
if **float**, the image is translated by a factor drawn
|
||||
randomly from a range (1 - `translate` , 1 + `translate`). If **tuple**,
|
||||
`translate` is drawn randomly from values specified by the
|
||||
tuple
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndaaray
|
||||
Translated image in the numpy format of shape `HxWxC`
|
||||
|
||||
numpy.ndarray
|
||||
Tranformed bounding box co-ordinates of the format `n x 4` where n is
|
||||
number of bounding boxes and 4 represents `x1,y1,x2,y2` of the box
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, translate_x = 0.2, translate_y = 0.2, diff = False):
|
||||
self.translate_x = translate_x
|
||||
self.translate_y = translate_y
|
||||
|
||||
assert self.translate_x > 0 and self.translate_x < 1
|
||||
assert self.translate_y > 0 and self.translate_y < 1
|
||||
|
||||
|
||||
def __call__(self, img, bboxes):
|
||||
#Chose a random digit to scale by
|
||||
img_shape = img.shape
|
||||
|
||||
#translate the image
|
||||
|
||||
#percentage of the dimension of the image to translate
|
||||
translate_factor_x = self.translate_x
|
||||
translate_factor_y = self.translate_y
|
||||
|
||||
|
||||
canvas = np.zeros(img_shape).astype(np.uint8)
|
||||
|
||||
|
||||
#get the top-left corner co-ordinates of the shifted box
|
||||
corner_x = int(translate_factor_x*img.shape[1])
|
||||
corner_y = int(translate_factor_y*img.shape[0])
|
||||
|
||||
|
||||
|
||||
#change the origin to the top-left corner of the translated box
|
||||
orig_box_cords = [max(0,corner_y), max(corner_x,0), min(img_shape[0], corner_y + img.shape[0]), min(img_shape[1],corner_x + img.shape[1])]
|
||||
|
||||
|
||||
|
||||
|
||||
mask = img[max(-corner_y, 0):min(img.shape[0], -corner_y + img_shape[0]), max(-corner_x, 0):min(img.shape[1], -corner_x + img_shape[1]),:]
|
||||
canvas[orig_box_cords[0]:orig_box_cords[2], orig_box_cords[1]:orig_box_cords[3],:] = mask
|
||||
img = canvas
|
||||
|
||||
bboxes[:,:4] += [corner_x, corner_y, corner_x, corner_y]
|
||||
|
||||
|
||||
bboxes = clip_box(bboxes, [0,0,img_shape[1], img_shape[0]], 0.25)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return img, bboxes
|
||||
|
||||
|
||||
class RandomRotate(object):
|
||||
"""Randomly rotates an image
|
||||
|
||||
|
||||
Bounding boxes which have an area of less than 25% in the remaining in the
|
||||
transformed image is dropped. The resolution is maintained, and the remaining
|
||||
area if any is filled by black color.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
angle: float or tuple(float)
|
||||
if **float**, the image is rotated by a factor drawn
|
||||
randomly from a range (-`angle`, `angle`). If **tuple**,
|
||||
the `angle` is drawn randomly from values specified by the
|
||||
tuple
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndaaray
|
||||
Rotated image in the numpy format of shape `HxWxC`
|
||||
|
||||
numpy.ndarray
|
||||
Tranformed bounding box co-ordinates of the format `n x 4` where n is
|
||||
number of bounding boxes and 4 represents `x1,y1,x2,y2` of the box
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, angle = 10):
|
||||
self.angle = angle
|
||||
|
||||
if type(self.angle) == tuple:
|
||||
assert len(self.angle) == 2, "Invalid range"
|
||||
|
||||
else:
|
||||
self.angle = (-self.angle, self.angle)
|
||||
|
||||
def __call__(self, img, bboxes):
|
||||
|
||||
angle = random.uniform(*self.angle)
|
||||
|
||||
w,h = img.shape[1], img.shape[0]
|
||||
cx, cy = w//2, h//2
|
||||
|
||||
img = rotate_im(img, angle)
|
||||
|
||||
corners = get_corners(bboxes)
|
||||
|
||||
corners = np.hstack((corners, bboxes[:,4:]))
|
||||
|
||||
|
||||
corners[:,:8] = rotate_box(corners[:,:8], angle, cx, cy, h, w)
|
||||
|
||||
new_bbox = get_enclosing_box(corners)
|
||||
|
||||
|
||||
scale_factor_x = img.shape[1] / w
|
||||
|
||||
scale_factor_y = img.shape[0] / h
|
||||
|
||||
img = cv2.resize(img, (w,h))
|
||||
|
||||
new_bbox[:,:4] /= [scale_factor_x, scale_factor_y, scale_factor_x, scale_factor_y]
|
||||
|
||||
bboxes = new_bbox
|
||||
|
||||
bboxes = clip_box(bboxes, [0,0,w, h], 0.25)
|
||||
|
||||
return img, bboxes
|
||||
|
||||
|
||||
class Rotate(object):
|
||||
"""Rotates an image
|
||||
|
||||
|
||||
Bounding boxes which have an area of less than 25% in the remaining in the
|
||||
transformed image is dropped. The resolution is maintained, and the remaining
|
||||
area if any is filled by black color.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
angle: float
|
||||
The angle by which the image is to be rotated
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndaaray
|
||||
Rotated image in the numpy format of shape `HxWxC`
|
||||
|
||||
numpy.ndarray
|
||||
Tranformed bounding box co-ordinates of the format `n x 4` where n is
|
||||
number of bounding boxes and 4 represents `x1,y1,x2,y2` of the box
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, angle):
|
||||
self.angle = angle
|
||||
|
||||
|
||||
def __call__(self, img, bboxes):
|
||||
"""
|
||||
Args:
|
||||
img (PIL Image): Image to be flipped.
|
||||
|
||||
Returns:
|
||||
PIL Image: Randomly flipped image.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
angle = self.angle
|
||||
print(self.angle)
|
||||
|
||||
w,h = img.shape[1], img.shape[0]
|
||||
cx, cy = w//2, h//2
|
||||
|
||||
corners = get_corners(bboxes)
|
||||
|
||||
corners = np.hstack((corners, bboxes[:,4:]))
|
||||
|
||||
img = rotate_im(img, angle)
|
||||
|
||||
corners[:,:8] = rotate_box(corners[:,:8], angle, cx, cy, h, w)
|
||||
|
||||
|
||||
|
||||
|
||||
new_bbox = get_enclosing_box(corners)
|
||||
|
||||
|
||||
scale_factor_x = img.shape[1] / w
|
||||
|
||||
scale_factor_y = img.shape[0] / h
|
||||
|
||||
img = cv2.resize(img, (w,h))
|
||||
|
||||
new_bbox[:,:4] /= [scale_factor_x, scale_factor_y, scale_factor_x, scale_factor_y]
|
||||
|
||||
|
||||
bboxes = new_bbox
|
||||
|
||||
bboxes = clip_box(bboxes, [0,0,w, h], 0.25)
|
||||
|
||||
return img, bboxes
|
||||
|
||||
|
||||
|
||||
class RandomShear(object):
|
||||
"""Randomly shears an image in horizontal direction
|
||||
|
||||
|
||||
Bounding boxes which have an area of less than 25% in the remaining in the
|
||||
transformed image is dropped. The resolution is maintained, and the remaining
|
||||
area if any is filled by black color.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
shear_factor: float or tuple(float)
|
||||
if **float**, the image is sheared horizontally by a factor drawn
|
||||
randomly from a range (-`shear_factor`, `shear_factor`). If **tuple**,
|
||||
the `shear_factor` is drawn randomly from values specified by the
|
||||
tuple
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndaaray
|
||||
Sheared image in the numpy format of shape `HxWxC`
|
||||
|
||||
numpy.ndarray
|
||||
Tranformed bounding box co-ordinates of the format `n x 4` where n is
|
||||
number of bounding boxes and 4 represents `x1,y1,x2,y2` of the box
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, shear_factor = 0.2):
|
||||
self.shear_factor = shear_factor
|
||||
|
||||
if type(self.shear_factor) == tuple:
|
||||
assert len(self.shear_factor) == 2, "Invalid range for scaling factor"
|
||||
else:
|
||||
self.shear_factor = (-self.shear_factor, self.shear_factor)
|
||||
|
||||
shear_factor = random.uniform(*self.shear_factor)
|
||||
|
||||
def __call__(self, img, bboxes):
|
||||
|
||||
shear_factor = random.uniform(*self.shear_factor)
|
||||
|
||||
w,h = img.shape[1], img.shape[0]
|
||||
|
||||
if shear_factor < 0:
|
||||
img, bboxes = HorizontalFlip()(img, bboxes)
|
||||
|
||||
M = np.array([[1, abs(shear_factor), 0],[0,1,0]])
|
||||
|
||||
nW = img.shape[1] + abs(shear_factor*img.shape[0])
|
||||
|
||||
bboxes[:,[0,2]] += ((bboxes[:,[1,3]]) * abs(shear_factor) ).astype(int)
|
||||
|
||||
|
||||
img = cv2.warpAffine(img, M, (int(nW), img.shape[0]))
|
||||
|
||||
if shear_factor < 0:
|
||||
img, bboxes = HorizontalFlip()(img, bboxes)
|
||||
|
||||
img = cv2.resize(img, (w,h))
|
||||
|
||||
scale_factor_x = nW / w
|
||||
|
||||
bboxes[:,:4] /= [scale_factor_x, 1, scale_factor_x, 1]
|
||||
|
||||
|
||||
return img, bboxes
|
||||
|
||||
class Shear(object):
|
||||
"""Shears an image in horizontal direction
|
||||
|
||||
|
||||
Bounding boxes which have an area of less than 25% in the remaining in the
|
||||
transformed image is dropped. The resolution is maintained, and the remaining
|
||||
area if any is filled by black color.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
shear_factor: float
|
||||
Factor by which the image is sheared in the x-direction
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndaaray
|
||||
Sheared image in the numpy format of shape `HxWxC`
|
||||
|
||||
numpy.ndarray
|
||||
Tranformed bounding box co-ordinates of the format `n x 4` where n is
|
||||
number of bounding boxes and 4 represents `x1,y1,x2,y2` of the box
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, shear_factor = 0.2):
|
||||
self.shear_factor = shear_factor
|
||||
|
||||
|
||||
def __call__(self, img, bboxes):
|
||||
|
||||
shear_factor = self.shear_factor
|
||||
if shear_factor < 0:
|
||||
img, bboxes = HorizontalFlip()(img, bboxes)
|
||||
|
||||
|
||||
M = np.array([[1, abs(shear_factor), 0],[0,1,0]])
|
||||
|
||||
nW = img.shape[1] + abs(shear_factor*img.shape[0])
|
||||
|
||||
bboxes[:,[0,2]] += ((bboxes[:,[1,3]])*abs(shear_factor)).astype(int)
|
||||
|
||||
|
||||
img = cv2.warpAffine(img, M, (int(nW), img.shape[0]))
|
||||
|
||||
if shear_factor < 0:
|
||||
img, bboxes = HorizontalFlip()(img, bboxes)
|
||||
|
||||
|
||||
return img, bboxes
|
||||
|
||||
class Resize(object):
|
||||
"""Resize the image in accordance to `image_letter_box` function in darknet
|
||||
|
||||
The aspect ratio is maintained. The longer side is resized to the input
|
||||
size of the network, while the remaining space on the shorter side is filled
|
||||
with black color. **This should be the last transform**
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
inp_dim : tuple(int)
|
||||
tuple containing the size to which the image will be resized.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndaaray
|
||||
Sheared image in the numpy format of shape `HxWxC`
|
||||
|
||||
numpy.ndarray
|
||||
Resized bounding box co-ordinates of the format `n x 4` where n is
|
||||
number of bounding boxes and 4 represents `x1,y1,x2,y2` of the box
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, inp_dim):
|
||||
self.inp_dim = inp_dim
|
||||
|
||||
def __call__(self, img, bboxes):
|
||||
w,h = img.shape[1], img.shape[0]
|
||||
img = letterbox_image(img, self.inp_dim)
|
||||
|
||||
|
||||
scale = min(self.inp_dim/h, self.inp_dim/w)
|
||||
bboxes[:,:4] *= (scale)
|
||||
|
||||
new_w = scale*w
|
||||
new_h = scale*h
|
||||
inp_dim = self.inp_dim
|
||||
|
||||
del_h = (inp_dim - new_h)/2
|
||||
del_w = (inp_dim - new_w)/2
|
||||
|
||||
add_matrix = np.array([[del_w, del_h, del_w, del_h]]).astype(int)
|
||||
|
||||
bboxes[:,:4] += add_matrix
|
||||
|
||||
img = img.astype(np.uint8)
|
||||
|
||||
return img, bboxes
|
||||
|
||||
|
||||
class RandomHSV(object):
|
||||
"""HSV Transform to vary hue saturation and brightness
|
||||
|
||||
Hue has a range of 0-179
|
||||
Saturation and Brightness have a range of 0-255.
|
||||
Chose the amount you want to change thhe above quantities accordingly.
|
||||
|
||||
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
hue : None or int or tuple (int)
|
||||
If None, the hue of the image is left unchanged. If int,
|
||||
a random int is uniformly sampled from (-hue, hue) and added to the
|
||||
hue of the image. If tuple, the int is sampled from the range
|
||||
specified by the tuple.
|
||||
|
||||
saturation : None or int or tuple(int)
|
||||
If None, the saturation of the image is left unchanged. If int,
|
||||
a random int is uniformly sampled from (-saturation, saturation)
|
||||
and added to the hue of the image. If tuple, the int is sampled
|
||||
from the range specified by the tuple.
|
||||
|
||||
brightness : None or int or tuple(int)
|
||||
If None, the brightness of the image is left unchanged. If int,
|
||||
a random int is uniformly sampled from (-brightness, brightness)
|
||||
and added to the hue of the image. If tuple, the int is sampled
|
||||
from the range specified by the tuple.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
numpy.ndaaray
|
||||
Transformed image in the numpy format of shape `HxWxC`
|
||||
|
||||
numpy.ndarray
|
||||
Resized bounding box co-ordinates of the format `n x 4` where n is
|
||||
number of bounding boxes and 4 represents `x1,y1,x2,y2` of the box
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, hue = None, saturation = None, brightness = None):
|
||||
if hue:
|
||||
self.hue = hue
|
||||
else:
|
||||
self.hue = 0
|
||||
|
||||
if saturation:
|
||||
self.saturation = saturation
|
||||
else:
|
||||
self.saturation = 0
|
||||
|
||||
if brightness:
|
||||
self.brightness = brightness
|
||||
else:
|
||||
self.brightness = 0
|
||||
|
||||
|
||||
|
||||
if type(self.hue) != tuple:
|
||||
self.hue = (-self.hue, self.hue)
|
||||
|
||||
if type(self.saturation) != tuple:
|
||||
self.saturation = (-self.saturation, self.saturation)
|
||||
|
||||
if type(brightness) != tuple:
|
||||
self.brightness = (-self.brightness, self.brightness)
|
||||
|
||||
def __call__(self, img, bboxes):
|
||||
|
||||
hue = random.randint(*self.hue)
|
||||
saturation = random.randint(*self.saturation)
|
||||
brightness = random.randint(*self.brightness)
|
||||
|
||||
img = img.astype(int)
|
||||
|
||||
a = np.array([hue, saturation, brightness]).astype(int)
|
||||
img += np.reshape(a, (1,1,3))
|
||||
|
||||
img = np.clip(img, 0, 255)
|
||||
img[:,:,0] = np.clip(img[:,:,0],0, 179)
|
||||
|
||||
img = img.astype(np.uint8)
|
||||
|
||||
|
||||
|
||||
return img, bboxes
|
||||
|
||||
class Sequence(object):
|
||||
|
||||
"""Initialise Sequence object
|
||||
|
||||
Apply a Sequence of transformations to the images/boxes.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
augemnetations : list
|
||||
List containing Transformation Objects in Sequence they are to be
|
||||
applied
|
||||
|
||||
probs : int or list
|
||||
If **int**, the probability with which each of the transformation will
|
||||
be applied. If **list**, the length must be equal to *augmentations*.
|
||||
Each element of this list is the probability with which each
|
||||
corresponding transformation is applied
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
Sequence
|
||||
Sequence Object
|
||||
|
||||
"""
|
||||
def __init__(self, augmentations, probs = 1):
|
||||
|
||||
|
||||
self.augmentations = augmentations
|
||||
self.probs = probs
|
||||
|
||||
def __call__(self, images, bboxes):
|
||||
for i, augmentation in enumerate(self.augmentations):
|
||||
if type(self.probs) == list:
|
||||
prob = self.probs[i]
|
||||
else:
|
||||
prob = self.probs
|
||||
|
||||
if random.random() < prob:
|
||||
images, bboxes = augmentation(images, bboxes)
|
||||
return images, bboxes
|
||||
Reference in New Issue
Block a user