import mindspore.dataset as ms import mindspore.dataset.vision.c_transforms as c_vision import mindspore.dataset.vision.py_transforms as py_vision import mindspore.dataset.vision.py_transforms_util as py_util import numpy as np from PIL import Image, ImageOps, ImageEnhance, __version__ __all__ = [ 'CentralCrop', 'HsvToRgb', 'AdjustBrightness', 'AdjustContrast', 'AdjustHue', 'Crop', 'FlipHorizontal', 'FlipVertical', 'GrayToRgb', 'RgbToGray', 'PadToBoundingBox' ] augment_error_message = 'img should be PIL image. Got {}. Use Decode() for encoded data or ToPIL() for decoded data.' def CentralCrop(image, central_fraction=None, size=None): ''' Parameters ---------- image : input Either a 3-D float Tensor of shape [height, width, depth], or a 4-D Tensor of shape [batch_size, 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 / 4-D float Tensor, as per the input. ------- ''' if size is None and central_fraction is None: raise ValueError('central_fraction and size can not be both None') if size is None: outshape = np.shape(image) if len(outshape) == 3: h_axis = 0 w_axis = 1 elif len(outshape) == 4: h_axis = 1 w_axis = 2 height = outshape[h_axis] width = outshape[w_axis] target_height = height * central_fraction target_width = width * central_fraction size = (target_height, target_width) return py_util.center_crop(image, size) def HsvToRgb(image, is_hwc=True): image = np.asarray(image) return py_util.hsv_to_rgbs(image, is_hwc=is_hwc) 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 ''' image = np.asarray(image) image = image / 255 image = image + factor index = np.where(image > 1) image[index] = 1 index = np.where(image < 0) image[index] = 0 image = image * 255 return image def AdjustContrast(image, factor): if isinstance(image, np.ndarray): image = Image.fromarray(image) if not isinstance(image, Image.Image): raise TypeError(augment_error_message.format(type(image))) image = ImageEnhance.Contrast(image).enhance(factor) image = np.array(image) return image def AdjustHue(image, factor): if isinstance(image, np.ndarray): image = Image.fromarray(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)) if not isinstance(image, Image.Image): raise TypeError(augment_error_message.format(type(image))) 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 image def AdjustSaturation(image, factor): if isinstance(image, np.ndarray): image = Image.fromarray(image) if not isinstance(image, Image.Image): raise TypeError(augment_error_message.format(type(image))) enhancer = ImageEnhance.Color(image) image = enhancer.enhance(factor) return image def Crop(image, offset_height, offset_width, target_height, target_width): if isinstance(image, np.ndarray): image = Image.fromarray(image) if not isinstance(image, Image.Image): raise TypeError(augment_error_message.format(type(image))) image = np.array( image.crop((offset_width, offset_height, offset_width + target_width, offset_width + target_height)) ) return image def FlipHorizontal(image): if isinstance(image, np.ndarray): image = Image.fromarray(image) if not isinstance(image, Image.Image): raise TypeError(augment_error_message.format(type(image))) image = np.array(image.transpose(Image.FLIP_LEFT_RIGHT)) return image def FlipVertical(image): if isinstance(image, np.ndarray): image = Image.fromarray(image) if not isinstance(image, Image.Image): raise TypeError(augment_error_message.format(type(image))) image = np.array(image.transpose(Image.FLIP_TOP_BOTTOM)) return image def GrayToRgb(image): image = np.asarray(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 output_image def RgbToGray(image): if isinstance(image, np.ndarray): image = Image.fromarray(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') image = np.asarray(image) return image def PadToBoundingBox(image, offset_height, offset_width, target_height, target_width): ''' Parameters ---------- image: A PIL 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") image = np.array(image) shape = image.shape top = offset_height bottom = target_height - shape[0] - top left = offset_width right = target_width - shape[1] - 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") return np.pad(image, ((top, bottom), (left, right), (0, 0)), mode='constant') def Standardization(image, mean=None, std=None, channel_mode=False): ''' 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. ------- ''' image = np.array(image, dtype=np.float32) num_shape = image.shape 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[2] std = [std[0]] * num_shape[2] mean = np.array(mean, dtype=image.dtype) std = np.array(std, dtype=image.dtype) return (image - mean[:, None, None]) / std[:, None, None] elif mean is None and std is None: if channel_mode: num_pixels = num_shape[0] * num_shape[1] image_mean = np.mean(image, axis=(0, 1)) stddev = np.std(image, axis=(0, 1)) min_sttdev = 1 / np.sqrt(num_pixels) min_sttdev = [min_sttdev] * num_shape[2] adjusted_sttdev = np.maximum(stddev, min_sttdev) image -= image_mean image = np.divide(image, adjusted_sttdev) return image else: num_pixels = num_shape[0] * num_shape[1] * num_shape[2] 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 image else: raise ValueError('std and mean must both be None or not None')