1/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2
3Licensed under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License.
5You may obtain a copy of the License at
6
7    http://www.apache.org/licenses/LICENSE-2.0
8
9Unless required by applicable law or agreed to in writing, software
10distributed under the License is distributed on an "AS IS" BASIS,
11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12See the License for the specific language governing permissions and
13limitations under the License.
14==============================================================================*/
15
16#include "tensorflow/core/framework/allocator.h"
17#include "tensorflow/core/framework/fake_input.h"
18#include "tensorflow/core/framework/node_def_builder.h"
19#include "tensorflow/core/framework/op_kernel.h"
20#include "tensorflow/core/framework/tensor.h"
21#include "tensorflow/core/framework/tensor_testutil.h"
22#include "tensorflow/core/framework/types.h"
23#include "tensorflow/core/framework/types.pb.h"
24#include "tensorflow/core/kernels/ops_testutil.h"
25#include "tensorflow/core/kernels/ops_util.h"
26#include "tensorflow/core/lib/core/status_test_util.h"
27#include "tensorflow/core/platform/test.h"
28
29namespace tensorflow {
30
31template <typename T>
32class RGBToHSVOpTest : public OpsTestBase {
33 protected:
34  void MakeOp(DataType data_type) {
35    TF_EXPECT_OK(NodeDefBuilder("rgb_to_hsv_op", "RGBToHSV")
36                     .Input(FakeInput(data_type))
37                     .Finalize(node_def()));
38    TF_EXPECT_OK(InitOp());
39  }
40
41  void CheckBlack(DataType data_type) {
42    // Black pixel should map to hsv = [0,0,0]
43    AddInputFromArray<T>(TensorShape({3}), {0, 0, 0});
44    TF_ASSERT_OK(RunOpKernel());
45
46    Tensor expected(allocator(), data_type, TensorShape({3}));
47    test::FillValues<T>(&expected, {0.0, 0.0, 0.0});
48    test::ExpectTensorEqual<T>(expected, *GetOutput(0));
49  }
50
51  void CheckGray(DataType data_type) {
52    // Gray pixel should have hue = saturation = 0.0, value = r/255
53    AddInputFromArray<T>(TensorShape({3}), {.5, .5, .5});
54    TF_ASSERT_OK(RunOpKernel());
55
56    Tensor expected(allocator(), data_type, TensorShape({3}));
57    test::FillValues<T>(&expected, {0.0, 0.0, .5});
58    test::ExpectTensorEqual<T>(expected, *GetOutput(0));
59  }
60
61  void CheckWhite(DataType data_type) {
62    // Gray pixel should have hue = saturation = 0.0, value = 1.0
63    AddInputFromArray<T>(TensorShape({3}), {1, 1, 1});
64    TF_ASSERT_OK(RunOpKernel());
65
66    Tensor expected(allocator(), data_type, TensorShape({3}));
67    test::FillValues<T>(&expected, {0.0, 0.0, 1.0});
68    test::ExpectTensorEqual<T>(expected, *GetOutput(0));
69  }
70
71  void CheckRedMax(DataType data_type) {
72    // Test case where red channel dominates
73    AddInputFromArray<T>(TensorShape({3}), {.8f, .4f, .2f});
74    TF_ASSERT_OK(RunOpKernel());
75
76    T expected_h = 1. / 6. * .2 / .6;
77    T expected_s = .6 / .8;
78    T expected_v = .8 / 1.;
79
80    Tensor expected(allocator(), data_type, TensorShape({3}));
81    test::FillValues<T>(&expected, {expected_h, expected_s, expected_v});
82    test::ExpectTensorNear<T>(expected, *GetOutput(0), 1e-6);
83  }
84
85  void CheckGreenMax(DataType data_type) {
86    // Test case where green channel dominates
87    AddInputFromArray<T>(TensorShape({3}), {.2f, .8f, .4f});
88    TF_ASSERT_OK(RunOpKernel());
89
90    T expected_h = 1. / 6. * (2.0 + (.2 / .6));
91    T expected_s = .6 / .8;
92    T expected_v = .8 / 1.;
93
94    Tensor expected(allocator(), data_type, TensorShape({3}));
95    test::FillValues<T>(&expected, {expected_h, expected_s, expected_v});
96    test::ExpectTensorNear<T>(expected, *GetOutput(0), 1e-6);
97  }
98
99  void CheckBlueMax(DataType data_type) {
100    // Test case where blue channel dominates
101    AddInputFromArray<T>(TensorShape({3}), {.4f, .2f, .8f});
102    TF_ASSERT_OK(RunOpKernel());
103
104    T expected_h = 1. / 6. * (4.0 + (.2 / .6));
105    T expected_s = .6 / .8;
106    T expected_v = .8 / 1.;
107
108    Tensor expected(allocator(), data_type, TensorShape({3}));
109    test::FillValues<T>(&expected, {expected_h, expected_s, expected_v});
110    test::ExpectTensorNear<T>(expected, *GetOutput(0), 1e-6);
111  }
112
113  void CheckNegativeDifference(DataType data_type) {
114    AddInputFromArray<T>(TensorShape({3}), {0, .1f, .2f});
115    TF_ASSERT_OK(RunOpKernel());
116
117    T expected_h = 1. / 6. * (4.0 + (-.1 / .2));
118    T expected_s = .2 / .2;
119    T expected_v = .2 / 1.;
120
121    Tensor expected(allocator(), data_type, TensorShape({3}));
122    test::FillValues<T>(&expected, {expected_h, expected_s, expected_v});
123    test::ExpectTensorNear<T>(expected, *GetOutput(0), 1e-6);
124  }
125};
126
127template <typename T>
128class HSVToRGBOpTest : public OpsTestBase {
129 protected:
130  void MakeOp(DataType data_type) {
131    TF_EXPECT_OK(NodeDefBuilder("hsv_to_rgb_op", "HSVToRGB")
132                     .Input(FakeInput(data_type))
133                     .Finalize(node_def()));
134    TF_EXPECT_OK(InitOp());
135  }
136
137  void CheckBlack(DataType data_type) {
138    // Black pixel should map to rgb = [0,0,0]
139    AddInputFromArray<T>(TensorShape({3}), {0.0, 0.0, 0.0});
140    TF_ASSERT_OK(RunOpKernel());
141
142    Tensor expected(allocator(), data_type, TensorShape({3}));
143    test::FillValues<T>(&expected, {0, 0, 0});
144    test::ExpectTensorEqual<T>(expected, *GetOutput(0));
145  }
146
147  void CheckGray(DataType data_type) {
148    // Gray pixel should have hue = saturation = 0.0, value = r/255
149    AddInputFromArray<T>(TensorShape({3}), {0.0, 0.0, .5});
150    TF_ASSERT_OK(RunOpKernel());
151
152    Tensor expected(allocator(), data_type, TensorShape({3}));
153    test::FillValues<T>(&expected, {.5, .5, .5});
154    test::ExpectTensorEqual<T>(expected, *GetOutput(0));
155  }
156
157  void CheckWhite(DataType data_type) {
158    // Gray pixel should have hue = saturation = 0.0, value = 1.0
159    AddInputFromArray<T>(TensorShape({3}), {0.0, 0.0, 1.0});
160    TF_ASSERT_OK(RunOpKernel());
161
162    Tensor expected(allocator(), data_type, TensorShape({3}));
163    test::FillValues<T>(&expected, {1, 1, 1});
164    test::ExpectTensorEqual<T>(expected, *GetOutput(0));
165  }
166
167  void CheckRedMax(DataType data_type) {
168    // Test case where red channel dominates
169    T expected_h = 1. / 6. * .2 / .6;
170    T expected_s = .6 / .8;
171    T expected_v = .8 / 1.;
172
173    AddInputFromArray<T>(TensorShape({3}),
174                         {expected_h, expected_s, expected_v});
175    TF_ASSERT_OK(RunOpKernel());
176
177    Tensor expected(allocator(), data_type, TensorShape({3}));
178    test::FillValues<T>(&expected, {.8, .4, .2});
179    test::ExpectTensorNear<T>(expected, *GetOutput(0), 1e-6);
180  }
181
182  void CheckGreenMax(DataType data_type) {
183    // Test case where green channel dominates
184    T expected_h = 1. / 6. * (2.0 + (.2 / .6));
185    T expected_s = .6 / .8;
186    T expected_v = .8 / 1.;
187
188    AddInputFromArray<T>(TensorShape({3}),
189                         {expected_h, expected_s, expected_v});
190    TF_ASSERT_OK(RunOpKernel());
191
192    Tensor expected(allocator(), data_type, TensorShape({3}));
193    test::FillValues<T>(&expected, {.2, .8, .4});
194    test::ExpectTensorNear<T>(expected, *GetOutput(0), 1e-6);
195  }
196
197  void CheckBlueMax(DataType data_type) {
198    // Test case where blue channel dominates
199    T expected_h = 1. / 6. * (4.0 + (.2 / .6));
200    T expected_s = .6 / .8;
201    T expected_v = .8 / 1.0;
202
203    AddInputFromArray<T>(TensorShape({3}),
204                         {expected_h, expected_s, expected_v});
205    TF_ASSERT_OK(RunOpKernel());
206
207    Tensor expected(allocator(), data_type, TensorShape({3}));
208    test::FillValues<T>(&expected, {.4, .2, .8});
209    test::ExpectTensorNear<T>(expected, *GetOutput(0), 1e-6);
210  }
211
212  void CheckNegativeDifference(DataType data_type) {
213    T expected_h = 1. / 6. * (4.0 + (-.1 / .2));
214    T expected_s = .2 / .2;
215    T expected_v = .2 / 1.;
216
217    AddInputFromArray<T>(TensorShape({3}),
218                         {expected_h, expected_s, expected_v});
219    TF_ASSERT_OK(RunOpKernel());
220
221    Tensor expected(allocator(), data_type, TensorShape({3}));
222    test::FillValues<T>(&expected, {0, .1f, .2f});
223    test::ExpectTensorNear<T>(expected, *GetOutput(0), 1e-6);
224  }
225};
226
227#define TEST_COLORSPACE(test, dt)         \
228  TEST_F(test, CheckBlack) {              \
229    MakeOp(dt);                           \
230    CheckBlack(dt);                       \
231  }                                       \
232  TEST_F(test, CheckGray) {               \
233    MakeOp(dt);                           \
234    CheckGray(dt);                        \
235  }                                       \
236  TEST_F(test, CheckWhite) {              \
237    MakeOp(dt);                           \
238    CheckWhite(dt);                       \
239  }                                       \
240  TEST_F(test, CheckRedMax) {             \
241    MakeOp(dt);                           \
242    CheckRedMax(dt);                      \
243  }                                       \
244  TEST_F(test, CheckGreenMax) {           \
245    MakeOp(dt);                           \
246    CheckGreenMax(dt);                    \
247  }                                       \
248  TEST_F(test, CheckBlueMax) {            \
249    MakeOp(dt);                           \
250    CheckBlueMax(dt);                     \
251  }                                       \
252  TEST_F(test, CheckNegativeDifference) { \
253    MakeOp(dt);                           \
254    CheckNegativeDifference(dt);          \
255  }
256
257typedef RGBToHSVOpTest<float> rgb_to_hsv_float;
258typedef RGBToHSVOpTest<double> rgb_to_hsv_double;
259
260TEST_COLORSPACE(rgb_to_hsv_float, DT_FLOAT);
261TEST_COLORSPACE(rgb_to_hsv_double, DT_DOUBLE);
262
263typedef HSVToRGBOpTest<float> hsv_to_rgb_float;
264typedef HSVToRGBOpTest<double> hsv_to_rgb_double;
265
266TEST_COLORSPACE(hsv_to_rgb_float, DT_FLOAT);
267TEST_COLORSPACE(hsv_to_rgb_double, DT_DOUBLE);
268}  // namespace tensorflow
269