import numpy as np import cv2 #### Augmentations 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) #INTER_NEAREST 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() # use CPU group by default, to reduce GPU RAM usage. 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 # Compute Dice coefficient 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 # Compute Dice coefficient intersection = np.logical_and(im1, im2) return intersection.sum() / im_sum