| | import numpy |
| | import numpy as np |
| | import torch |
| | import random |
| | import cv2 |
| |
|
| |
|
| | class Scale(object): |
| | """ |
| | Resize the given image to a fixed scale |
| | """ |
| |
|
| | def __init__(self, wi, he): |
| | ''' |
| | :param wi: width after resizing |
| | :param he: height after reszing |
| | ''' |
| | self.w = wi |
| | self.h = he |
| |
|
| | |
| |
|
| | def __call__(self, img, label): |
| | ''' |
| | :param img: RGB image |
| | :param label: semantic label image |
| | :return: resized images |
| | ''' |
| | |
| | img = cv2.resize(img, (self.w, self.h)) |
| | |
| | label = cv2.resize(label, (self.w, self.h), interpolation=cv2.INTER_NEAREST) |
| | return [img, label] |
| |
|
| |
|
| | class Resize(object): |
| | def __init__(self, min_size, max_size, strict=False): |
| | if not isinstance(min_size, (list, tuple)): |
| | min_size = (min_size,) |
| | self.min_size = min_size |
| | self.max_size = max_size |
| | self.strict = strict |
| |
|
| | |
| | def get_size(self, image_size): |
| | w, h = image_size |
| | if not self.strict: |
| | size = random.choice(self.min_size) |
| | max_size = self.max_size |
| | if max_size is not None: |
| | min_original_size = float(min((w, h))) |
| | max_original_size = float(max((w, h))) |
| | if max_original_size / min_original_size * size > max_size: |
| | size = int(round(max_size * min_original_size / max_original_size)) |
| |
|
| | if (w <= h and w == size) or (h <= w and h == size): |
| | return (h, w) |
| |
|
| | if w < h: |
| | ow = size |
| | oh = int(size * h / w) |
| | else: |
| | oh = size |
| | ow = int(size * w / h) |
| |
|
| | return (oh, ow) |
| | else: |
| | if w < h: |
| | return (self.max_size, self.min_size[0]) |
| | else: |
| | return (self.min_size[0], self.max_size) |
| |
|
| | def __call__(self, image, label): |
| | size = self.get_size(image.shape[:2]) |
| | image = cv2.resize(image, size) |
| | |
| | label = cv2.resize(label, size, interpolation=cv2.INTER_NEAREST) |
| | return (image, label) |
| |
|
| |
|
| | class RandomCropResize(object): |
| | """ |
| | Randomly crop and resize the given image with a probability of 0.5 |
| | """ |
| |
|
| | def __init__(self, crop_area): |
| | ''' |
| | :param crop_area: area to be cropped (this is the max value and we select between 0 and crop area |
| | ''' |
| | self.cw = crop_area |
| | self.ch = crop_area |
| |
|
| | def __call__(self, img, label): |
| | if random.random() < 0.5: |
| | h, w = img.shape[:2] |
| | x1 = random.randint(0, self.ch) |
| | y1 = random.randint(0, self.cw) |
| |
|
| | img_crop = img[y1:h - y1, x1:w - x1] |
| | label_crop = label[y1:h - y1, x1:w - x1] |
| |
|
| | img_crop = cv2.resize(img_crop, (w, h)) |
| | label_crop = cv2.resize(label_crop, (w, h), interpolation=cv2.INTER_NEAREST) |
| |
|
| | return img_crop, label_crop |
| | else: |
| | return [img, label] |
| |
|
| |
|
| | class RandomFlip(object): |
| | """ |
| | Randomly flip the given Image with a probability of 0.5 |
| | """ |
| |
|
| | def __call__(self, image, label): |
| | if random.random() < 0.5: |
| | image = cv2.flip(image, 0) |
| | label = cv2.flip(label, 0) |
| | if random.random() < 0.5: |
| | image = cv2.flip(image, 1) |
| | label = cv2.flip(label, 1) |
| | return [image, label] |
| |
|
| |
|
| | class RandomExchange(object): |
| | """ |
| | Randomly flip the given Image with a probability of 0.5 |
| | """ |
| |
|
| | def __call__(self, image, label): |
| | if random.random() < 0.5: |
| | pre_img = image[:, :, 0:3] |
| | post_img = image[:, :, 3:6] |
| | image = numpy.concatenate((post_img, pre_img), axis=2) |
| | return [image, label] |
| |
|
| |
|
| | class Normalize(object): |
| | """ |
| | Given mean: (B, G, R) and std: (B, G, R), |
| | will normalize each channel of the torch.*Tensor, i.e. |
| | channel = (channel - mean) / std |
| | """ |
| |
|
| | def __init__(self, mean, std): |
| | ''' |
| | :param mean: global mean computed from dataset |
| | :param std: global std computed from dataset |
| | ''' |
| | self.mean = mean |
| | self.std = std |
| | self.depth_mean = [0.5] |
| | self.depth_std = [0.5] |
| |
|
| | def __call__(self, image, label): |
| | image = image.astype(np.float32) |
| | image = image / 255 |
| | label = np.ceil(label / 255) |
| | for i in range(6): |
| | image[:, :, i] -= self.mean[i] |
| | for i in range(6): |
| | image[:, :, i] /= self.std[i] |
| |
|
| | return [image, label] |
| |
|
| |
|
| | class GaussianNoise(object): |
| | def __init__(self, std=0.05): |
| | ''' |
| | :param mean: global mean computed from dataset |
| | :param std: global std computed from dataset |
| | ''' |
| | self.std = std |
| |
|
| | def __call__(self, image, label): |
| | noise = np.random.normal(loc=0, scale=self.std, size=image.shape) |
| | image = image + noise.astype(np.float32) |
| | return [image, label] |
| |
|
| |
|
| | class ToTensor(object): |
| | ''' |
| | This class converts the data to tensor so that it can be processed by PyTorch |
| | ''' |
| |
|
| | def __init__(self, scale=1): |
| | ''' |
| | :param scale: set this parameter according to the output scale |
| | ''' |
| | self.scale = scale |
| |
|
| | def __call__(self, image, label): |
| | if self.scale != 1: |
| | h, w = label.shape[:2] |
| | image = cv2.resize(image, (int(w), int(h))) |
| | label = cv2.resize(label, (int(w / self.scale), int(h / self.scale)), \ |
| | interpolation=cv2.INTER_NEAREST) |
| | image = image[:, :, ::-1].copy() |
| | image = image.transpose((2, 0, 1)) |
| | image_tensor = torch.from_numpy(image) |
| | label_tensor = torch.LongTensor(np.array(label, dtype=np.int)).unsqueeze(dim=0) |
| |
|
| | return [image_tensor, label_tensor] |
| |
|
| |
|
| | class Compose(object): |
| | """ |
| | Composes several transforms together. |
| | """ |
| |
|
| | def __init__(self, transforms): |
| | self.transforms = transforms |
| |
|
| | def __call__(self, *args): |
| | for t in self.transforms: |
| | args = t(*args) |
| | return args |
| |
|