import os import random import time import numpy as np from PIL import Image, ImageOps import numbers from torchvision.transforms import Pad,RandomHorizontalFlip from torchvision.transforms import ToTensor, ToPILImage def _is_pil_image(img): return isinstance(img, Image.Image) def crop(img, i, j, h, w): """Crop the given PIL Image. Args: img (PIL Image): Image to be cropped. i: Upper pixel coordinate. j: Left pixel coordinate. h: Height of the cropped image. w: Width of the cropped image. Returns: PIL Image: Cropped image. """ if not _is_pil_image(img): raise TypeError('img should be PIL Image. Got {}'.format(type(img))) return img.crop((j, i, j + w, i + h)) class RandomCrop(object): """Crop the given PIL Image at a random location. Args: size (sequence or int): Desired output size of the crop. If size is an int instead of sequence like (h, w), a square crop (size, size) is made. padding (int or sequence, optional): Optional padding on each border of the image. Default is 0, i.e no padding. If a sequence of length 4 is provided, it is used to pad left, top, right, bottom borders respectively. #对pytorch包内RandomCrop做了修改,可以同时处理image和label,保证为同一区域。 """ def __init__(self, size, padding=0): if isinstance(size, numbers.Number): self.size = (int(size), int(size)) else: self.size = size self.padding = padding @staticmethod def get_params(img, output_size): """Get parameters for ``crop`` for a random crop. Args: img (PIL Image): Image to be cropped. output_size (tuple): Expected output size of the crop. Returns: tuple: params (i, j, h, w) to be passed to ``crop`` for random crop. """ w, h = img.size tw, th = output_size if w == tw and h == th: return 0, 0, h, w i = random.randint(0, h - th) j = random.randint(0, w - tw) return i, j, th, tw def __call__(self, img, label): #crop the same area of ori-image and label """ Args: img (PIL Image): Image to be cropped. Returns: PIL Image: Cropped image. """ if self.padding > 0: img = F.pad(img, self.padding) i, j, h, w = self.get_params(img, self.size) return crop(img, i, j, h, w), crop(label, i, j, h, w) def __repr__(self): return self.__class__.__name__ + '(size={0})'.format(self.size) class RandomFlip(object): """Randomflip the given PIL Image randomly with a given probability. horizontal or vertical Args: p (float): probability of the image being flipped. Default value is 0.5 """ # make sure that crop area of image and label are the same def __init__(self, p=0.5): self.p = p def __call__(self, img, label): """ Args: img (PIL Image): Image to be flipped. Returns: PIL Image: Randomly flipped image. """ if random.random() < self.p: img = img.transpose(Image.FLIP_LEFT_RIGHT) label = label.transpose(Image.FLIP_LEFT_RIGHT) #left or right if random.random() < self.p: img = img.transpose(Image.FLIP_TOP_BOTTOM) label = label.transpose(Image.FLIP_TOP_BOTTOM) # bottom or top return img, label def __repr__(self): return self.__class__.__name__ + '(p={})'.format(self.p) class CenterCrop(object): def __init__(self, size, padding=0): if isinstance(size, numbers.Number): self.size = (int(size), int(size)) else: self.size = size self.padding = padding def __call__(self, img, label): """ Args: img (PIL Image): Image to be cropped. Returns: PIL Image: Cropped image. """ w, h = img.size th, tw = self.size i = int(round((h - th) / 2.)) j = int(round((w - tw) / 2.)) return crop(img, j,i, tw, th), crop(label, j,i, tw, th) def __repr__(self): return self.__class__.__name__ + '(size={0})'.format(self.size) class RandomRotate(object): def __init__(self, degree): self.degree = degree def __call__(self, img, mask): rotate_degree = random.random() * 2 * self.degree - self.degree return img.rotate(rotate_degree, Image.BILINEAR), mask.rotate(rotate_degree, Image.NEAREST)