import cv2 import random import numpy as np def mod_crop(img, scale): """Mod crop images, used during testing. Args: img (ndarray): Input image. scale (int): Scale factor. Returns: ndarray: Result image. """ img = img.copy() if img.ndim in (2, 3): h, w = img.shape[0], img.shape[1] h_remainder, w_remainder = h % scale, w % scale img = img[:h - h_remainder, :w - w_remainder, ...] else: raise ValueError(f'Wrong img ndim: {img.ndim}.') return img def augment(imgs, hflip=True, rotation=True, flows=None, return_status=False): """Augment: horizontal flips OR rotate (0, 90, 180, 270 degrees). We use vertical flip and transpose for rotation implementation. All the images in the list use the same augmentation. Args: imgs (list[ndarray] | ndarray): Images to be augmented. If the input is an ndarray, it will be transformed to a list. hflip (bool): Horizontal flip. Default: True. rotation (bool): Ratotation. Default: True. flows (list[ndarray]: Flows to be augmented. If the input is an ndarray, it will be transformed to a list. Dimension is (h, w, 2). Default: None. return_status (bool): Return the status of flip and rotation. Default: False. Returns: list[ndarray] | ndarray: Augmented images and flows. If returned results only have one element, just return ndarray. """ hflip = hflip and random.random() < 0.5 vflip = rotation and random.random() < 0.5 rot90 = rotation and random.random() < 0.5 def _augment(img): if hflip: # horizontal cv2.flip(img, 1, img) if vflip: # vertical cv2.flip(img, 0, img) if rot90: img = img.transpose(1, 0, 2) return img def _augment_flow(flow): if hflip: # horizontal cv2.flip(flow, 1, flow) flow[:, :, 0] *= -1 if vflip: # vertical cv2.flip(flow, 0, flow) flow[:, :, 1] *= -1 if rot90: flow = flow.transpose(1, 0, 2) flow = flow[:, :, [1, 0]] return flow if not isinstance(imgs, list): imgs = [imgs] imgs = [_augment(img) for img in imgs] if len(imgs) == 1: imgs = imgs[0] if flows is not None: if not isinstance(flows, list): flows = [flows] flows = [_augment_flow(flow) for flow in flows] if len(flows) == 1: flows = flows[0] return imgs, flows else: if return_status: return imgs, (hflip, vflip, rot90) else: return imgs def img_rotate(img, angle, center=None, scale=1.0): """Rotate image. Args: img (ndarray): Image to be rotated. angle (float): Rotation angle in degrees. Positive values mean counter-clockwise rotation. center (tuple[int]): Rotation center. If the center is None, initialize it as the center of the image. Default: None. scale (float): Isotropic scale factor. Default: 1.0. """ (h, w) = img.shape[:2] if center is None: center = (w // 2, h // 2) matrix = cv2.getRotationMatrix2D(center, angle, scale) rotated_img = cv2.warpAffine(img, matrix, (w, h)) return rotated_img def data_augmentation(image, mode): """ Performs data augmentation of the input image Input: image: a cv2 (OpenCV) image mode: int. Choice of transformation to apply to the image 0 - no transformation 1 - flip up and down 2 - rotate counterwise 90 degree 3 - rotate 90 degree and flip up and down 4 - rotate 180 degree 5 - rotate 180 degree and flip 6 - rotate 270 degree 7 - rotate 270 degree and flip """ if mode == 0: # original out = image elif mode == 1: # flip up and down out = np.flipud(image) elif mode == 2: # rotate counterwise 90 degree out = np.rot90(image) elif mode == 3: # rotate 90 degree and flip up and down out = np.rot90(image) out = np.flipud(out) elif mode == 4: # rotate 180 degree out = np.rot90(image, k=2) elif mode == 5: # rotate 180 degree and flip out = np.rot90(image, k=2) out = np.flipud(out) elif mode == 6: # rotate 270 degree out = np.rot90(image, k=3) elif mode == 7: # rotate 270 degree and flip out = np.rot90(image, k=3) out = np.flipud(out) else: raise Exception('Invalid choice of image transformation') return out def random_augmentation(*args): out = [] flag_aug = random.randint(0,7) for data in args: if type(data) == list: out.append([data_augmentation(_data, flag_aug).copy() for _data in data]) else: out.append(data_augmentation(data, flag_aug).copy()) return out