|
- import tensorflow as tf
- import numpy as np
- from tensorflow.python.ops import math_ops
- from tensorflow.python.ops import array_ops
- from tensorflow.python.framework import ops
- from tensorflow.python.ops.image_ops_impl import _AssertAtLeast3DImage
- from tensorflow.python.framework import dtypes
- from tensorflow.python.ops.image_ops_impl import convert_image_dtype
- import numbers
-
- __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',
- ]
-
-
- 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 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 central_fraction 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
-
- if isinstance(size, numbers.Number):
- target_height = size
- target_width = size
- elif isinstance(size, tuple) or isinstance(size, list):
- if len(size) == 2:
- target_height = size[0]
- target_width = size[1]
- else:
- raise ValueError('The length of size must be 2')
- else:
- raise ValueError("Size should be a single integer or a list/tuple (h, w) of length 2.")
- if target_height > outshape[h_axis] or target_width > outshape[w_axis]:
- raise ValueError("Centralcrop image size must < original image size.")
- central_fraction = max(target_height / outshape[h_axis], target_width / outshape[w_axis])
- else:
- if central_fraction > 1 or central_fraction <= 0:
- raise ValueError('central_fraction must be in (0,1].')
-
- return tf.image.central_crop(image, central_fraction)
-
-
- def HsvToRgb(image):
-
- return tf.image.hsv_to_rgb(image)
-
-
- def AdjustBrightness(image, factor):
-
- return tf.image.adjust_brightness(image, delta=factor)
-
-
- def AdjustContrast(image, factor):
-
- return tf.image.adjust_contrast(image, contrast_factor=factor)
-
-
- def AdjustHue(image, factor):
-
- return tf.image.adjust_hue(image, delta=factor)
-
-
- def AdjustSaturation(image, factor):
-
- return tf.image.adjust_saturation(image, saturation_factor=factor)
-
-
- 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.
-
- Returns:
- Output [batch, target_height, target_width, channels] or [target_height, target_width, channels]
- -------
- '''
-
- return tf.image.crop_to_bounding_box(image, offset_height, offset_width, target_height, target_width)
-
-
- def FlipHorizontal(image):
-
- return tf.image.flip_left_right(image)
-
-
- def FlipVertical(image):
-
- return tf.image.flip_up_down(image)
-
-
- def GrayToRgb(image):
-
- return tf.image.grayscale_to_rgb(image)
-
-
- def RgbToGray(image):
-
- return tf.image.rgb_to_grayscale(image)
-
-
- def PadToBoundingbox(image, offset_height, offset_width, target_height, target_width, padding_value=0, is_hwc=True):
-
- return tf.image.pad_to_bounding_box(
- image,
- offset_height,
- offset_width,
- target_height,
- target_width,
- )
-
-
- def Pad(image, padding, padding_value=0, mode='constant'):
- '''
-
- 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 (top, bottom, left, right) 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.
- -------
-
- '''
- image_shape = image.shape
- if len(image_shape) == 3:
- batch_size = 0
- elif len(image_shape) == 4:
- batch_size = image_shape[0]
- else:
- raise TypeError('Image must be a 3-D tensor or 4-D tensor.')
-
- 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:
- padding = (padding[0], padding[1], (0, 0))
- else:
- padding = ((0, 0), padding[0], padding[1], (0, 0))
-
- return tf.pad(image, padding, mode=mode, constant_values=padding_value)
-
-
- 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 = tf.cast(image, tf.float32)
- with ops.name_scope(None, 'Standardization', [image]) as scope:
- image = ops.convert_to_tensor(image, name='image')
- image = _AssertAtLeast3DImage(image)
-
- orig_dtype = image.dtype
- if orig_dtype not in [dtypes.float16, dtypes.float32]:
- image = convert_image_dtype(image, dtypes.float32)
-
- if mean is not None and std is not None:
- mean = np.array(mean, dtype=np.float32)
- std = np.array(std, dtype=np.float32)
- image -= mean
- image = math_ops.divide(image, std, name=scope)
- return convert_image_dtype(image, orig_dtype, saturate=True)
-
- elif mean is None and std is None:
- if channel_mode:
- num_pixels = math_ops.reduce_prod(array_ops.shape(image)[-3:-1])
- #`num_pixels` is the number of elements in each channels of 'image'
- image_mean = math_ops.reduce_mean(image, axis=[-2, -3], keepdims=True)
- # `image_mean` is the mean of elements in each channels of 'image'
-
- stddev = math_ops.reduce_std(image, axis=[-2, -3], keepdims=True)
- min_stddev = math_ops.rsqrt(math_ops.cast(num_pixels, image.dtype))
- adjusted_sttdev = math_ops.maximum(stddev, min_stddev)
-
- image -= image_mean
- image = math_ops.divide(image, adjusted_sttdev, name=scope)
- return convert_image_dtype(image, orig_dtype, saturate=True)
-
- else:
- num_pixels = math_ops.reduce_prod(array_ops.shape(image)[-3:])
- #`num_pixels` is the number of elements in `image`
- image_mean = math_ops.reduce_mean(image, axis=[-1, -2, -3], keepdims=True)
-
- # Apply a minimum normalization that protects us against uniform images.
- stddev = math_ops.reduce_std(image, axis=[-1, -2, -3], keepdims=True)
- min_stddev = math_ops.rsqrt(math_ops.cast(num_pixels, image.dtype))
- adjusted_stddev = math_ops.maximum(stddev, min_stddev)
-
- image -= image_mean
- image = math_ops.divide(image, adjusted_stddev, name=scope)
- return convert_image_dtype(image, orig_dtype, saturate=True)
- 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).
- -------
-
- '''
-
- return tf.image.random_brightness(image, factor)
-
-
- 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).
- -------
- '''
-
- return tf.image.random_contrast(image, lower, upper, seed)
-
-
- 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.
-
- Returns:
- Adjusted image(s), same shape and DType as `image`.
- -------
-
- '''
-
- return tf.image.random_hue(image, factor, seed)
-
-
- 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 image(s), same shape and DType as `image`.
- -------
- '''
-
- return tf.image.random_saturation(image, lower, upper, seed)
-
-
- def RandomCrop(image, size):
- '''
-
- Parameters
- ----------
- image:
- Input an image to crop.
- size:
- a list or tuple. 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 isinstance(size, int):
- crop_size = (size, size)
- elif isinstance(size, (list, tuple)) and len(size) == 2:
- crop_size = (size[0], size[1])
- else:
- raise ValueError("Size should be a single integer or a list/tuple (h, w) of length 2.")
-
- if len(image.shape) == 3:
- h, w, c = image.shape
- crop_size = crop_size + (c, )
- elif len(image.shape) == 4:
- b, h, w, c = image.shape
- crop_size = (b, ) + crop_size + (c, )
-
- return tf.image.random_crop(image, size=crop_size)
-
-
- 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 shoulid be in
- (bilinear, lanczos3, lanczos5, bicubic, gaussian, nearest, area, mitchellcubic).
- 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
- -------
-
- '''
- if isinstance(size, int):
- size = [size, size]
- elif len(size) != 2:
- raise ValueError('Size should be a single integer or a list/tuple (h, w) of length 2.')
-
- return tf.image.resize(image, size, method, preserve_aspect_ratio, antialias)
-
-
- 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].
- -------
-
- '''
- image_shape = image.shape
- boxes_num = 0
- if isinstance(boxes, tf.Tensor):
- boxes_num = boxes.shape[0]
- elif isinstance(boxes, np.ndarray) or isinstance(boxes, list) or isinstance(boxes, tuple):
- boxes = tf.constant(boxes)
- boxes_num = boxes.shape[0]
-
- if isinstance(crop_size, int):
- crop_size = (crop_size, crop_size)
- crop_size = tf.constant(crop_size)
- elif isinstance(crop_size, np.ndarray) or isinstance(crop_size, list) or isinstance(crop_size, tuple):
- crop_size = tf.constant(crop_size)
-
- if isinstance(box_indices, np.ndarray) or isinstance(box_indices, list) or isinstance(box_indices, tuple):
- box_indices = tf.constant(box_indices)
- # if input is an image.
- # a 3-D Tensor of shape [image_height, image_width, depth] should use 'tf.expand_dims(image, axis = 0)'
- # to convert input to a 4-D Tensor of shape [batch_size,image_height, image_width, depth]
- if len(image_shape) == 3:
- image = tf.expand_dims(image, axis=0)
- box_indices = np.zeros((boxes_num), dtype=np.int)
- box_indices = tf.constant(box_indices)
-
- return tf.image.crop_and_resize(
- image, boxes=boxes, box_indices=box_indices, crop_size=crop_size, method=method,
- extrapolation_value=extrapolation_value
- )
-
-
- 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:
- 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 width.
- Returns:
- Cropped and/or padded image.
- -------
- '''
-
- return tf.image.resize_with_crop_or_pad(image, target_height, target_width)
-
-
- 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].
- -------
-
- '''
-
- return tf.image.resize_with_pad(image, target_height, target_width, method=method, antialias=antialias)
-
-
- def RgbToHsv(image):
-
- return tf.image.rgb_to_hsv(image)
-
-
- def Transpose(image, order):
- image = ops.convert_to_tensor(image)
- image = _AssertAtLeast3DImage(image)
- shape = image.get_shape()
- if shape.ndims == 3 or shape.ndims is None:
- if len(order) != 3:
- raise ValueError('if image is 3-D tensor, order should be a list/tuple with length of 3')
- return array_ops.transpose(image, order)
- elif shape.ndims == 4:
- if len(order) != 4:
- raise ValueError('if image is 4-D tensor, order should be a list/tuple with length of 4')
- return array_ops.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 isinstance(image, tf.Tensor):
- image = np.asarray(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- if is_hwc:
- h, w, c = 0, 1, 2
- else:
- h, w, c = 1, 2, 0
- if fill_mode not in ('constant', 'nearest', 'reflect', 'wrap'):
- raise TypeError('fill_mode must be in (constant, nearest, reflect, wrap)')
-
- image = tf.keras.preprocessing.image.random_rotation(
- image, degrees, h, w, c, fill_mode, fill_value, interpolation_order
- )
- return tf.convert_to_tensor(image)
-
-
- 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 isinstance(image, tf.Tensor):
- image = np.asarray(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.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 number or list/tuple of length 2')
-
- if is_hwc:
- h, w, c = 0, 1, 2
- else:
- h, w, c = 1, 2, 0
- if fill_mode not in ('constant', 'nearest', 'reflect', 'wrap'):
- raise TypeError('fill_mode must be in (constant, nearest, reflect, wrap)')
-
- image = tf.keras.preprocessing.image.random_shift(
- image, wrg=width_fraction, hrg=height_fraction, row_axis=h, col_axis=w, channel_axis=c, fill_mode=fill_mode,
- cval=fill_value, interpolation_order=interpolation_order
- )
-
- return tf.convert_to_tensor(image)
-
-
- def RandomShear(image, degree, fill_mode='nearest', fill_value=0, is_hwc=True, interpolation_order=1):
- '''
-
- Parameters
- ----------
- image
- Input tensor. Must be 3D.
- degree:
- Transformation intensity in degrees.
- 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 isinstance(image, tf.Tensor):
- image = np.asarray(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- if is_hwc:
- h, w, c = 0, 1, 2
- else:
- h, w, c = 1, 2, 0
-
- image = tf.keras.preprocessing.image.random_shear(
- image, intensity=degree, row_axis=h, col_axis=w, channel_axis=c, fill_mode=fill_mode, cval=fill_value,
- interpolation_order=interpolation_order
- )
- return tf.convert_to_tensor(image)
-
-
- 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 isinstance(image, tf.Tensor):
- image = np.asarray(image)
- if not isinstance(image, np.ndarray):
- raise TypeError('img should be NumPy image. Got {}'.format(type(image)))
- if isinstance(zoom_range, numbers.Number):
- zoom_range = (zoom_range, zoom_range)
- elif isinstance(zoom_range, list) or isinstance(zoom_range, tuple):
- if len(zoom_range) == 2:
- zoom_range = (zoom_range[0], zoom_range[1])
- else:
- raise ValueError('shift must be number or list/tuple of length 2')
- if is_hwc:
- h, w, c = 0, 1, 2
- else:
- h, w, c = 1, 2, 0
-
- image = tf.keras.preprocessing.image.random_zoom(
- image, zoom_range=zoom_range, row_axis=h, col_axis=w, channel_axis=c, fill_mode=fill_mode, cval=fill_value,
- interpolation_order=interpolation_order
- )
- return tf.convert_to_tensor(image)
-
-
- 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
- -------
- '''
- image = tf.cast(image, dtype=tf.float32)
- scale = tf.cast(scale, dtype=tf.float32)
- offset = tf.cast(offset, dtype=tf.float32)
- return image * scale + offset
-
-
- def RandomFlipVertical(image):
-
- return tf.image.random_flip_up_down(image)
-
-
- def RandomFlipHorizontal(image):
-
- return tf.image.random_flip_left_right(image)
-
-
- def HWC2CHW(image):
-
- 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 (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.')
|