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

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.""" 

16 

17from typing import Optional 

18import warnings 

19 

20import tensorflow as tf 

21 

22from tensorflow_addons import options 

23from tensorflow_addons.utils.resource_loader import LazySO 

24from tensorflow_addons.utils.types import Number, TensorLike 

25 

26_distort_image_so = LazySO("custom_ops/image/_distort_image_ops.so") 

27 

28 

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. 

40 

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]`. 

46 

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). 

60 

61 Returns: 

62 3-D float `Tensor` of shape `[height, width, channels]`. 

63 

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.") 

70 

71 if lower_saturation < 0: 

72 raise ValueError("lower_saturation must be non-negative.") 

73 

74 if lower_value < 0: 

75 raise ValueError("lower_value must be non-negative.") 

76 

77 if lower_saturation > upper_saturation: 

78 raise ValueError( 

79 "lower_saturation must be not greater than " "upper_saturation." 

80 ) 

81 

82 if lower_value > upper_value: 

83 raise ValueError("lower_value must be not greater than upper_value.") 

84 

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 ) 

103 

104 

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 

137 

138 image = image @ transform_matrix 

139 return image 

140 

141 

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. 

150 

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. 

156 

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. 

162 

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). 

169 

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) 

179 

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") 

185 

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) 

202 

203 return tf.image.convert_image_dtype(image, orig_dtype)