import cv2
cv2.setNumThreads(0)
cv2.ocl.setUseOpenCL(False)
import numpy as np
import math
from scipy.ndimage.filters import gaussian_filter
from functools import wraps
def vflip(img):
return cv2.flip(img, 0)
def hflip(img):
return cv2.flip(img, 1)
def random_flip(img, code):
return cv2.flip(img, code)
def transpose(img):
return img.transpose(1, 0, 2) if len(img.shape) > 2 else img.transpose(1, 0)
def rot90(img, factor):
img = np.rot90(img, factor)
return np.ascontiguousarray(img)
def rotate(img, angle):
height, width = img.shape[0:2]
mat = cv2.getRotationMatrix2D((width/2, height/2), angle, 1.0)
img = cv2.warpAffine(img, mat, (width, height),
flags=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_REFLECT_101)
return img
def shift_scale_rotate(img, angle, scale, dx, dy):
height, width = img.shape[:2]
cc = math.cos(angle/180*math.pi) * scale
ss = math.sin(angle/180*math.pi) * scale
rotate_matrix = np.array([[cc, -ss], [ss, cc]])
box0 = np.array([[0, 0], [width, 0], [width, height], [0, height], ])
box1 = box0 - np.array([width/2, height/2])
box1 = np.dot(box1, rotate_matrix.T) + np.array([width/2+dx*width, height/2+dy*height])
box0 = box0.astype(np.float32)
box1 = box1.astype(np.float32)
mat = cv2.getPerspectiveTransform(box0, box1)
img = cv2.warpPerspective(img, mat, (width, height),
flags=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_REFLECT_101)
return img
def center_crop(img, height, width):
h, w, c = img.shape
dy = (h-height)//2
dx = (w-width)//2
y1 = dy
y2 = y1 + height
x1 = dx
x2 = x1 + width
img = img[y1:y2, x1:x2, :]
return img
def clip(img, dtype, maxval):
return np.clip(img, 0, maxval).astype(dtype)
def clipped(func):
@wraps(func)
def wrapped_function(img, *args, **kwargs):
dtype, maxval = img.dtype, np.max(img)
return clip(func(img, *args, **kwargs), dtype, maxval)
return wrapped_function
def shift_hsv(img, hue_shift, sat_shift, val_shift):
dtype = img.dtype
img = cv2.cvtColor(img, cv2.COLOR_RGB2HSV).astype(np.int32)
h, s, v = cv2.split(img)
h = cv2.add(h, hue_shift)
h = np.where(h < 0, 255 - h, h)
h = np.where(h > 255, h - 255, h)
h = h.astype(dtype)
s = clip(cv2.add(s, sat_shift), dtype, 255 if dtype == np.uint8 else 1.)
v = clip(cv2.add(v, val_shift), dtype, 255 if dtype == np.uint8 else 1.)
img = cv2.merge((h, s, v)).astype(dtype)
img = cv2.cvtColor(img, cv2.COLOR_HSV2RGB)
return img
@clipped
def shift_rgb(img, r_shift, g_shift, b_shift):
img[...,0] = img[...,0] + r_shift
img[...,1] = img[...,1] + g_shift
img[...,2] = img[...,2] + b_shift
return img
def clahe(img, clipLimit=2.0, tileGridSize=(8,8)):
img_yuv = cv2.cvtColor(img, cv2.COLOR_RGB2LAB)
clahe = cv2.createCLAHE(clipLimit=clipLimit, tileGridSize=tileGridSize)
img_yuv[:, :, 0] = clahe.apply(img_yuv[:, :, 0])
img_output = cv2.cvtColor(img_yuv, cv2.COLOR_LAB2RGB)
return img_output
def blur(img, ksize):
return cv2.blur(img, (ksize, ksize))
def median_blur(img, ksize):
return cv2.medianBlur(img, ksize)
def motion_blur(img, ksize):
kernel = np.zeros((ksize, ksize))
xs, ys = np.random.randint(0, kernel.shape[1]), np.random.randint(0, kernel.shape[0])
xe, ye = np.random.randint(0, kernel.shape[1]), np.random.randint(0, kernel.shape[0])
cv2.line(kernel, (xs, ys), (xe, ye), 1, thickness=1)
return cv2.filter2D(img, -1, kernel / np.sum(kernel))
def random_polosa(img):
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
if np.mean(gray) < 100:
empty = np.zeros(img.shape[:2], dtype=np.uint8)
xs, ys = np.random.randint(0, empty.shape[1]), np.random.randint(0, empty.shape[0])
xe, ye = np.random.randint(0, empty.shape[1]), np.random.randint(0, empty.shape[0])
factor = np.random.randint(1, 10) / 3.
cv2.line(empty, (xs, ys), (xe, ye), np.max(gray) / factor, thickness=np.random.randint(10, 100))
empty = cv2.blur(empty, (5, 5))
empty = empty | gray
return cv2.cvtColor(empty, cv2.COLOR_GRAY2RGB)
return img
def distort1(img, k=0, dx=0, dy=0):
""""
## unconverntional augmnet ################################################################################3
## https://stackoverflow.com/questions/6199636/formulas-for-barrel-pincushion-distortion
## https://stackoverflow.com/questions/10364201/image-transformation-in-opencv
## https://stackoverflow.com/questions/2477774/correcting-fisheye-distortion-programmatically
## http://www.coldvision.io/2017/03/02/advanced-lane-finding-using-opencv/
## barrel\pincushion distortion
"""
height, width = img.shape[:2]
# map_x, map_y =
# cv2.initUndistortRectifyMap(intrinsics, dist_coeffs, None, None, (width,height),cv2.CV_32FC1)
# https://stackoverflow.com/questions/6199636/formulas-for-barrel-pincushion-distortion
# https://stackoverflow.com/questions/10364201/image-transformation-in-opencv
k = k * 0.00001
dx = dx * width
dy = dy * height
x, y = np.mgrid[0:width:1, 0:height:1]
x = x.astype(np.float32) - width/2 - dx
y = y.astype(np.float32) - height/2 - dy
theta = np.arctan2(y, x)
d = (x*x + y*y)**0.5
r = d*(1+k*d*d)
map_x = r*np.cos(theta) + width/2 + dx
map_y = r*np.sin(theta) + height/2 + dy
img = cv2.remap(img, map_x, map_y, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101)
return img
def distort2(img, num_steps=10, xsteps=[], ysteps=[]):
"""
#http://pythology.blogspot.sg/2014/03/interpolation-on-regular-distorted-grid.html
## grid distortion
"""
height, width = img.shape[:2]
x_step = width // num_steps
xx = np.zeros(width, np.float32)
prev = 0
for idx, x in enumerate(range(0, width, x_step)):
start = x
end = x + x_step
if end > width:
end = width
cur = width
else:
cur = prev + x_step*xsteps[idx]
xx[start:end] = np.linspace(prev, cur, end-start)
prev = cur
y_step = height // num_steps
yy = np.zeros(height, np.float32)
prev = 0
for idx, y in enumerate(range(0, height, y_step)):
start = y
end = y + y_step
if end > height:
end = height
cur = height
else:
cur = prev + y_step*ysteps[idx]
yy[start:end] = np.linspace(prev, cur, end-start)
prev = cur
map_x, map_y = np.meshgrid(xx, yy)
map_x = map_x.astype(np.float32)
map_y = map_y.astype(np.float32)
img = cv2.remap(img, map_x, map_y,
interpolation=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_REFLECT_101)
return img
def elastic_transform_fast(image, alpha, sigma, alpha_affine, random_state=None):
"""Elastic deformation of images as described in [Simard2003]_ (with modifications).
.. [Simard2003] Simard, Steinkraus and Platt, "Best Practices for
Convolutional Neural Networks applied to Visual Document Analysis", in
Proc. of the International Conference on Document Analysis and
Recognition, 2003.
Based on https://gist.github.com/erniejunior/601cdf56d2b424757de5
"""
if random_state is None:
random_state = np.random.RandomState(1234)
shape = image.shape
shape_size = shape[:2]
# Random affine
center_square = np.float32(shape_size) // 2
square_size = min(shape_size) // 3
alpha = float(alpha)
sigma = float(sigma)
alpha_affine = float(alpha_affine)
pts1 = np.float32([center_square + square_size, [center_square[0] + square_size, center_square[1] - square_size],
center_square - square_size])
pts2 = pts1 + random_state.uniform(-alpha_affine, alpha_affine, size=pts1.shape).astype(np.float32)
M = cv2.getAffineTransform(pts1, pts2)
image = cv2.warpAffine(image, M, shape_size[::-1], borderMode=cv2.BORDER_REFLECT_101)
dx = np.float32(gaussian_filter((random_state.rand(*shape_size) * 2 - 1), sigma) * alpha)
dy = np.float32(gaussian_filter((random_state.rand(*shape_size) * 2 - 1), sigma) * alpha)
x, y = np.meshgrid(np.arange(shape[1]), np.arange(shape[0]))
mapx = np.float32(x + dx)
mapy = np.float32(y + dy)
return cv2.remap(image, mapx, mapy, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101)
def remap_color(img, bg, center, max):
def get_lut(img, bg, center, max):
ma = np.max(img)
# me = np.mean(img)
# th = np.mean([ma, me]) * 1.5
th = ma / 2
gap = 10
channels = [[], [], []]
range2 = ma - int(th)
for i in range(3):
channels[i].append(np.linspace(bg[i] - gap, center[i] - gap, int(th)).astype(np.uint8))
channels[i].append(np.linspace(center[i] - gap, max[i] + gap, range2).astype(np.uint8))
channels[i].append([max[i] + gap] * (256 - sum(map(len, channels[i]))))
channels[i] = np.hstack(channels[i])
return np.dstack(channels)
# img = adjust_gamma(img, 5.)
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
if np.mean(gray) > 100:
return img
lut = get_lut(img, bg, center, max)
res = cv2.LUT(img, lut).astype(np.uint8)
return res
def invert(img):
return 255 - img
def channel_shuffle(img):
ch_arr = [0, 1, 2]
np.random.shuffle(ch_arr)
img = img[..., ch_arr]
return img
@clipped
def gauss_noise(image, var):
row, col, ch = image.shape
mean = var
# var = 30
sigma = var**0.5
gauss = np.random.normal(mean,sigma,(row,col,ch))
gauss = gauss.reshape(row,col,ch)
gauss = (gauss - np.min(gauss)).astype(np.uint8)
return image.astype(np.int32) + gauss
def salt_pepper_noise(image):
#todo
s_vs_p = 0.5
amount = 0.004
noisy = image
# Salt mode
num_salt = np.ceil(amount * image.size * s_vs_p)
coords = [np.random.randint(0, i - 1, int(num_salt))
for i in image.shape]
noisy[coords] = 255
# Pepper mode
num_pepper = np.ceil(amount * image.size * (1. - s_vs_p))
coords = [np.random.randint(0, i - 1, int(num_pepper))
for i in image.shape]
noisy[coords] = 0
return noisy
def poisson_noise(image):
#todo
vals = len(np.unique(image))
vals = 2 ** np.ceil(np.log2(vals))
noisy = np.random.poisson(image * vals) / float(vals)
return noisy
def speckle_noise(image):
#todo
row, col, ch = image.shape
gauss = np.random.randn(row,col,ch)
gauss = gauss.reshape(row,col,ch)
noisy = image + image * gauss
return noisy
@clipped
def random_brightness(img, alpha):
return alpha * img
@clipped
def random_contrast(img, alpha):
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
gray = (3.0 * (1.0 - alpha) / gray.size) * np.sum(gray)
return alpha * img + gray
def to_three_channel_gray(img):
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
invgray = 255 - gray
clahe = cv2.createCLAHE(clipLimit=2, tileGridSize=(8, 8))
if np.mean(invgray) < np.mean(gray):
invgray, gray = gray, invgray
res = [invgray, gray, clahe.apply(invgray)]
return cv2.merge(res)
def to_gray(img):
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
if np.mean(gray) > 127:
gray = 255 - gray
return cv2.cvtColor(gray, cv2.COLOR_GRAY2RGB)
def add_channel(img):
lab = cv2.cvtColor(img, cv2.COLOR_RGB2LAB)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(21, 21))
lab = clahe.apply(lab[:, :, 0])
if lab.mean() > 127:
lab = 255 - lab
return np.dstack((img, lab))
def fix_mask(msk):
if len(msk.shape) > 2:
msk[..., 2] = (msk[..., 2] > 127)
msk[..., 1] = (msk[..., 1] > 127) * (msk[..., 2] == 0)
msk[..., 0] = (msk[..., 1] == 0) * (msk[..., 2] == 0)
else:
msk = (msk > 127)
return msk.astype(np.uint8) * 255
def img_to_tensor(im):
return np.moveaxis(im / (255. if im.dtype == np.uint8 else 1), -1, 0).astype(np.float32)
def mask_to_tensor(mask, num_classes, sigmoid):
if num_classes > 1:
if not sigmoid:
#softmax
long_mask = np.zeros((mask.shape[:2]), dtype=np.int64)
if len(mask.shape) == 3:
for c in range(mask.shape[2]):
long_mask[mask[...,c] > 0] = c
else:
long_mask[mask > 127] = 1
long_mask[mask == 0] = 0
return long_mask
else:
mask = img_to_tensor(mask)
else:
mask = np.expand_dims(mask / (255. if mask.dtype == np.uint8 else 1), 0).astype(np.float32)
return mask