Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/tensorflow_addons/image/distort_image_ops.py: 18%
61 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"""Python layer for distort_image_ops."""
17from typing import Optional
18import warnings
20import tensorflow as tf
22from tensorflow_addons import options
23from tensorflow_addons.utils.resource_loader import LazySO
24from tensorflow_addons.utils.types import Number, TensorLike
26_distort_image_so = LazySO("custom_ops/image/_distort_image_ops.so")
29def random_hsv_in_yiq(
30 image: TensorLike,
31 max_delta_hue: Number = 0,
32 lower_saturation: Number = 1,
33 upper_saturation: Number = 1,
34 lower_value: Number = 1,
35 upper_value: Number = 1,
36 seed: Optional[int] = None,
37 name: Optional[str] = None,
38) -> tf.Tensor:
39 """Adjust hue, saturation, value of an RGB image randomly in YIQ color space.
41 Equivalent to `adjust_yiq_hsv()` but uses a `delta_h` randomly
42 picked in the interval `[-max_delta_hue, max_delta_hue]`, a
43 `scale_saturation` randomly picked in the interval
44 `[lower_saturation, upper_saturation]`, and a `scale_value`
45 randomly picked in the interval `[lower_saturation, upper_saturation]`.
47 Args:
48 image: RGB image or images. Size of the last dimension must be 3.
49 max_delta_hue: `float`. Maximum value for the random delta_hue. Passing 0
50 disables adjusting hue.
51 lower_saturation: `float`. Lower bound for the random scale_saturation.
52 upper_saturation: `float`. Upper bound for the random scale_saturation.
53 lower_value: `float`. Lower bound for the random scale_value.
54 upper_value: `float`. Upper bound for the random scale_value.
55 seed: An operation-specific seed. It will be used in conjunction
56 with the graph-level seed to determine the real seeds that will be
57 used in this operation. Please see the documentation of
58 set_random_seed for its interaction with the graph-level random seed.
59 name: A name for this operation (optional).
61 Returns:
62 3-D float `Tensor` of shape `[height, width, channels]`.
64 Raises:
65 ValueError: if `max_delta`, `lower_saturation`, `upper_saturation`,
66 `lower_value`, or `upper_value` is invalid.
67 """
68 if max_delta_hue < 0:
69 raise ValueError("max_delta must be non-negative.")
71 if lower_saturation < 0:
72 raise ValueError("lower_saturation must be non-negative.")
74 if lower_value < 0:
75 raise ValueError("lower_value must be non-negative.")
77 if lower_saturation > upper_saturation:
78 raise ValueError(
79 "lower_saturation must be not greater than " "upper_saturation."
80 )
82 if lower_value > upper_value:
83 raise ValueError("lower_value must be not greater than upper_value.")
85 with tf.name_scope(name or "random_hsv_in_yiq") as scope:
86 if max_delta_hue == 0:
87 delta_hue = 0
88 else:
89 delta_hue = tf.random.uniform([], -max_delta_hue, max_delta_hue, seed=seed)
90 if lower_saturation == upper_saturation:
91 scale_saturation = lower_saturation
92 else:
93 scale_saturation = tf.random.uniform(
94 [], lower_saturation, upper_saturation, seed=seed
95 )
96 if lower_value == upper_value:
97 scale_value = lower_value
98 else:
99 scale_value = tf.random.uniform([], lower_value, upper_value, seed=seed)
100 return adjust_hsv_in_yiq(
101 image, delta_hue, scale_saturation, scale_value, name=scope
102 )
105def _adjust_hsv_in_yiq(
106 image,
107 delta_hue,
108 scale_saturation,
109 scale_value,
110):
111 if image.shape.rank is not None and image.shape.rank < 3:
112 raise ValueError("input must be at least 3-D.")
113 if image.shape[-1] is not None and image.shape[-1] != 3:
114 raise ValueError(
115 "input must have 3 channels but instead has {}.".format(image.shape[-1])
116 )
117 # Construct hsv linear transformation matrix in YIQ space.
118 # https://beesbuzz.biz/code/hsv_color_transforms.php
119 yiq = tf.constant(
120 [[0.299, 0.596, 0.211], [0.587, -0.274, -0.523], [0.114, -0.322, 0.312]],
121 dtype=image.dtype,
122 )
123 yiq_inverse = tf.constant(
124 [
125 [1.0, 1.0, 1.0],
126 [0.95617069, -0.2726886, -1.103744],
127 [0.62143257, -0.64681324, 1.70062309],
128 ],
129 dtype=image.dtype,
130 )
131 vsu = scale_value * scale_saturation * tf.math.cos(delta_hue)
132 vsw = scale_value * scale_saturation * tf.math.sin(delta_hue)
133 hsv_transform = tf.convert_to_tensor(
134 [[scale_value, 0, 0], [0, vsu, vsw], [0, -vsw, vsu]], dtype=image.dtype
135 )
136 transform_matrix = yiq @ hsv_transform @ yiq_inverse
138 image = image @ transform_matrix
139 return image
142def adjust_hsv_in_yiq(
143 image: TensorLike,
144 delta_hue: Number = 0,
145 scale_saturation: Number = 1,
146 scale_value: Number = 1,
147 name: Optional[str] = None,
148) -> tf.Tensor:
149 """Adjust hue, saturation, value of an RGB image in YIQ color space.
151 This is a convenience method that converts an RGB image to float
152 representation, converts it to YIQ, rotates the color around the
153 Y channel by delta_hue in radians, scales the chrominance channels
154 (I, Q) by scale_saturation, scales all channels (Y, I, Q) by scale_value,
155 converts back to RGB, and then back to the original data type.
157 `image` is an RGB image. The image hue is adjusted by converting the
158 image to YIQ, rotating around the luminance channel (Y) by
159 `delta_hue` in radians, multiplying the chrominance channels (I, Q) by
160 `scale_saturation`, and multiplying all channels (Y, I, Q) by
161 `scale_value`. The image is then converted back to RGB.
163 Args:
164 image: RGB image or images. Size of the last dimension must be 3.
165 delta_hue: `float`, the hue rotation amount, in radians.
166 scale_saturation: `float`, factor to multiply the saturation by.
167 scale_value: `float`, factor to multiply the value by.
168 name: A name for this operation (optional).
170 Returns:
171 Adjusted image(s), same shape and dtype as `image`.
172 """
173 with tf.name_scope(name or "adjust_hsv_in_yiq"):
174 image = tf.convert_to_tensor(image, name="image")
175 # Remember original dtype to so we can convert back if needed
176 orig_dtype = image.dtype
177 if not image.dtype.is_floating:
178 image = tf.image.convert_image_dtype(image, tf.float32)
180 delta_hue = tf.cast(delta_hue, dtype=image.dtype, name="delta_hue")
181 scale_saturation = tf.cast(
182 scale_saturation, dtype=image.dtype, name="scale_saturation"
183 )
184 scale_value = tf.cast(scale_value, dtype=image.dtype, name="scale_value")
186 if not options.is_custom_kernel_disabled():
187 warnings.warn(
188 "C++/CUDA kernel of `adjust_hsv_in_yiq` will be removed in Addons `0.13`.",
189 DeprecationWarning,
190 )
191 try:
192 image = _distort_image_so.ops.addons_adjust_hsv_in_yiq(
193 image, delta_hue, scale_saturation, scale_value
194 )
195 except tf.errors.NotFoundError:
196 options.warn_fallback("adjust_hsv_in_yiq")
197 image = _adjust_hsv_in_yiq(
198 image, delta_hue, scale_saturation, scale_value
199 )
200 else:
201 image = _adjust_hsv_in_yiq(image, delta_hue, scale_saturation, scale_value)
203 return tf.image.convert_image_dtype(image, orig_dtype)