|
- import numpy as np
- from PIL import Image, ImageOps, ImageEnhance, __version__
- import random
- import colorsys
- import numbers
- import math
- import io
- __all__ = [
- 'CentralCrop',
- 'HsvToRgb',
- 'AdjustBrightness',
- 'AdjustContrast',
- 'AdjustHue',
- 'AdjustSaturation',
- 'Crop',
- 'FlipHorizontal',
- 'FlipVertical',
- 'GrayToRgb',
- 'Standardization',
- 'RgbToGray',
- 'PadToBoundingbox',
- 'Pad',
- 'RandomBrightness',
- 'RandomContrast',
- 'RandomHue',
- 'RandomSaturation',
- 'RandomCrop',
- 'Resize',
- 'CropAndResize',
- 'CropOrPad',
- 'ResizeAndPad',
- 'RgbToHsv',
- 'Transpose',
- 'RandomRotation',
- 'RandomShift',
- 'RandomShear',
- 'RandomZoom',
- 'Rescale',
- 'RandomFlipVertical',
- 'RandomFlipHorizontal',
- 'HWC2CHW',
- 'CHW2HWC',
- ]
-
- augment_error_message = 'img should be PIL image. Got {}.'
-
-
- def ToTensor(image):
-
- image = np.asarray(image).astype(np.float32)
- return image
-
-
- def ToPIL(image):
- """
- Convert the input image to PIL format.
-
- Args:
- img: Image to be converted.
-
- Returns:
- img (PIL image), Converted image.
- """
- return Image.fromarray(np.array(image).astype(np.uint8))
-
-
- def Decode(image):
- """
- Decode the input image to PIL image format in RGB mode.
-
- Args:
- img: Image to be decoded.
-
- Returns:
- img (PIL image), Decoded image in RGB mode.
- """
-
- try:
- data = io.BytesIO(image)
- img = Image.open(data)
- return img.convert('RGB')
- except IOError as e:
- raise ValueError("{0}\nWARNING: Failed to decode given image.".format(e))
- except AttributeError as e:
- raise ValueError("{0}\nWARNING: Failed to decode, Image might already be decoded.".format(e))
-
-
- def Crop(image, offset_height, offset_width, target_height, target_width, is_hwc=True):
- '''
-
- Parameters
- ----------
- image:
- A image or a batch of images
- offset_height:
- Vertical coordinate of the top-left corner of the result in the input.
- offset_width:
- Horizontal coordinate of the top-left corner of the result in the input.
- target_height:
- Height of the result.
- target_width:
- Width of the result.
- is_hwc:
- If is_hwc is True, the order of image channels is [B,H,W,C] or [H,W,C]. If is_hwc is False, the order of image channels is [B,C,H,W] or [C,H,W,]
- Returns:
- Output [batch, target_height, target_width, channels] or [target_height, target_width, channels]
- -------
-
- '''
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- shape_size = len(image.shape)
-
- if not shape_size in (3, 4):
- raise TypeError(
- 'img shape should be (H, W, C)/(N, H, W, C)/(C, H, W)/(N, C, H, W). \
- Got {}'.format(image.shape)
- )
- if shape_size == 3:
- if is_hwc:
- height, width, channels = image.shape
- else:
- channels, height, width = image.shape
- else:
- if is_hwc:
- batch, height, width, channels = image.shape
- else:
- batch, channels, height, width = image.shape
-
- if offset_width < 0:
- raise ValueError('offset_width must be >0.')
- if offset_height < 0:
- raise ValueError('offset_height must be >0.')
- if target_height < 0:
- raise ValueError('target_height must be >0.')
- if target_width < 0:
- raise ValueError('target_width must be >0.')
- if offset_width + target_width > width:
- raise ValueError('offset_width + target_width must be <= image width.')
- if offset_height + target_height > height:
- raise ValueError('offset_height + target_height must be <= image height.')
-
- if shape_size == 3:
- if is_hwc:
- return ToTensor(
- image[offset_height:offset_height + target_height, offset_width:offset_width + target_width, :]
- )
- else:
- return ToTensor(
- image[:, offset_height:offset_height + target_height, offset_width:offset_width + target_width]
- )
- else:
- if is_hwc:
- return ToTensor(
- image[:, offset_height:offset_height + target_height, offset_width:offset_width + target_width, :]
- )
- else:
- return ToTensor(
- image[:, :, offset_height:offset_height + target_height, offset_width:offset_width + target_width]
- )
-
-
- def CentralCrop(image, central_fraction=None, size=None, is_hwc=True):
- '''
-
- Parameters
- ----------
- image :
- input Either a 3-D float Tensor of shape [height, width, depth] or a 4-D Tensor of shape [batch, height, width, depth],
- central_fraction :
- float (0, 1], fraction of size to crop
- size:
- size (Union[int, sequence]) – The output size of the cropped image. If size is an integer, a square crop of size (size, size) is returned.
- If size is a sequence of length 2, it should be (height, width).
- Returns :
- 3-D float Tensor or 4-D float Tensor, as per the input.
- -------
- If backend is tensorflow, central_fraction will be used preferentially. if size is used, the height-width ratio will be equivalent to original ratio..
- If backend is mindspore, size will be used preferentially.
- '''
- if size is None and central_fraction is None:
- raise ValueError('central_fraction and size can not be both None')
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- shape_size = len(image.shape)
- if not shape_size in (3, 4):
- raise TypeError(
- 'img shape should be (H, W, C)/(N, H, W, C)/(C, H, W)/(N, C, H, W). \
- Got {}'.format(image.shape)
- )
-
- if shape_size == 3:
- if is_hwc:
- height, width, channels = image.shape
- else:
- channels, height, width = image.shape
- else:
- if is_hwc:
- batch, height, width, channels = image.shape
- else:
- batch, channels, height, width = image.shape
- if size is None:
- if central_fraction > 1 or central_fraction <= 0:
- raise ValueError('central_fraction must be in (0,1].')
- target_height = int(round(height * central_fraction))
- target_width = int(round(width * central_fraction))
- size = (target_height, target_width)
- if isinstance(size, int):
- size = (size, size)
- crop_height, crop_width = size
- crop_top = int(round((height - crop_height) / 2.))
- crop_left = int(round((width - crop_width) / 2.))
-
- return Crop(image, crop_top, crop_left, crop_height, crop_width, is_hwc)
-
-
- def hsv_to_rgb(np_hsv_img, is_hwc):
- """
- Convert HSV img to RGB img.
-
- Args:
- np_hsv_img (numpy.ndarray): NumPy HSV image array of shape (H, W, C) or (C, H, W) to be converted.
- is_hwc (Bool): If True, the shape of np_hsv_img is (H, W, C), otherwise must be (C, H, W).
-
- Returns:
- np_rgb_img (numpy.ndarray), NumPy HSV image with same shape of np_hsv_img.
- """
- if is_hwc:
- h, s, v = np_hsv_img[:, :, 0], np_hsv_img[:, :, 1], np_hsv_img[:, :, 2]
- else:
- h, s, v = np_hsv_img[0, :, :], np_hsv_img[1, :, :], np_hsv_img[2, :, :]
- to_rgb = np.vectorize(colorsys.hsv_to_rgb)
- r, g, b = to_rgb(h, s, v)
-
- if is_hwc:
- axis = 2
- else:
- axis = 0
- np_rgb_img = np.stack((r, g, b), axis=axis)
- return np_rgb_img
-
-
- def HsvToRgb(image, is_hwc=True):
-
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- shape_size = len(image.shape)
-
- if not shape_size in (3, 4):
- raise TypeError(
- 'img shape should be (H, W, C)/(N, H, W, C)/(C, H, W)/(N, C, H, W). \
- Got {}'.format(image.shape)
- )
- if shape_size == 3:
- batch_size = 0
- if is_hwc:
- num_channels = image.shape[2]
- else:
- num_channels = image.shape[0]
- else:
- batch_size = image.shape[0]
- if is_hwc:
- num_channels = image.shape[3]
- else:
- num_channels = image.shape[1]
-
- if num_channels != 3:
- raise TypeError('img should be 3 channels RGB img. Got {} channels'.format(num_channels))
- if batch_size == 0:
- return hsv_to_rgb(image, is_hwc)
- return ToTensor([hsv_to_rgb(img, is_hwc) for img in image])
-
-
- def AdjustBrightness(image, factor):
- '''
-
- Parameters
- ----------
- image:
- input NumPy image array or PIL image
- factor:
- factor should be in the range (-1,1)
- Returns:
- -------
- np darray image
- '''
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- if factor >= 1 or factor <= -1:
- raise ValueError('factor must be in (-1,1).')
- image = image + factor * 255
- image = np.clip(image, 0, 255)
-
- return ToTensor(image)
-
-
- def AdjustContrast(image, factor):
-
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, np.ndarray):
- image = ToPIL(image)
- if not isinstance(image, Image.Image):
- raise TypeError(augment_error_message.format(type(image)))
-
- image = ImageEnhance.Contrast(image).enhance(factor)
-
- return ToTensor(image)
-
-
- def AdjustHue(image, factor):
-
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, np.ndarray):
- image = ToPIL(image)
- if not isinstance(image, Image.Image):
- raise TypeError(augment_error_message.format(type(image)))
-
- image_hue_factor = factor
- if not -1 <= image_hue_factor <= 1:
- raise ValueError('image_hue_factor {} is not in [-1, 1].'.format(image_hue_factor))
-
- mode = image.mode
- if mode in {'L', '1', 'I', 'F'}:
- return image
-
- hue, saturation, value = image.convert('HSV').split()
-
- np_hue = np.array(hue, dtype=np.uint8)
-
- with np.errstate(over='ignore'):
- np_hue += np.uint8(image_hue_factor * 255)
- hue = Image.fromarray(np_hue, 'L')
-
- image = Image.merge('HSV', (hue, saturation, value)).convert(mode)
-
- return ToTensor(image)
-
-
- def AdjustSaturation(image, factor):
-
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, np.ndarray):
- image = ToPIL(image)
- if not isinstance(image, Image.Image):
- raise TypeError(augment_error_message.format(type(image)))
-
- enhancer = ImageEnhance.Color(image)
- image = enhancer.enhance(factor)
-
- return ToTensor(image)
-
-
- def FlipHorizontal(image):
-
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
-
- image = np.fliplr(image)
-
- return image
-
-
- def FlipVertical(image):
-
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- image = np.flipud(image)
-
- return image
-
-
- def GrayToRgb(image):
-
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- shape = image.shape
- output_image = np.zeros((shape[0], shape[1], 3), dtype=np.uint8)
- if len(shape) == 3:
- for i in range(3):
- output_image[:, :, i] = image[:, :, 1]
- elif len(shape) == 2:
- for i in range(3):
- output_image[:, :, i] = image
-
- return ToTensor(output_image)
-
-
- def RgbToGray(image):
-
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, np.ndarray):
- image = ToPIL(image)
- if not isinstance(image, Image.Image):
- raise TypeError(augment_error_message.format(type(image)))
- '''
- 将彩色图像转换为灰度(模式“L”)时,库使用ITU-R 601-2 Luma转换:
- L = R * 299/1000 + G * 587/1000 + B * 114/1000
- '''
- image = image.convert('L')
- return ToTensor(image)
-
-
- def PadToBoundingbox(image, offset_height, offset_width, target_height, target_width, padding_value=0, is_hwc=True):
- '''
-
- Parameters
- ----------
- image:
- A 3-D numpy ndarray or 4-D numpy ndarray image
- offset_height:
- Number of rows of zeros to add on top.
- offset_width:
- Number of columns of zeros to add on the left.
- target_height:
- Height of output image.
- target_width
- Width of output image.
- Returns
- A numpy ndarray image
- -------
- '''
-
- if offset_height < 0:
- raise ValueError("offset_height must be >= 0")
- if offset_width < 0:
- raise ValueError("offset_width must be >= 0")
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- shape_size = len(image.shape)
- if not shape_size in (3, 4):
- raise TypeError(
- 'img shape should be (H, W, C)/(N, H, W, C)/(C, H, W)/(N, C, H, W). \
- Got {}'.format(image.shape)
- )
- if shape_size == 3:
- if is_hwc:
- height, width, channels = image.shape
- else:
- channels, height, width = image.shape
- else:
- if is_hwc:
- batch, height, width, channels = image.shape
- else:
- batch, channels, height, width = image.shape
- top = offset_height
- bottom = target_height - height - top
- left = offset_width
- right = target_width - width - left
-
- if bottom < 0:
- raise ValueError("target_height must be >= offset_height + height")
-
- if right < 0:
- raise ValueError("target_width must be >= offset_width + width")
-
- if shape_size == 3:
- if is_hwc:
- return ToTensor(
- np.pad(
- image, ((top, bottom), (left, right), (0, 0)), mode='constant',
- constant_values=(padding_value, padding_value)
- )
- )
- else:
- return ToTensor(
- np.pad(
- image, ((0, 0), (top, bottom), (left, right)), mode='constant',
- constant_values=(padding_value, padding_value)
- )
- )
- else:
- if is_hwc:
- return ToTensor(
- np.pad(
- image, ((0, 0), (top, bottom), (left, right), (0, 0)), mode='constant',
- constant_values=(padding_value, padding_value)
- )
- )
- else:
- return ToTensor(
- np.pad(
- image, ((0, 0), (0, 0), (top, bottom), (left, right)), mode='constant',
- constant_values=(padding_value, padding_value)
- )
- )
-
-
- def Pad(image, padding, padding_value=0, mode='constant', is_hwc=True):
- '''
-
- Parameters
- ----------
- image:
- A 3-D or 4-D Tensor.
- padding:
- An integer or a list/tuple. If a single number is provided, pad all borders with this value.
- If a tuple or list of 2 values is provided, pad the left and top with the first value and the right and bottom with the second value.
- If 4 values are provided as a list or tuple, pad the left, top, right and bottom respectively.
- padding_value:
- In "CONSTANT" mode, the scalar pad value to use. Must be same type as tensor.
- mode:
- One of "CONSTANT", "REFLECT", or "SYMMETRIC" (case-insensitive)
- Returns:
- A padded Tensor. Has the same type as tensor.
- -------
-
- '''
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- shape_size = image.shape
- if len(shape_size) == 3:
- batch_size = 0
- elif len(shape_size) == 4:
- batch_size = shape_size[0]
- else:
- raise TypeError(
- 'img shape should be (H, W, C)/(N, H, W, C)/(C, H, W)/(N, C, H, W). \
- Got {}'.format(image.shape)
- )
- if mode not in ('constant', 'edge', 'reflect', 'symmetric'):
- raise TypeError('mode should be one of (constant,edge,reflect,symmetric).')
-
- if isinstance(padding, int):
- padding = ((padding, padding), (padding, padding))
- elif isinstance(padding, list) or isinstance(padding, tuple):
- if len(padding) == 2:
- padding = ((padding[0], padding[0]), (padding[1], padding[1]))
- elif len(padding) == 4:
- padding = ((padding[0], padding[1]), (padding[2], padding[3]))
- else:
- raise ValueError('The length of padding should be 2 or 4, but got {}.'.format(len(padding)))
- else:
- raise TypeError('Padding should be an integer or a list/tuple, but got {}.'.format(type(padding)))
-
- if batch_size == 0:
- if is_hwc:
- padding = (padding[0], padding[1], (0, 0))
- else:
- padding = (
- (0, 0),
- padding[0],
- padding[1],
- )
- else:
- if is_hwc:
- padding = ((0, 0), padding[0], padding[1], (0, 0))
- else:
- padding = ((0, 0), (0, 0), padding[0], padding[1])
- if mode == 'constant':
- return ToTensor(np.pad(image, padding, mode=mode, constant_values=(padding_value, padding_value)))
- else:
- return ToTensor(np.pad(image, padding, mode=mode))
-
-
- def Standardization(image, mean=None, std=None, channel_mode=False, is_hwc=True):
- '''
-
- Parameters
- ----------
- image:
- An n-D Tensor with at least 3 dimensions, the last 3 of which are the dimensions of each image.
- mean:
- List or tuple of mean values for each channel, with respect to channel order.
- std:
- List or tuple of standard deviations for each channel.
- channel_mode:
- Decide to implement standardization on whole image or each channel of image.
- Returns:
- A Tensor with the same shape and dtype as image.
- -------
- '''
-
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image) or isinstance(image, np.ndarray):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- num_shape = image.shape
- if is_hwc:
- height, width, channels = 0, 1, 2
- else:
- channels, height, width = 0, 1, 2
- if mean is not None and std is not None:
- if len(mean) != len(std):
- raise ValueError("Length of mean and std must be equal")
- if len(mean) == 1:
- mean = [mean[0]] * num_shape[channels]
- std = [std[0]] * num_shape[channels]
- mean = np.array(mean, dtype=image.dtype)
- std = np.array(std, dtype=image.dtype)
- return ToTensor((image - mean[:, None, None]) / std[:, None, None])
- elif mean is None and std is None:
- if channel_mode:
- num_pixels = num_shape[height] * num_shape[width]
- image_mean = np.mean(image, axis=(height, width))
- stddev = np.std(image, axis=(height, width))
- min_sttdev = 1 / np.sqrt(num_pixels)
- min_sttdev = [min_sttdev] * num_shape[channels]
- adjusted_sttdev = np.maximum(stddev, min_sttdev)
- image -= image_mean
- image = np.divide(image, adjusted_sttdev)
- return ToTensor(image)
- else:
- num_pixels = num_shape[height] * num_shape[width] * num_shape[channels]
- image_mean = np.mean(image, axis=(0, 1, 2))
- image_mean = [image_mean] * 3
- stddev = np.std(image, axis=(0, 1, 2))
- min_sttdev = 1 / np.sqrt(num_pixels)
- adjusted_sttdev = np.maximum(stddev, min_sttdev)
- adjusted_sttdev = [adjusted_sttdev] * 3
- image -= image_mean
- image = np.divide(image, adjusted_sttdev)
- return ToTensor(image)
- else:
- raise ValueError('std and mean must both be None or not None')
-
-
- def RandomBrightness(image, factor):
- '''
-
- Parameters
- ----------
- image:
- An image or images to adjust
- factor:
- Float, must be non-negative. Factor must be (0,1). Random range will be [-factor, factor).
- Returns:
- The brightness-adjusted image(s).
- -------
-
- '''
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image) or isinstance(image, np.ndarray):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- if factor < 0 or factor > 1:
- raise ValueError('factor should be in [0,1].')
- delta = random.uniform(-factor, factor)
- image = image + delta * 255
- image = np.clip(image, 0, 255)
-
- return image
-
-
- def RandomContrast(image, lower, upper, seed=None):
- '''
-
- Parameters
- ----------
- image:
- An image tensor with 3 or more dimensions.
- lower:
- float. Lower bound for the random contrast factor.
- upper:
- float. Upper bound for the random contrast factor.
- seed:
- A Python integer. Used to create a random seed.
-
- Returns:
- The contrast-adjusted image(s).
- -------
- '''
- if upper <= lower:
- raise ValueError('upper must be > lower')
- if lower < 0:
- raise ValueError('lower must be non-negative')
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, np.ndarray):
- image = ToPIL(image)
- if not isinstance(image, Image.Image):
- raise TypeError(augment_error_message.format(type(image)))
-
- factor = random.uniform(lower, upper)
- image = ImageEnhance.Contrast(image).enhance(factor)
-
- return ToTensor(image)
-
-
- def RandomHue(image, factor, seed=None):
- '''
-
- Parameters
- ----------
- image:
- RGB image or images. The size of the last dimension must be 3.
- factor:
- float. The maximum value for the random factor.
- seed:
- An operation-specific seed. I
-
- Returns:
- Adjusted numpy ndarrry image(s).
- -------
-
- '''
-
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, np.ndarray):
- image = ToPIL(image)
- if not isinstance(image, Image.Image):
- raise TypeError(augment_error_message.format(type(image)))
-
- if factor > 0.5 or factor < 0:
- raise ValueError('factor should be in [0,0.5].')
-
- image_hue_factor = random.uniform(-factor, factor)
- mode = image.mode
- if mode in {'L', '1', 'I', 'F'}:
- return image
-
- hue, saturation, value = image.convert('HSV').split()
-
- np_hue = np.array(hue, dtype=np.uint8)
-
- with np.errstate(over='ignore'):
- np_hue += np.uint8(image_hue_factor * 255)
- hue = Image.fromarray(np_hue, 'L')
-
- image = Image.merge('HSV', (hue, saturation, value)).convert(mode)
-
- return ToTensor(image)
-
-
- def RandomSaturation(image, lower, upper, seed=None):
- '''
- Parameters
- ----------
- image:
- RGB image or images. The size of the last dimension must be 3.
- lower:
- float. Lower bound for the random saturation factor.
- upper:
- float. Upper bound for the random saturation factor.
- seed:
- An operation-specific seed.
-
- Returns;
- Adjusted numpy ndarray image(s).
- -------
- '''
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, np.ndarray):
- image = ToPIL(image)
- if not isinstance(image, Image.Image):
- raise TypeError(augment_error_message.format(type(image)))
- if upper <= lower:
- raise ValueError('upper must be > lower.')
-
- if lower < 0:
- raise ValueError('lower must be non-negative.')
- factor = random.uniform(lower, upper)
- enhancer = ImageEnhance.Color(image)
- image = enhancer.enhance(factor)
-
- return ToTensor(image)
-
-
- def RandomCrop(image, size, is_hwc=True):
- '''
-
- Parameters
- ----------
- image:
- Input an image to crop.
- size:
- if size is an integer, shape of cropped image will be [size, size, 3]. if length of size is 2.
- shape of cropped image will be [height, width, 3].
- Returns:
- A cropped image of the same rank as image and shape size.
- -------
- '''
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image) or isinstance(image, np.ndarray):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- if isinstance(size, int):
- size = (size, size)
- elif isinstance(size, (tuple, list)) and len(size) == 2:
- size = size
- else:
- raise ValueError("Size should be a single integer or a list/tuple (h, w) of length 2.")
-
- def _input_to_factor_(image, size, is_hwc):
- if len(image.shape) == 3:
- if is_hwc:
- height, width, channels = image.shape
- else:
- channels, height, width = image.shape
- else:
- if is_hwc:
- batch, height, width, channels = image.shape
- else:
- batch, channels, height, width = image.shape
-
- target_height, target_width = size
- if target_height > height or target_width > width:
- raise ValueError("Crop size {} is larger than input image size {}".format(size, (height, width)))
- if target_height == height and target_width == width:
- return 0, 0, height, width
-
- top = random.randint(0, height - target_height)
- left = random.randint(0, width - target_width)
- return top, left, target_height, target_width
-
- top, left, height, width = _input_to_factor_(image, size, is_hwc)
-
- return Crop(image, top, left, height, width, is_hwc)
-
-
- def Resize(image, size, method='bilinear', preserve_aspect_ratio=False, antialias=False):
- '''
-
- Parameters
- ----------
- images:
- Input an image to resize
- size:
- if size is an integer, shape of resized image will be [size, size, 3]. if length of size is 2.
- shape of resized image will be [height, width, 3].
- method:
- An image.ResizeMethod, or string equivalent. Defaults to bilinear.
- preserve_aspect_ratio:
- Whether to preserve the aspect ratio.
- antialias:
- Whether to use an anti-aliasing filter when downsampling an image.
- Returns:
- an resized image
- -------
- '''
- DE_PY_INTER_MODE = {
- 'nearest': Image.NEAREST,
- 'bilinear': Image.BILINEAR,
- 'cubic': Image.CUBIC,
- 'lanczos': Image.LANCZOS,
- 'bicubic': Image.BICUBIC
- }
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, np.ndarray):
- image = ToPIL(image)
- if not isinstance(image, Image.Image):
- raise TypeError(augment_error_message.format(type(image)))
- if isinstance(size, int):
- size = (size, size)
- elif isinstance(size, (tuple, list)) or len(size) == 2:
- target_height, target_width = size
- size = (target_width, target_height)
- else:
- raise ValueError("Size should be a single integer or a list/tuple (h, w) of length 2.")
- if method not in ('nearest', 'bilinear', 'cubic', 'lanczos', 'bicubic'):
- raise TypeError('Unknown resize method! resize method must be in (nearest bilinear cubic lanczos bicubic)')
-
- if preserve_aspect_ratio:
- width, height = image.size
- target_width, target_height = size
- scale_factor_height = float(target_height / height)
- scale_factor_width = float(target_width / width)
- scale_factor = np.minimum(scale_factor_height, scale_factor_width)
- new_target_height = int(scale_factor * height)
- new_target_width = int(scale_factor * width)
- size = (new_target_width, new_target_height)
- interpolation = DE_PY_INTER_MODE[method]
- image = image.resize(size, interpolation)
- if antialias:
- image = image.resize(size, Image.ANTIALIAS)
-
- return ToTensor(image)
-
-
- def CropAndResize(image, boxes, box_indices, crop_size, method='bilinear', extrapolation_value=0, is_hwc=True):
- '''
-
- Parameters
- ----------
- image:
- A 4-D tensor of shape [batch, image_height, image_width, depth]. Both image_height and image_width need to be positive.
- boxes:
- A 2-D tensor of shape [num_boxes, 4].
- box_indices:
- A 1-D tensor of shape [num_boxes] with int32 values in [0,batch).
- The value of box_ind[i] specifies the image that the i-th box refers to.
- crop_size:
- A 1-D tensor of 2 elements, size = [crop_height, crop_width]. All cropped image patches are resized to this size.
- The aspect ratio of the image content is not preserved. Both crop_height and crop_width need to be positive.
- method:
- An optional string specifying the sampling method for resizing.
- It can be either "bilinear" or "nearest" and default to "bilinear".
- extrapolation_value:
- An optional float. Defaults to 0. Value used for extrapolation, when applicable.
- Returns:
- A 4-D tensor of shape [num_boxes, crop_height, crop_width, depth].
- -------
-
- '''
- if method not in ["bilinear", "nearest"]:
- raise ValueError('method must be bilinear or nearest.')
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image) or isinstance(image, np.ndarray):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- boxes = np.asarray(boxes)
- box_indices = np.asarray(box_indices)
- image_shape = image.shape
- if len(image_shape) == 4:
- batch_size = image_shape[0]
- elif len(image_shape) == 3:
- image = np.expand_dims(image, axis=0)
- else:
- raise ValueError('Input must be a 3-D or 4-D image Tensor.')
-
- box_num = boxes.shape[0] # boxes.shape is [n,4]. n is the number of boxes.
- if not is_hwc: # 判断通道顺序,为了便于后续计算,将通道顺序调整为HWC or BHWC
- image = np.transpose(image, (0, 2, 3, 1))
- batch_size, height, width, channels = image.shape
- return_image = np.zeros((box_num, crop_size[0], crop_size[1], 3))
- for i in range(box_num):
- y1, x1, y2, x2 = boxes[i] # 首先判断图像是否需要翻转 , 若y1>y2 需要垂直翻转, 若x1>x2 需要水平翻转
- cur_image = image[box_indices[i]]
- if y1 > y2:
- cur_image = FlipVertical(cur_image)
- y1, y2 = y2, y1
- if x1 > x2:
- cur_image = FlipHorizontal(cur_image)
- x1, x2 = x2, x1
- top_padding = 0 if y1 > 0 else int(round(height * (-y1)))
- left_padding = 0 if x1 > 0 else int(round(width * (-x1)))
- bottom_padding = 0 if y2 < 1 else int(round(height * (y2 - 1)))
- right_padding = 0 if x2 < 1 else int(round(width * (x2 - 1)))
- # 判断是否需要padding
- target_height = top_padding + height + bottom_padding
- target_width = left_padding + width + right_padding
- if target_height != height or target_width != width:
- cur_image = PadToBoundingbox(
- cur_image, offset_height=top_padding, offset_width=left_padding, target_height=target_height,
- target_width=target_width, padding_value=extrapolation_value, is_hwc=is_hwc
- )
- offset_height = 0 if y1 < 0 else int(round(height * y1))
- offset_width = 0 if x1 < 0 else int(round(width * x1))
- target_height = int(round(height * (y2 - y1)))
- target_width = int(round(width * (x2 - x1)))
- crop_image = Crop(cur_image, offset_height, offset_width, target_height, target_width, is_hwc)
- resized_image = Resize(crop_image, crop_size, method=method)
- return_image[i] = resized_image
- if not is_hwc:
- return_image = np.transpose(return_image, (0, 3, 1, 2))
- return ToTensor(return_image)
-
-
- def CropOrPad(image, target_height, target_width, is_hwc=True):
- '''
- Resizes an image to a target width and height by either centrally cropping the image or padding it evenly with zeros.
- Parameters
- ----------
- image:
- 3-D Tensor of shape [height, width, channels].
- target_height:
- Target height.
- target_width:
- Target width.
- Returns:
- Cropped and/or padded image.
- -------
- '''
-
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image) or isinstance(image, np.ndarray):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- shape_size = len(image.shape)
- if not shape_size in (3, 4):
- raise TypeError(
- 'img shape should be (H, W, C)/(N, H, W, C)/(C, H, W)/(N, C, H, W). \
- Got {}'.format(image.shape)
- )
- if target_height < 0:
- raise ValueError('target_height must be >0.')
- if target_width < 0:
- raise ValueError('target_width must be >0.')
- if shape_size == 3:
- if is_hwc:
- height, width, channels = image.shape
- else:
- channels, height, width = image.shape
- else:
- if is_hwc:
- batch, height, width, channels = image.shape
- else:
- batch, channels, height, width = image.shape
- offset_height = height - target_height
- offset_width = width - target_width
- offset_crop_height = max(offset_height // 2, 0)
- offset_crop_width = max(offset_width // 2, 0)
- offset_pad_height = max(-offset_height // 2, 0)
- offset_pad_width = max(-offset_width // 2, 0)
- cropped = Crop(
- image, offset_crop_height, offset_crop_width, min(height, target_height), min(width, target_width), is_hwc
- )
-
- padded = PadToBoundingbox(cropped, offset_pad_height, offset_pad_width, target_height, target_width, is_hwc=is_hwc)
-
- return ToTensor(padded)
-
-
- def ResizeAndPad(image, target_height, target_width, method='bilinear', antialias=False, is_hwc=True):
- '''
-
- Parameters
- ----------
- image:
- 4-D Tensor of shape [batch, height, width, channels] or 3-D Tensor of shape [height, width, channels].
- target_height:
- Target height.
- target_width:
- Target height.
- is_hwc:
- The flag of image shape, (H, W, C) or (N, H, W, C) if True and (C, H, W) or (N, C, H, W) if False (default=True).
- Returns:
- Resized and padded image. If images was 4-D, a 4-D float Tensor of shape [batch, new_height, new_width, channels].
- If images was 3-D, a 3-D float Tensor of shape [new_height, new_width, channels].
- -------
-
- '''
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image) or isinstance(image, np.ndarray):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- shape_size = len(image.shape)
- if not shape_size in (3, 4):
- raise TypeError(
- 'img shape should be (H, W, C)/(N, H, W, C)/(C, H, W)/(N, C, H, W). \
- Got {}'.format(image.shape)
- )
- if target_height < 0:
- raise ValueError('target_height must be >0.')
- if target_width < 0:
- raise ValueError('target_width must be >0.')
- if shape_size == 3:
- if is_hwc:
- height, width, channels = image.shape
- else:
- channels, height, width = image.shape
- else:
- if is_hwc:
- batch, height, width, channels = image.shape
- else:
- batch, channels, height, width = image.shape
- height = float(height)
- width = float(width)
- ratio = max(height / target_height, width / target_width)
- resized_height = int(round(height / ratio))
- resized_width = int(round(width / ratio))
- padding_height = max(0, int(round((target_height - resized_height) / 2)))
- padding_width = max(0, int(round((target_width - resized_width) / 2)))
- resized = Resize(
- image, size=(resized_height, resized_width), method=method, antialias=antialias
- ) #需要解决 batch images的resize
- padded = PadToBoundingbox(resized, padding_height, padding_width, target_height, target_width, is_hwc=is_hwc)
- return ToTensor(padded)
-
-
- def rgb_to_hsv(np_rgb_img, is_hwc):
- """
- Convert RGB img to HSV img.
-
- Args:
- np_rgb_img (numpy.ndarray): NumPy RGB image array of shape (H, W, C) or (C, H, W) to be converted.
- is_hwc (Bool): If True, the shape of np_hsv_img is (H, W, C), otherwise must be (C, H, W).
-
- Returns:
- np_hsv_img (numpy.ndarray), NumPy HSV image with same type of np_rgb_img.
- """
- if is_hwc:
- r, g, b = np_rgb_img[:, :, 0], np_rgb_img[:, :, 1], np_rgb_img[:, :, 2]
- else:
- r, g, b = np_rgb_img[0, :, :], np_rgb_img[1, :, :], np_rgb_img[2, :, :]
- to_hsv = np.vectorize(colorsys.rgb_to_hsv)
- h, s, v = to_hsv(r, g, b)
- if is_hwc:
- axis = 2
- else:
- axis = 0
- np_hsv_img = np.stack((h, s, v), axis=axis)
- return np_hsv_img
-
-
- def RgbToHsv(image, is_hwc=True):
-
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image) or isinstance(image, np.ndarray):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
-
- shape_size = len(image.shape)
-
- if not shape_size in (3, 4):
- raise TypeError(
- 'img shape should be (H, W, C)/(N, H, W, C)/(C ,H, W)/(N, C, H, W). \
- Got {}'.format(image.shape)
- )
-
- if shape_size == 3:
- batch_size = 0
- if is_hwc:
- num_channels = image.shape[2]
- else:
- num_channels = image.shape[0]
- else:
- batch_size = image.shape[0]
- if is_hwc:
- num_channels = image.shape[3]
- else:
- num_channels = image.shape[1]
-
- if num_channels != 3:
- raise TypeError('img should be 3 channels RGB img. Got {} channels'.format(num_channels))
- if batch_size == 0:
- return ToTensor(rgb_to_hsv(image, is_hwc))
- return ToTensor([rgb_to_hsv(img, is_hwc) for img in image])
-
-
- def Transpose(image, order):
- """
- Transpose the input image with order
- """
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image) or isinstance(image, np.ndarray):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- if len(image.shape) == 3:
- if len(order) != 3:
- raise ValueError('if image is 3-D tensor, order should be a list/tuple with length of 3')
- return ToTensor(np.transpose(image, order))
- elif len(image.shape) == 4:
- if len(order) != 3:
- raise ValueError('if image is 3-D tensor, order should be a list/tuple with length of 3')
- return ToTensor(np.transpose(image, order))
- else:
- raise ValueError('\'image\' must have either 3 or 4 dimensions.')
-
-
- def RandomRotation(
- image, degrees, fill_mode='nearest', fill_value=0, center=None, expand=False, is_hwc=True, interpolation_order=1
- ):
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, np.ndarray):
- image = ToPIL(image)
- if not isinstance(image, Image.Image):
- raise TypeError(augment_error_message.format(type(image)))
-
- if isinstance(degrees, numbers.Number):
- if degrees < 0:
- raise ValueError("If degrees is a single number, it cannot be negative.")
- degrees = (-degrees, degrees)
- elif isinstance(degrees, (list, tuple)):
- if len(degrees) != 2:
- raise ValueError("If degrees is a sequence, the length must be 2.")
- else:
- raise TypeError("Degrees must be a single non-negative number or a sequence")
-
- DE_PY_INTER_MODE = {
- 'nearest': Image.NEAREST,
- 'bilinear': Image.BILINEAR,
- 'antialias': Image.ANTIALIAS,
- 'bicubic': Image.BICUBIC
- }
- if fill_mode not in ('nearest', 'bilinear', 'antialias', 'bicubic'):
- raise TypeError('Fill_mode must be in (nearest,bilinear, antialias,bicubic)')
-
- if isinstance(fill_value, int):
- fill_value = tuple([fill_value] * 3)
-
- angle = random.uniform(degrees[0], degrees[1])
- fill_mode = DE_PY_INTER_MODE[fill_mode]
- return ToTensor(image.rotate(angle, fill_mode, expand, center, fillcolor=fill_value))
-
-
- def RandomShift(image, shift, fill_mode='nearest', fill_value=0, is_hwc=True, interpolation_order=1):
- '''
-
- Parameters
- ----------
- image
- Input tensor. Must be 3D.
- shift:
- int or list/tuple, if shift is int, Width shift range will equal to height shift range.
- if shift is list/tuple, shift range will be [width fraction, height fraction]
- is_hwc:
- The flag of image shape, (H, W, C) or (N, H, W, C) if True and (C, H, W) or (N, C, H, W) if False (default=True).
- fill_mode:
- Points outside the boundaries of the input are filled according to the given mode (one of {'constant', 'nearest', 'reflect', 'wrap'}).
- fill_value:
- Value used for points outside the boundaries of the input if mode='constant'.
- interpolation_order
- int, order of spline interpolation. see ndimage.interpolation.affine_transform
- Returns
- Shifted Numpy image tensor.
- -------
-
- '''
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, np.ndarray):
- image = ToPIL(image)
- if not isinstance(image, Image.Image):
- raise TypeError(augment_error_message.format(type(image)))
-
- if isinstance(shift, numbers.Number):
- width_fraction = shift
- height_fraction = shift
- elif isinstance(shift, list) or isinstance(shift, tuple):
- if len(shift) == 2:
- width_fraction = shift[0]
- height_fraction = shift[1]
- else:
- raise ValueError('shift must be int or list/tuple of length 2')
-
- DE_PY_INTER_MODE = {'nearest': Image.NEAREST, 'bilinear': Image.BILINEAR, 'bicubic': Image.BICUBIC}
- if fill_mode not in ('nearest', 'bilinear', 'bicubic'):
- raise TypeError('Fill_mode must be in (nearest,bilinear,bicubic)')
- fill_mode = DE_PY_INTER_MODE[fill_mode]
- width, height = image.size
- max_dx = width_fraction * width
- max_dy = height_fraction * height
- translations = (np.round(random.uniform(-max_dx, max_dx)), np.round(random.uniform(-max_dy, max_dy)))
-
- scale = 1.0
- shear = 0.0
- output_size = image.size
- center = (width * 0.5 + 0.5, height * 0.5 + 0.5)
-
- angle = math.radians(0)
- shear = math.radians(shear)
- shear = [shear, 0]
- scale = 1.0 / scale
- d = math.cos(angle + shear[0]) * math.cos(angle + shear[1]) + \
- math.sin(angle + shear[0]) * math.sin(angle + shear[1])
- matrix = [
- math.cos(angle + shear[0]),
- math.sin(angle + shear[0]), 0, -math.sin(angle + shear[1]),
- math.cos(angle + shear[1]), 0
- ]
- matrix = [scale / d * m for m in matrix]
- matrix[2] += matrix[0] * (-center[0] - translations[0]) + matrix[1] * (-center[1] - translations[1])
- matrix[5] += matrix[3] * (-center[0] - translations[0]) + matrix[4] * (-center[1] - translations[1])
-
- # Apply center translation: C * RSS^-1 * C^-1 * T^-1
- matrix[2] += center[0]
- matrix[5] += center[1]
-
- if __version__ >= '5':
- kwargs = {"fillcolor": fill_value}
- else:
- kwargs = {}
- return ToTensor(image.transform(output_size, Image.AFFINE, matrix, fill_mode, **kwargs))
-
-
- def RandomShear(image, degree, fill_mode='nearest', fill_value=0, is_hwc=True, interpolation_order=1):
- '''
-
- Parameters
- ----------
- image
- Input tensor. Must be 3D.
- shift:
- int or list/tuple, if shift is int, Width shift range will equal to height shift range.
- if shift is list/tuple, shift range will be [width fraction, height fraction]
- is_hwc:
- The flag of image shape, (H, W, C) or (N, H, W, C) if True and (C, H, W) or (N, C, H, W) if False (default=True).
- fill_mode:
- Points outside the boundaries of the input are filled according to the given mode (one of {'constant', 'nearest', 'reflect', 'wrap'}).
- fill_value:
- Value used for points outside the boundaries of the input if mode='constant'.
- interpolation_order
- int, order of spline interpolation. see ndimage.interpolation.affine_transform
- Returns
- Shifted Numpy image tensor.
- -------
-
- '''
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, np.ndarray):
- image = ToPIL(image)
- if not isinstance(image, Image.Image):
- raise TypeError(augment_error_message.format(type(image)))
- DE_PY_INTER_MODE = {'nearest': Image.NEAREST, 'bilinear': Image.BILINEAR, 'bicubic': Image.BICUBIC}
- if fill_mode not in ('nearest', 'bilinear', 'bicubic'):
- raise TypeError('Fill_mode must be in (nearest,bilinear,bicubic)')
- fill_mode = DE_PY_INTER_MODE[fill_mode]
- width, height = image.size
- translations = (0, 0)
- scale = 1.0
- shear = degree
- output_size = image.size
- center = (width * 0.5 + 0.5, height * 0.5 + 0.5)
- angle = math.radians(0)
-
- if shear is not None:
- if isinstance(shear, numbers.Number):
- shear = (-1 * shear, shear)
- shear = [random.uniform(shear[0], shear[1]), random.uniform(shear[0], shear[1])]
- elif len(shear) == 2 or len(shear) == 4:
- if len(shear) == 2:
- shear = [shear[0], shear[1], shear[0], shear[1]]
- elif len(shear) == 4:
- shear = [s for s in shear]
- shear = [random.uniform(shear[0], shear[1]), random.uniform(shear[2], shear[3])]
- else:
- raise ValueError(
- "Shear should be a single value or a tuple/list containing " + "two values. Got {}".format(shear)
- )
- shear = [math.radians(s) for s in shear]
- else:
- shear = [0, 0]
-
-
- d = math.cos(angle + shear[0]) * math.cos(angle + shear[1]) + \
- math.sin(angle + shear[0]) * math.sin(angle + shear[1])
- matrix = [
- math.cos(angle + shear[0]),
- math.sin(angle + shear[0]), 0, -math.sin(angle + shear[1]),
- math.cos(angle + shear[1]), 0
- ]
- matrix = [scale / d * m for m in matrix]
- matrix[2] += matrix[0] * (-center[0] - translations[0]) + matrix[1] * (-center[1] - translations[1])
- matrix[5] += matrix[3] * (-center[0] - translations[0]) + matrix[4] * (-center[1] - translations[1])
-
- # Apply center translation: C * RSS^-1 * C^-1 * T^-1
- matrix[2] += center[0]
- matrix[5] += center[1]
-
- if __version__ >= '5':
- kwargs = {"fillcolor": fill_value}
- else:
- kwargs = {}
- return ToTensor(image.transform(output_size, Image.AFFINE, matrix, fill_mode, **kwargs))
-
-
- def RandomZoom(image, zoom_range, fill_mode='nearest', fill_value=0, is_hwc=True, interpolation_order=1):
- '''
-
- Parameters
- ----------
- image:
- Input tensor. Must be 3D.
- zoom_range:
- Tuple of floats; zoom range for width and height.
- is_hwc:
- The flag of image shape, (H, W, C) or (N, H, W, C) if True and (C, H, W) or (N, C, H, W) if False (default=True).
- fill_mode:
- Points outside the boundaries of the input are filled according to the given mode (one of {'constant', 'nearest', 'reflect', 'wrap'}).
- fill_value:
- Value used for points outside the boundaries of the input if mode='constant'.
- interpolation_order:
- int, order of spline interpolation. see ndimage.interpolation.affine_transform
-
- Returns
- Zoomed Numpy image tensor.
- -------
-
- '''
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, np.ndarray):
- image = ToPIL(image)
- if not isinstance(image, Image.Image):
- raise TypeError(augment_error_message.format(type(image)))
- DE_PY_INTER_MODE = {'nearest': Image.NEAREST, 'bilinear': Image.BILINEAR, 'bicubic': Image.BICUBIC}
- if isinstance(zoom_range, list) or isinstance(zoom_range, tuple):
- if len(zoom_range) == 2:
- scale = random.uniform(zoom_range[0], zoom_range[1])
- else:
- raise ValueError('The length of zoom_range must be 2')
- else:
- raise ValueError(
- "Zoom_range should be a single value or a tuple/list containing " + "two values. Got {}".format(zoom_range)
- )
- if fill_mode not in ('nearest', 'bilinear', 'bicubic'):
- raise TypeError('Fill_mode must be in (nearest,bilinear,bicubic)')
- fill_mode = DE_PY_INTER_MODE[fill_mode]
- width, height = image.size
- translations = (0, 0)
- shear = (0, 0)
- output_size = image.size
- center = (width * 0.5 + 0.5, height * 0.5 + 0.5)
- angle = math.radians(0)
-
- d = math.cos(angle + shear[0]) * math.cos(angle + shear[1]) + \
- math.sin(angle + shear[0]) * math.sin(angle + shear[1])
- matrix = [
- math.cos(angle + shear[0]),
- math.sin(angle + shear[0]), 0, -math.sin(angle + shear[1]),
- math.cos(angle + shear[1]), 0
- ]
- matrix = [scale / d * m for m in matrix]
- matrix[2] += matrix[0] * (-center[0] - translations[0]) + matrix[1] * (-center[1] - translations[1])
- matrix[5] += matrix[3] * (-center[0] - translations[0]) + matrix[4] * (-center[1] - translations[1])
-
- # Apply center translation: C * RSS^-1 * C^-1 * T^-1
- matrix[2] += center[0]
- matrix[5] += center[1]
-
- if __version__ >= '5':
- kwargs = {"fillcolor": fill_value}
- else:
- kwargs = {}
- return ToTensor(image.transform(output_size, Image.AFFINE, matrix, fill_mode, **kwargs))
-
-
- def Rescale(image, scale, offset=0):
- '''
-
- Parameters
- ----------
- image:
- 3-D image or 4-D images
- scale:
- Float, the scale to apply to the inputs.
- offset:
- Float, the offset to apply to the inputs.
- Returns:
- rescaled images
- -------
- '''
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image) or isinstance(image, np.ndarray):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
-
- return ToTensor(image * scale + offset)
-
-
- def RandomFlipVertical(image, prob=0.5):
-
- if prob > random.random():
- image = FlipVertical(image)
- return image
-
-
- def RandomFlipHorizontal(image, prob=0.5):
-
- if prob > random.random():
- image = FlipHorizontal(image)
- return image
-
-
- def HWC2CHW(image):
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image) or isinstance(image, np.ndarray):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
-
- image_shape = image.shape
- if (len(image_shape) == 3):
- return Transpose(image, (2, 0, 1))
- elif (len(image_shape) == 4):
- return Transpose(image, (0, 3, 1, 2))
- else:
- raise ValueError('\'image\' must have either 3 or 4 dimensions.')
-
-
- def CHW2HWC(image):
- if not isinstance(image, np.ndarray) and not isinstance(image, Image.Image):
- image = Decode(image)
- if isinstance(image, Image.Image) or isinstance(image, np.ndarray):
- image = ToTensor(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
-
- image_shape = image.shape
- if (len(image_shape) == 3):
- return Transpose(image, (1, 2, 0))
- elif (len(image_shape) == 4):
- return Transpose(image, (0, 2, 3, 1))
- else:
- raise ValueError('\'image\' must have either 3 or 4 dimensions.')
|