|
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: |
|
cv2.flip(img, 1, img) |
|
if vflip: |
|
cv2.flip(img, 0, img) |
|
if rot90: |
|
img = img.transpose(1, 0, 2) |
|
return img |
|
|
|
def _augment_flow(flow): |
|
if hflip: |
|
cv2.flip(flow, 1, flow) |
|
flow[:, :, 0] *= -1 |
|
if vflip: |
|
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: |
|
|
|
out = image |
|
elif mode == 1: |
|
|
|
out = np.flipud(image) |
|
elif mode == 2: |
|
|
|
out = np.rot90(image) |
|
elif mode == 3: |
|
|
|
out = np.rot90(image) |
|
out = np.flipud(out) |
|
elif mode == 4: |
|
|
|
out = np.rot90(image, k=2) |
|
elif mode == 5: |
|
|
|
out = np.rot90(image, k=2) |
|
out = np.flipud(out) |
|
elif mode == 6: |
|
|
|
out = np.rot90(image, k=3) |
|
elif mode == 7: |
|
|
|
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 |
|
|