|
""" |
|
dual augmentation on both images and their masks Script ver: Apr 10th 11:20 |
|
|
|
|
|
""" |
|
import random |
|
import numpy as np |
|
import cv2 |
|
from PIL import Image |
|
from torchvision import transforms |
|
from utils.tools import to_2tuple |
|
|
|
|
|
class DualCompose: |
|
def __init__(self, transforms): |
|
self.transforms = transforms |
|
|
|
def __call__(self, image, mask=None): |
|
|
|
for t in self.transforms: |
|
image, mask = t(image, mask) |
|
|
|
|
|
|
|
|
|
|
|
b, g, r = cv2.split(image) |
|
image = cv2.merge([r, g, b]) |
|
b, g, r = cv2.split(mask) |
|
mask = cv2.merge([r, g, b]) |
|
|
|
return Image.fromarray(np.uint8(image)), Image.fromarray(np.uint8(mask)) |
|
|
|
|
|
class DualImageTransform: |
|
|
|
def __init__(self): |
|
pass |
|
|
|
def __call__(self, image, mask=None): |
|
|
|
b, g, r = cv2.split(image) |
|
image = cv2.merge([r, g, b]) |
|
b, g, r = cv2.split(mask) |
|
mask = cv2.merge([r, g, b]) |
|
|
|
return Image.fromarray(np.uint8(image)), Image.fromarray(np.uint8(mask)) |
|
|
|
|
|
class Dual_RandomHorizontalFlip: |
|
""" |
|
Random horizontal flip. |
|
image shape: (height, width, channels) |
|
mask shape: (height, width) |
|
possibility: possibility for flip |
|
""" |
|
|
|
def __init__(self, possibility=0.5): |
|
assert isinstance(possibility, (int, float)) |
|
self.possibility = possibility |
|
|
|
def __call__(self, image, mask): |
|
if random.random() <= self.possibility: |
|
image = np.flip(image, axis=1) |
|
mask = np.flip(mask, axis=1) |
|
|
|
return image, mask |
|
|
|
|
|
class Dual_RandomVerticalFlip: |
|
""" |
|
Random vertical flip. |
|
image shape: (height, width, channels) |
|
mask shape: (height, width) |
|
possibility: possibility for flip |
|
""" |
|
|
|
def __init__(self, possibility=0.5): |
|
assert isinstance(possibility, (int, float)) |
|
self.possibility = possibility |
|
|
|
def __call__(self, image, mask): |
|
if random.random() <= self.possibility: |
|
image = np.flip(image, axis=0) |
|
mask = np.flip(mask, axis=0) |
|
|
|
return image, mask |
|
|
|
|
|
class Dual_Rotate: |
|
""" |
|
Random rotation. |
|
image shape: (height, width, channels) |
|
mask shape: (height, width) |
|
possibility: possibility for rotate |
|
range: range of rotation angles |
|
""" |
|
|
|
def __init__(self, possibility=0.5, range=20): |
|
self.possibility = possibility |
|
self.range = range |
|
|
|
def __call__(self, image, mask): |
|
|
|
height, width = image.shape[:2] |
|
|
|
if random.random() <= self.possibility: |
|
angle = np.random.randint(0, self.range) |
|
|
|
center = (width // 2, height // 2) |
|
|
|
M = cv2.getRotationMatrix2D(center, -angle, 1) |
|
|
|
image = cv2.warpAffine(image, M, (width, height)) |
|
mask = cv2.warpAffine(mask.astype(np.uint8), M, (width, height)) |
|
|
|
return image.astype(np.uint8), mask.astype(np.int) |
|
|
|
|
|
def Four_step_dual_augmentation(data_augmentation_mode=0, edge_size=384): |
|
""" |
|
Get data augmentation methods |
|
|
|
Dual_transform : Transform CV2 images and their mask by Rotate, RandomHorizontalFlip, etc. |
|
DualImage : Transform CV2 images and their mask to PIL images |
|
train_domain_transform : transforms.ColorJitter on PIL images |
|
transform: PIL crop, resize and to Tensor |
|
|
|
USAGE: |
|
|
|
IN Train: |
|
image, mask = self.Dual_transform(image, mask) |
|
# image color jitter shifting |
|
image = self.train_domain_transform(image) |
|
# crop + resize |
|
image = self.transform(image) |
|
|
|
IN Val $ Test: |
|
|
|
# 0/255 mask -> binary mask |
|
image, mask = self.DualImage(image, mask) |
|
# crop + resize |
|
image = self.transform(image) |
|
""" |
|
|
|
edge_size = to_2tuple(edge_size) |
|
|
|
if data_augmentation_mode == 0: |
|
|
|
Dual_transform = DualCompose([ |
|
Dual_Rotate(possibility=0.8, range=180), |
|
Dual_RandomHorizontalFlip(), |
|
Dual_RandomVerticalFlip(), |
|
]) |
|
|
|
DualImage = DualImageTransform() |
|
|
|
|
|
train_domain_transform = transforms.Compose([ |
|
|
|
transforms.ColorJitter(brightness=0.15, contrast=0.3, saturation=0.3, hue=0.06), |
|
]) |
|
|
|
|
|
transform = transforms.Compose([ |
|
transforms.CenterCrop(700), |
|
transforms.Resize(edge_size), |
|
transforms.ToTensor(), |
|
]) |
|
|
|
elif data_augmentation_mode == 1: |
|
|
|
Dual_transform = DualCompose([ |
|
Dual_Rotate(possibility=0.8, range=180), |
|
Dual_RandomHorizontalFlip(), |
|
Dual_RandomVerticalFlip(), |
|
]) |
|
|
|
DualImage = DualImageTransform() |
|
|
|
|
|
train_domain_transform = transforms.Compose([ |
|
|
|
transforms.ColorJitter(brightness=0.15, contrast=0.3, saturation=0.3, hue=0.06), |
|
]) |
|
|
|
|
|
transform = transforms.Compose([ |
|
transforms.Resize(edge_size), |
|
transforms.ToTensor(), |
|
]) |
|
|
|
elif data_augmentation_mode == 2: |
|
|
|
Dual_transform = DualCompose([ |
|
Dual_Rotate(possibility=0.8, range=180), |
|
Dual_RandomHorizontalFlip(), |
|
Dual_RandomVerticalFlip(), |
|
]) |
|
|
|
DualImage = DualImageTransform() |
|
|
|
|
|
train_domain_transform = transforms.Compose([ |
|
|
|
transforms.ColorJitter(brightness=0.15, contrast=0.3, saturation=0.3, hue=0.06), |
|
]) |
|
|
|
|
|
transform = transforms.Compose([ |
|
transforms.CenterCrop(360), |
|
transforms.Resize(edge_size), |
|
transforms.ToTensor(), |
|
]) |
|
|
|
elif data_augmentation_mode == 3: |
|
|
|
Dual_transform = DualCompose([ |
|
|
|
Dual_RandomHorizontalFlip(), |
|
Dual_RandomVerticalFlip(), |
|
]) |
|
|
|
DualImage = DualImageTransform() |
|
|
|
|
|
train_domain_transform = transforms.Compose([ |
|
|
|
transforms.ColorJitter(brightness=0.15, contrast=0.3, saturation=0.3, hue=0.06), |
|
]) |
|
|
|
|
|
transform = transforms.Compose([ |
|
transforms.Resize(edge_size), |
|
transforms.ToTensor(), |
|
]) |
|
|
|
else: |
|
print('no legal data augmentation is selected') |
|
return -1 |
|
|
|
return Dual_transform, DualImage, train_domain_transform, transform |
|
|