|
import numpy as np |
|
import cv2 |
|
|
|
|
|
def shift_image(img, shift_pnt): |
|
M = np.float32([[1, 0, shift_pnt[0]], [0, 1, shift_pnt[1]]]) |
|
res = cv2.warpAffine(img, M, (img.shape[1], img.shape[0]), borderMode=cv2.BORDER_REFLECT_101) |
|
return res |
|
|
|
|
|
def rotate_image(image, angle, scale, rot_pnt): |
|
rot_mat = cv2.getRotationMatrix2D(rot_pnt, angle, scale) |
|
result = cv2.warpAffine(image, rot_mat, (image.shape[1], image.shape[0]), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101) |
|
return result |
|
|
|
|
|
def gauss_noise(img, var=30): |
|
row, col, ch = img.shape |
|
mean = var |
|
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 np.clip(img.astype(np.int32) + gauss, 0, 255).astype('uint8') |
|
|
|
|
|
def clahe(img, clipLimit=2.0, tileGridSize=(5,5)): |
|
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 _blend(img1, img2, alpha): |
|
return np.clip(img1 * alpha + (1 - alpha) * img2, 0, 255).astype('uint8') |
|
|
|
|
|
_alpha = np.asarray([0.114, 0.587, 0.299]).reshape((1, 1, 3)) |
|
def _grayscale(img): |
|
return np.sum(_alpha * img, axis=2, keepdims=True) |
|
|
|
|
|
def saturation(img, alpha): |
|
gs = _grayscale(img) |
|
return _blend(img, gs, alpha) |
|
|
|
|
|
def brightness(img, alpha): |
|
gs = np.zeros_like(img) |
|
return _blend(img, gs, alpha) |
|
|
|
|
|
def contrast(img, alpha): |
|
gs = _grayscale(img) |
|
gs = np.repeat(gs.mean(), 3) |
|
return _blend(img, gs, alpha) |
|
|
|
|
|
def change_hsv(img, h, s, v): |
|
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) |
|
hsv = hsv.astype(int) |
|
hsv[:,:,0] += h |
|
hsv[:,:,0] = np.clip(hsv[:,:,0], 0, 255) |
|
hsv[:,:,1] += s |
|
hsv[:,:,1] = np.clip(hsv[:,:,1], 0, 255) |
|
hsv[:,:,2] += v |
|
hsv[:,:,2] = np.clip(hsv[:,:,2], 0, 255) |
|
hsv = hsv.astype('uint8') |
|
img = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR) |
|
return img |
|
|
|
def shift_channels(img, b_shift, g_shift, r_shift): |
|
img = img.astype(int) |
|
img[:,:,0] += b_shift |
|
img[:,:,0] = np.clip(img[:,:,0], 0, 255) |
|
img[:,:,1] += g_shift |
|
img[:,:,1] = np.clip(img[:,:,1], 0, 255) |
|
img[:,:,2] += r_shift |
|
img[:,:,2] = np.clip(img[:,:,2], 0, 255) |
|
img = img.astype('uint8') |
|
return img |
|
|
|
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 |
|
|
|
|
|
|
|
|
|
class AverageMeter(object): |
|
"""Computes and stores the average and current value""" |
|
def __init__(self): |
|
self.reset() |
|
def reset(self): |
|
self.val = 0 |
|
self.avg = 0 |
|
self.sum = 0 |
|
self.count = 0 |
|
def update(self, val, n=1): |
|
self.val = val |
|
self.sum += val * n |
|
self.count += n |
|
self.avg = self.sum / self.count |
|
|
|
|
|
|
|
def preprocess_inputs(x): |
|
x = np.asarray(x, dtype='float32') |
|
x /= 127 |
|
x -= 1 |
|
return x |
|
|
|
import torch.distributed as dist |
|
import functools |
|
@functools.lru_cache() |
|
def _get_global_gloo_group(): |
|
""" |
|
Return a process group based on gloo backend, containing all the ranks |
|
The result is cached. |
|
""" |
|
if dist.get_backend() == "nccl": |
|
return dist.new_group(backend="gloo") |
|
else: |
|
return dist.group.WORLD |
|
|
|
def all_gather(data, group=None): |
|
""" |
|
Run all_gather on arbitrary picklable data (not necessarily tensors). |
|
|
|
Args: |
|
data: any picklable object |
|
group: a torch process group. By default, will use a group which |
|
contains all ranks on gloo backend. |
|
|
|
Returns: |
|
list[data]: list of data gathered from each rank |
|
""" |
|
if dist.get_world_size() == 1: |
|
return [data] |
|
if group is None: |
|
group = _get_global_gloo_group() |
|
world_size = dist.get_world_size(group) |
|
if world_size == 1: |
|
return [data] |
|
|
|
output = [None for _ in range(world_size)] |
|
dist.all_gather_object(output, data, group=group) |
|
return output |
|
|
|
|
|
def dice(im1, im2, empty_score=1.0): |
|
""" |
|
Computes the Dice coefficient, a measure of set similarity. |
|
Parameters |
|
---------- |
|
im1 : array-like, bool |
|
Any array of arbitrary size. If not boolean, will be converted. |
|
im2 : array-like, bool |
|
Any other array of identical size. If not boolean, will be converted. |
|
Returns |
|
------- |
|
dice : float |
|
Dice coefficient as a float on range [0,1]. |
|
Maximum similarity = 1 |
|
No similarity = 0 |
|
Both are empty (sum eq to zero) = empty_score |
|
|
|
Notes |
|
----- |
|
The order of inputs for `dice` is irrelevant. The result will be |
|
identical if `im1` and `im2` are switched. |
|
""" |
|
im1 = np.asarray(im1).astype(bool) |
|
im2 = np.asarray(im2).astype(bool) |
|
|
|
if im1.shape != im2.shape: |
|
raise ValueError("Shape mismatch: im1 and im2 must have the same shape.") |
|
|
|
im_sum = im1.sum() + im2.sum() |
|
if im_sum == 0: |
|
return empty_score |
|
|
|
|
|
intersection = np.logical_and(im1, im2) |
|
|
|
return 2. * intersection.sum() / im_sum |
|
|
|
|
|
def iou(im1, im2, empty_score=1.0): |
|
im1 = np.asarray(im1).astype(np.bool) |
|
im2 = np.asarray(im2).astype(np.bool) |
|
|
|
if im1.shape != im2.shape: |
|
raise ValueError("Shape mismatch: im1 and im2 must have the same shape.") |
|
|
|
union = np.logical_or(im1, im2) |
|
im_sum = union.sum() |
|
if im_sum == 0: |
|
return empty_score |
|
|
|
|
|
intersection = np.logical_and(im1, im2) |
|
|
|
return intersection.sum() / im_sum |