Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/tensorflow_addons/image/cutout_ops.py: 18%
55 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
1# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15"""Cutout op"""
17import tensorflow as tf
18from tensorflow_addons.utils.types import TensorLike, Number
21@tf.function
22def _norm_params(mask_size, offset=None):
23 tf.assert_equal(
24 tf.reduce_any(mask_size % 2 != 0),
25 False,
26 "mask_size should be divisible by 2",
27 )
28 if tf.rank(mask_size) == 0:
29 mask_size = tf.stack([mask_size, mask_size])
30 if offset is not None and tf.rank(offset) == 1:
31 offset = tf.expand_dims(offset, 0)
32 return mask_size, offset
35@tf.function
36def _random_center(mask_dim_length, image_dim_length, batch_size, seed):
37 if mask_dim_length >= image_dim_length:
38 return tf.tile([image_dim_length // 2], [batch_size])
39 half_mask_dim_length = mask_dim_length // 2
40 return tf.random.uniform(
41 shape=[batch_size],
42 minval=half_mask_dim_length,
43 maxval=image_dim_length - half_mask_dim_length,
44 dtype=tf.int32,
45 seed=seed,
46 )
49def random_cutout(
50 images: TensorLike,
51 mask_size: TensorLike,
52 constant_values: Number = 0,
53 seed: Number = None,
54) -> tf.Tensor:
55 """Apply [cutout](https://arxiv.org/abs/1708.04552) to images with random offset.
57 This operation applies a `(mask_height x mask_width)` mask of zeros to
58 a random location within `images`. The pixel values filled in will be of
59 the value `constant_values`. The location where the mask will be applied is
60 randomly chosen uniformly over the whole images.
62 Args:
63 images: A tensor of shape `(batch_size, height, width, channels)` (NHWC).
64 mask_size: Specifies how big the zero mask that will be generated is that
65 is applied to the images. The mask will be of size
66 `(mask_height x mask_width)`. Note: mask_size should be divisible by 2.
67 constant_values: What pixel value to fill in the images in the area that has
68 the cutout mask applied to it.
69 seed: A Python integer. Used in combination with `tf.random.set_seed` to
70 create a reproducible sequence of tensors across multiple calls.
71 Returns:
72 A `Tensor` of the same shape and dtype as `images`.
73 Raises:
74 InvalidArgumentError: if `mask_size` can't be divisible by 2.
75 """
76 images = tf.convert_to_tensor(images)
77 mask_size = tf.convert_to_tensor(mask_size)
79 image_dynamic_shape = tf.shape(images)
80 batch_size, image_height, image_width = (
81 image_dynamic_shape[0],
82 image_dynamic_shape[1],
83 image_dynamic_shape[2],
84 )
86 mask_size, _ = _norm_params(mask_size, offset=None)
88 cutout_center_height = _random_center(mask_size[0], image_height, batch_size, seed)
89 cutout_center_width = _random_center(mask_size[1], image_width, batch_size, seed)
91 offset = tf.transpose([cutout_center_height, cutout_center_width], [1, 0])
92 return cutout(images, mask_size, offset, constant_values)
95def cutout(
96 images: TensorLike,
97 mask_size: TensorLike,
98 offset: TensorLike = (0, 0),
99 constant_values: Number = 0,
100) -> tf.Tensor:
101 """Apply [cutout](https://arxiv.org/abs/1708.04552) to images.
103 This operation applies a `(mask_height x mask_width)` mask of zeros to
104 a location within `images` specified by the offset.
105 The pixel values filled in will be of the value `constant_values`.
106 The location where the mask will be applied is randomly
107 chosen uniformly over the whole images.
109 Args:
110 images: A tensor of shape `(batch_size, height, width, channels)` (NHWC).
111 mask_size: Specifies how big the zero mask that will be generated is that
112 is applied to the images. The mask will be of size
113 `(mask_height x mask_width)`. Note: mask_size should be divisible by 2.
114 offset: A tuple of `(height, width)` or `(batch_size, 2)`
115 constant_values: What pixel value to fill in the images in the area that has
116 the cutout mask applied to it.
117 Returns:
118 A `Tensor` of the same shape and dtype as `images`.
119 Raises:
120 InvalidArgumentError: if `mask_size` can't be divisible by 2.
121 """
122 with tf.name_scope("cutout"):
123 images = tf.convert_to_tensor(images)
124 mask_size = tf.convert_to_tensor(mask_size)
125 offset = tf.convert_to_tensor(offset)
127 image_static_shape = images.shape
128 image_dynamic_shape = tf.shape(images)
129 image_height, image_width, channels = (
130 image_dynamic_shape[1],
131 image_dynamic_shape[2],
132 image_dynamic_shape[3],
133 )
135 mask_size, offset = _norm_params(mask_size, offset)
136 mask_size = mask_size // 2
138 cutout_center_heights = offset[:, 0]
139 cutout_center_widths = offset[:, 1]
141 lower_pads = tf.maximum(0, cutout_center_heights - mask_size[0])
142 upper_pads = tf.maximum(0, image_height - cutout_center_heights - mask_size[0])
143 left_pads = tf.maximum(0, cutout_center_widths - mask_size[1])
144 right_pads = tf.maximum(0, image_width - cutout_center_widths - mask_size[1])
146 cutout_shape = tf.transpose(
147 [
148 image_height - (lower_pads + upper_pads),
149 image_width - (left_pads + right_pads),
150 ],
151 [1, 0],
152 )
153 padding_dims = tf.stack(
154 [
155 tf.stack([lower_pads, upper_pads], axis=1),
156 tf.stack([left_pads, right_pads], axis=1),
157 ],
158 axis=1,
159 )
160 mask = tf.map_fn(
161 _generate_masks,
162 [cutout_shape, padding_dims],
163 fn_output_signature=tf.TensorSpec(
164 shape=image_static_shape[1:-1], dtype=tf.bool
165 ),
166 )
167 mask = tf.expand_dims(mask, -1)
168 mask = tf.tile(mask, [1, 1, 1, channels])
170 images = tf.where(
171 mask,
172 images,
173 tf.cast(constant_values, dtype=images.dtype),
174 )
175 images.set_shape(image_static_shape)
176 return images
179def _generate_masks(args):
180 cutout_shape, padding_dims = args
181 mask = tf.pad(
182 tf.zeros(cutout_shape, dtype=tf.bool),
183 padding_dims,
184 constant_values=True,
185 )
186 return mask