def __init__(self, pool_size=(2, 2), strides=(2, 2), padding="SAME", **kwargs): super(MaxUnpooling2D, self).__init__(**kwargs) if padding != "SAME" and padding != "VALID": raise ValueError('Padding must be a string from: "SAME", "VALID"') self.pool_size = normalize_tuple(pool_size, 2, "pool_size") self.strides = normalize_tuple(strides, 2, "strides") self.padding = padding
def mean_filter2d( image: TensorLike, filter_shape: Union[List[int], Tuple[int], int] = [3, 3], padding: str = "REFLECT", constant_values: TensorLike = 0, name: Optional[str] = None, ) -> tf.Tensor: """Perform mean filtering on image(s). Args: image: Either a 2-D `Tensor` of shape `[height, width]`, a 3-D `Tensor` of shape `[height, width, channels]`, or a 4-D `Tensor` of shape `[batch_size, height, width, channels]`. filter_shape: An `integer` or `tuple`/`list` of 2 integers, specifying the height and width of the 2-D mean filter. Can be a single integer to specify the same value for all spatial dimensions. padding: A `string`, one of "REFLECT", "CONSTANT", or "SYMMETRIC". The type of padding algorithm to use, which is compatible with `mode` argument in `tf.pad`. For more details, please refer to https://www.tensorflow.org/api_docs/python/tf/pad. constant_values: A `scalar`, the pad value to use in "CONSTANT" padding mode. name: A name for this operation (optional). Returns: 2-D, 3-D or 4-D `Tensor` of the same dtype as input. Raises: ValueError: If `image` is not 2, 3 or 4-dimensional, if `padding` is other than "REFLECT", "CONSTANT" or "SYMMETRIC", or if `filter_shape` is invalid. """ with tf.name_scope(name or "mean_filter2d"): image = tf.convert_to_tensor(image, name="image") original_ndims = img_utils.get_ndims(image) image = img_utils.to_4D_image(image) filter_shape = keras_utils.normalize_tuple(filter_shape, 2, "filter_shape") # Keep the precision if it's float; # otherwise, convert to float32 for computing. orig_dtype = image.dtype if not image.dtype.is_floating: image = tf.dtypes.cast(image, tf.dtypes.float32) # Explicitly pad the image image = _pad(image, filter_shape, mode=padding, constant_values=constant_values) # Filter of shape (filter_width, filter_height, in_channels, 1) # has the value of 1 for each element. area = tf.constant(filter_shape[0] * filter_shape[1], dtype=image.dtype) filter_shape += (tf.shape(image)[-1], 1) kernel = tf.ones(shape=filter_shape, dtype=image.dtype) output = tf.nn.depthwise_conv2d( image, kernel, strides=(1, 1, 1, 1), padding="VALID" ) output /= area output = img_utils.from_4D_image(output, original_ndims) return tf.dtypes.cast(output, orig_dtype)
def __init__( self, output_size: Iterable[int], **kwargs, ): super(MaxUnpooling2DV2, self).__init__(**kwargs) self.output_size = normalize_tuple(output_size, 4, "output_size")
def __init__(self, reduce_function: Callable, output_size: Union[int, Iterable[int]], data_format=None, **kwargs): self.data_format = conv_utils.normalize_data_format(data_format) self.reduce_function = reduce_function self.output_size = conv_utils.normalize_tuple(output_size, 1, "output_size") super().__init__(**kwargs)
def __init__(self, bins: Union[Iterable[int], Iterable[Iterable[int]]], data_format=None, *args, **kwargs): self.bins = [conv_utils.normalize_tuple(bin, 2, "bin") for bin in bins] self.data_format = conv_utils.normalize_data_format(data_format) self.pool_layers = [] for bin in self.bins: self.pool_layers.append( AdaptiveAveragePooling2D(bin, self.data_format)) super().__init__(*args, **kwargs)
def test_normalize_tuple(self): self.assertEqual((2, 2, 2), normalize_tuple(2, n=3, name='strides')) self.assertEqual((2, 1, 2), normalize_tuple((2, 1, 2), n=3, name='strides')) with self.assertRaises(ValueError): normalize_tuple((2, 1), n=3, name='strides') with self.assertRaises(ValueError): normalize_tuple(None, n=3, name='strides')
def test_normalize_tuple(): assert (2, 2, 2) == keras_utils.normalize_tuple(2, n=3, name="strides") assert (2, 1, 2) == keras_utils.normalize_tuple((2, 1, 2), n=3, name="strides") with pytest.raises(ValueError): keras_utils.normalize_tuple((2, 1), n=3, name="strides") with pytest.raises(TypeError): keras_utils.normalize_tuple(None, n=3, name="strides")
def test_normalize_tuple(self): self.assertEqual((2, 2, 2), keras_utils.normalize_tuple(2, n=3, name="strides")) self.assertEqual((2, 1, 2), keras_utils.normalize_tuple((2, 1, 2), n=3, name="strides")) with self.assertRaises(ValueError): keras_utils.normalize_tuple((2, 1), n=3, name="strides") with self.assertRaises(TypeError): keras_utils.normalize_tuple(None, n=3, name="strides")
def median_filter2d(image, filter_shape=(3, 3), padding="REFLECT", constant_values=0, name=None): """Perform median filtering on image(s). Args: image: Either a 2-D `Tensor` of shape `[height, width]`, a 3-D `Tensor` of shape `[height, width, channels]`, or a 4-D `Tensor` of shape `[batch_size, height, width, channels]`. filter_shape: An `integer` or `tuple`/`list` of 2 integers, specifying the height and width of the 2-D median filter. Can be a single integer to specify the same value for all spatial dimensions. padding: A `string`, one of "REFLECT", "CONSTANT", or "SYMMETRIC". The type of padding algorithm to use, which is compatible with `mode` argument in `tf.pad`. For more details, please refer to https://www.tensorflow.org/api_docs/python/tf/pad. constant_values: A `scalar`, the pad value to use in "CONSTANT" padding mode. name: A name for this operation (optional). Returns: 3-D or 4-D `Tensor` of the same dtype as input. Raises: ValueError: If `image` is not 2, 3 or 4-dimensional, if `padding` is other than "REFLECT", "CONSTANT" or "SYMMETRIC", or if `filter_shape` is invalid. """ with tf.name_scope(name or "median_filter2d"): image = tf.convert_to_tensor(image, name="image") original_ndims = img_utils.get_ndims(image) image = img_utils.to_4D_image(image) if padding not in ["REFLECT", "CONSTANT", "SYMMETRIC"]: raise ValueError( "padding should be one of \"REFLECT\", \"CONSTANT\", or " "\"SYMMETRIC\".") filter_shape = keras_utils.normalize_tuple(filter_shape, 2, "filter_shape") image_shape = tf.shape(image) batch_size = image_shape[0] height = image_shape[1] width = image_shape[2] channels = image_shape[3] # Explicitly pad the image image = _pad(image, filter_shape, mode=padding, constant_values=constant_values) area = filter_shape[0] * filter_shape[1] floor = (area + 1) // 2 ceil = area // 2 + 1 patches = tf.image.extract_patches( image, sizes=[1, filter_shape[0], filter_shape[1], 1], strides=[1, 1, 1, 1], rates=[1, 1, 1, 1], padding="VALID") patches = tf.reshape(patches, shape=[batch_size, height, width, area, channels]) patches = tf.transpose(patches, [0, 1, 2, 4, 3]) # Note the returned median is casted back to the original type # Take [5, 6, 7, 8] for example, the median is (6 + 7) / 2 = 3.5 # It turns out to be int(6.5) = 6 if the original type is int top = tf.nn.top_k(patches, k=ceil).values if area % 2 == 1: median = top[:, :, :, :, floor - 1] else: median = (top[:, :, :, :, floor - 1] + top[:, :, :, :, ceil - 1]) / 2 output = tf.cast(median, image.dtype) output = img_utils.from_4D_image(output, original_ndims) return output
def gaussian_filter2d( image: TensorLike, filter_shape: Union[List[int], Tuple[int], int] = [3, 3], sigma: Union[List[float], Tuple[float], float] = 1.0, padding: str = "REFLECT", constant_values: TensorLike = 0, name: Optional[str] = None, ) -> TensorLike: """Perform Gaussian blur on image(s). Args: image: Either a 2-D `Tensor` of shape `[height, width]`, a 3-D `Tensor` of shape `[height, width, channels]`, or a 4-D `Tensor` of shape `[batch_size, height, width, channels]`. filter_shape: An `integer` or `tuple`/`list` of 2 integers, specifying the height and width of the 2-D gaussian filter. Can be a single integer to specify the same value for all spatial dimensions. sigma: A `float` or `tuple`/`list` of 2 floats, specifying the standard deviation in x and y direction the 2-D gaussian filter. Can be a single float to specify the same value for all spatial dimensions. padding: A `string`, one of "REFLECT", "CONSTANT", or "SYMMETRIC". The type of padding algorithm to use, which is compatible with `mode` argument in `tf.pad`. For more details, please refer to https://www.tensorflow.org/api_docs/python/tf/pad. constant_values: A `scalar`, the pad value to use in "CONSTANT" padding mode. name: A name for this operation (optional). Returns: 2-D, 3-D or 4-D `Tensor` of the same dtype as input. Raises: ValueError: If `image` is not 2, 3 or 4-dimensional, if `padding` is other than "REFLECT", "CONSTANT" or "SYMMETRIC", if `filter_shape` is invalid, or if `sigma` is invalid. """ with tf.name_scope(name or "gaussian_filter2d"): if isinstance(sigma, (list, tuple)): if len(sigma) != 2: raise ValueError( "sigma should be a float or a tuple/list of 2 floats") else: sigma = (sigma, ) * 2 if any(s < 0 for s in sigma): raise ValueError("sigma should be greater than or equal to 0.") image = tf.convert_to_tensor(image, name="image") sigma = tf.convert_to_tensor(sigma, name="sigma") original_ndims = img_utils.get_ndims(image) image = img_utils.to_4D_image(image) # Keep the precision if it's float; # otherwise, convert to float32 for computing. orig_dtype = image.dtype if not image.dtype.is_floating: image = tf.cast(image, tf.float32) channels = tf.shape(image)[3] filter_shape = keras_utils.normalize_tuple(filter_shape, 2, "filter_shape") sigma = tf.cast(sigma, image.dtype) gaussian_kernel_x = _get_gaussian_kernel(sigma[1], filter_shape[1]) gaussian_kernel_x = gaussian_kernel_x[tf.newaxis, :] gaussian_kernel_y = _get_gaussian_kernel(sigma[0], filter_shape[0]) gaussian_kernel_y = gaussian_kernel_y[:, tf.newaxis] gaussian_kernel_2d = _get_gaussian_kernel_2d(gaussian_kernel_y, gaussian_kernel_x) gaussian_kernel_2d = gaussian_kernel_2d[:, :, tf.newaxis, tf.newaxis] gaussian_kernel_2d = tf.tile(gaussian_kernel_2d, [1, 1, channels, 1]) image = _pad(image, filter_shape, mode=padding, constant_values=constant_values) output = tf.nn.depthwise_conv2d( input=image, filter=gaussian_kernel_2d, strides=(1, 1, 1, 1), padding="VALID", ) output = img_utils.from_4D_image(output, original_ndims) return tf.cast(output, orig_dtype)
def gaussian_filter2d( image: FloatTensorLike, filter_shape: Union[List[int], Tuple[int]] = [3, 3], sigma: FloatTensorLike = 1, padding: str = "REFLECT", constant_values: TensorLike = 0, name: Optional[str] = None, ) -> FloatTensorLike: """Perform Gaussian blur on image(s). Args: image: Either a 2-D `Tensor` of shape `[height, width]`, a 3-D `Tensor` of shape `[height, width, channels]`, or a 4-D `Tensor` of shape `[batch_size, height, width, channels]`. filter_shape: An `integer` or `tuple`/`list` of 2 integers, specifying the height and width of the 2-D gaussian filter. Can be a single integer to specify the same value for all spatial dimensions. sigma: Standard deviation of Gaussian. padding: A `string`, one of "REFLECT", "CONSTANT", or "SYMMETRIC". The type of padding algorithm to use, which is compatible with `mode` argument in `tf.pad`. For more details, please refer to https://www.tensorflow.org/api_docs/python/tf/pad. constant_values: A `scalar`, the pad value to use in "CONSTANT" padding mode. name: A name for this operation (optional). Returns: 2-D, 3-D or 4-D `Tensor` of the same dtype as input. Raises: ValueError: If `image` is not 2, 3 or 4-dimensional, if `padding` is other than "REFLECT", "CONSTANT" or "SYMMETRIC", if `filter_shape` is invalid, or if `sigma` is less than or equal to 0. """ with tf.name_scope(name or "gaussian_filter2d"): if sigma <= 0: raise ValueError("Sigma should not be zero") if padding not in ["REFLECT", "CONSTANT", "SYMMETRIC"]: raise ValueError( "Padding should be REFLECT, CONSTANT, OR SYMMETRIC") image = tf.cast(image, tf.float32) original_ndims = img_utils.get_ndims(image) image = img_utils.to_4D_image(image) channels = tf.shape(image)[3] filter_shape = keras_utils.normalize_tuple(filter_shape, 2, "filter_shape") gaussian_filter_x = _get_gaussian_kernel(sigma, filter_shape[1]) gaussian_filter_x = tf.cast(gaussian_filter_x, tf.float32) gaussian_filter_x = tf.reshape(gaussian_filter_x, [1, filter_shape[1]]) gaussian_filter_y = _get_gaussian_kernel(sigma, filter_shape[0]) gaussian_filter_y = tf.reshape(gaussian_filter_y, [filter_shape[0], 1]) gaussian_filter_y = tf.cast(gaussian_filter_y, tf.float32) gaussian_filter_2d = _get_gaussian_kernel_2d(gaussian_filter_y, gaussian_filter_x) gaussian_filter_2d = tf.repeat(gaussian_filter_2d, channels) gaussian_filter_2d = tf.reshape( gaussian_filter_2d, [filter_shape[0], filter_shape[1], channels, 1]) image = _pad( image, filter_shape, mode=padding, constant_values=constant_values, ) output = tf.nn.depthwise_conv2d( input=image, filter=gaussian_filter_2d, strides=(1, 1, 1, 1), padding="VALID", ) output = img_utils.from_4D_image(output, original_ndims) return output