• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2015 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 
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/register_types.h"
21 #include "tensorflow/core/framework/tensor.h"
22 #include "tensorflow/core/framework/tensor_testutil.h"
23 #include "tensorflow/core/framework/tensor_util.h"
24 #include "tensorflow/core/framework/types.h"
25 #include "tensorflow/core/framework/types.pb.h"
26 #include "tensorflow/core/kernels/ops_testutil.h"
27 #include "tensorflow/core/kernels/ops_util.h"
28 #include "tensorflow/core/lib/core/status_test_util.h"
29 #include "tensorflow/core/lib/strings/str_util.h"
30 #include "tensorflow/core/platform/test.h"
31 
32 namespace tensorflow {
33 
34 class CropAndResizeOpTest : public OpsTestBase {
35  protected:
36   template <typename T>
MakeOp(float extrapolation_value,const string & method)37   void MakeOp(float extrapolation_value, const string& method) {
38     TF_EXPECT_OK(NodeDefBuilder("crop_and_resize_op", "CropAndResize")
39                      .Input(FakeInput(DataTypeToEnum<T>::value))
40                      .Input(FakeInput(DT_FLOAT))
41                      .Input(FakeInput(DT_INT32))
42                      .Input(FakeInput(DT_INT32))
43                      .Attr("extrapolation_value", extrapolation_value)
44                      .Attr("method", method)
45                      .Finalize(node_def()));
46     TF_EXPECT_OK(InitOp());
47   }
48 };
49 
50 #define REGISTER_TEST(T)                                               \
51   TEST_F(CropAndResizeOpTest, TestCropAndResize##T) {                  \
52     MakeOp<T>(0, "bilinear");                                          \
53     AddInputFromArray<T>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});     \
54     AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});       \
55     AddInputFromArray<int32>(TensorShape({1}), {0});                   \
56     AddInputFromArray<int32>(TensorShape({2}), {1, 1});                \
57     TF_ASSERT_OK(RunOpKernel());                                       \
58                                                                        \
59     Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 1, 1, 1})); \
60     test::FillValues<float>(&expected, {2.5});                         \
61     test::ExpectTensorEqual<float>(expected, *GetOutput(0));           \
62   }                                                                    \
63                                                                        \
64   TEST_F(CropAndResizeOpTest, TestCropAndResize##T##nearest) {         \
65     MakeOp<T>(0, "nearest");                                           \
66     AddInputFromArray<T>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});     \
67     AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});       \
68     AddInputFromArray<int32>(TensorShape({1}), {0});                   \
69     AddInputFromArray<int32>(TensorShape({2}), {1, 1});                \
70     TF_ASSERT_OK(RunOpKernel());                                       \
71                                                                        \
72     Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 1, 1, 1})); \
73     test::FillValues<float>(&expected, {4.0});                         \
74     test::ExpectTensorEqual<float>(expected, *GetOutput(0));           \
75   }
76 
77 REGISTER_TEST(float)
REGISTER_TEST(double)78 REGISTER_TEST(double)
79 REGISTER_TEST(uint8)
80 REGISTER_TEST(uint16)
81 REGISTER_TEST(int8)
82 REGISTER_TEST(int16)
83 REGISTER_TEST(int32)
84 REGISTER_TEST(int64)
85 
86 #undef REGISTER_TEST
87 
88 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To1x1Uint8) {
89   MakeOp<uint8>(0, "bilinear");
90   // Input:
91   //  1, 2
92   //  3, 4
93   AddInputFromArray<uint8>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
94   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
95   AddInputFromArray<int32>(TensorShape({1}), {0});
96   AddInputFromArray<int32>(TensorShape({2}), {1, 1});
97   TF_ASSERT_OK(RunOpKernel());
98 
99   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 1, 1, 1}));
100   test::FillValues<float>(&expected, {2.5});
101   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
102 }
103 
TEST_F(CropAndResizeOpTest,TestCropAndResize2x2To1x1Uint8NearestNeibor)104 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To1x1Uint8NearestNeibor) {
105   MakeOp<uint8>(0, "nearest");
106   // Input:
107   //  1, 2
108   //  3, 4
109   AddInputFromArray<uint8>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
110   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
111   AddInputFromArray<int32>(TensorShape({1}), {0});
112   AddInputFromArray<int32>(TensorShape({2}), {1, 1});
113   TF_ASSERT_OK(RunOpKernel());
114 
115   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 1, 1, 1}));
116   test::FillValues<float>(&expected, {4.0});
117   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
118 }
119 
TEST_F(CropAndResizeOpTest,TestCropAndResize2x2To1x1Flipped)120 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To1x1Flipped) {
121   MakeOp<float>(0, "bilinear");
122   // Input:
123   //  1, 2
124   //  3, 4
125   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
126   AddInputFromArray<float>(TensorShape({1, 4}), {1, 1, 0, 0});
127   AddInputFromArray<int32>(TensorShape({1}), {0});
128   AddInputFromArray<int32>(TensorShape({2}), {1, 1});
129   TF_ASSERT_OK(RunOpKernel());
130 
131   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 1, 1, 1}));
132   test::FillValues<float>(&expected, {2.5});
133   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
134 }
135 
TEST_F(CropAndResizeOpTest,TestCropAndResize2x2To1x1FlippedNearestNeighbor)136 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To1x1FlippedNearestNeighbor) {
137   MakeOp<float>(0, "nearest");
138   // Input:
139   //  1, 2
140   //  3, 4
141   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
142   AddInputFromArray<float>(TensorShape({1, 4}), {1, 1, 0, 0});
143   AddInputFromArray<int32>(TensorShape({1}), {0});
144   AddInputFromArray<int32>(TensorShape({2}), {1, 1});
145   TF_ASSERT_OK(RunOpKernel());
146 
147   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 1, 1, 1}));
148   test::FillValues<float>(&expected, {4.0});
149   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
150 }
151 
TEST_F(CropAndResizeOpTest,TestCropAndResize2x2To3x3)152 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To3x3) {
153   MakeOp<float>(0, "bilinear");
154   // Input:
155   //  1, 2
156   //  3, 4
157   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
158   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
159   AddInputFromArray<int32>(TensorShape({1}), {0});
160   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
161   TF_ASSERT_OK(RunOpKernel());
162 
163   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));
164   // clang-format off
165   test::FillValues<float>(&expected,
166     {1,  1.5,  2,
167      2,  2.5,  3,
168      3,  3.5,  4});
169   // clang-format on
170   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
171 }
172 
TEST_F(CropAndResizeOpTest,TestCropAndResize2x2To3x3NearestNeighbor)173 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To3x3NearestNeighbor) {
174   MakeOp<float>(0, "nearest");
175   // Input:
176   //  1, 2
177   //  3, 4
178   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
179   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
180   AddInputFromArray<int32>(TensorShape({1}), {0});
181   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
182   TF_ASSERT_OK(RunOpKernel());
183 
184   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));
185   // clang-format off
186   test::FillValues<float>(&expected,
187     {1,  2,  2,
188      3,  4,  4,
189      3,  4,  4});
190   // clang-format on
191   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
192 }
193 
TEST_F(CropAndResizeOpTest,TestCropAndResize2x2To3x3Flipped)194 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To3x3Flipped) {
195   MakeOp<float>(0, "bilinear");
196   // Input:
197   //  1, 2
198   //  3, 4
199   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
200   AddInputFromArray<float>(TensorShape({1, 4}), {1, 1, 0, 0});
201   AddInputFromArray<int32>(TensorShape({1}), {0});
202   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
203   TF_ASSERT_OK(RunOpKernel());
204 
205   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));
206   // clang-format off
207   test::FillValues<float>(&expected,
208     {4,  3.5,  3,
209      3,  2.5,  2,
210      2,  1.5,  1});
211   // clang-format on
212   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
213 }
214 
TEST_F(CropAndResizeOpTest,TestCropAndResize2x2To3x3FlippedNearestNeighbor)215 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To3x3FlippedNearestNeighbor) {
216   MakeOp<float>(0, "nearest");
217   // Input:
218   //  1, 2
219   //  3, 4
220   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
221   AddInputFromArray<float>(TensorShape({1, 4}), {1, 1, 0, 0});
222   AddInputFromArray<int32>(TensorShape({1}), {0});
223   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
224   TF_ASSERT_OK(RunOpKernel());
225 
226   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));
227   // clang-format off
228   test::FillValues<float>(&expected,
229     {4,  4,  3,
230      4,  4,  3,
231      2,  2,  1});
232   // clang-format on
233   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
234 }
235 
TEST_F(CropAndResizeOpTest,TestCropAndResize3x3To2x2)236 TEST_F(CropAndResizeOpTest, TestCropAndResize3x3To2x2) {
237   MakeOp<float>(0, "bilinear");
238   // Input:
239   //  1, 2, 3
240   //  4, 5, 6
241   //  7, 8, 9
242   AddInputFromArray<float>(TensorShape({1, 3, 3, 1}),
243                            {1, 2, 3, 4, 5, 6, 7, 8, 9});
244   AddInputFromArray<float>(TensorShape({2, 4}), {0, 0, 1, 1, 0, 0, 0.5, 0.5});
245   AddInputFromArray<int32>(TensorShape({2}), {0, 0});
246   AddInputFromArray<int32>(TensorShape({2}), {2, 2});
247   TF_ASSERT_OK(RunOpKernel());
248 
249   Tensor expected(allocator(), DT_FLOAT, TensorShape({2, 2, 2, 1}));
250 
251   // clang-format off
252   test::FillValues<float>(&expected,
253     {1,  3,
254      7,  9,
255      1,  2,
256      4,  5});
257   // clang-format on
258   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
259 }
260 
TEST_F(CropAndResizeOpTest,TestCropAndResize3x3To2x2NearestNeighbor)261 TEST_F(CropAndResizeOpTest, TestCropAndResize3x3To2x2NearestNeighbor) {
262   MakeOp<float>(0, "nearest");
263   // Input:
264   //  1, 2, 3
265   //  4, 5, 6
266   //  7, 8, 9
267   AddInputFromArray<float>(TensorShape({1, 3, 3, 1}),
268                            {1, 2, 3, 4, 5, 6, 7, 8, 9});
269   AddInputFromArray<float>(TensorShape({2, 4}), {0, 0, 1, 1, 0, 0, 0.5, 0.5});
270   AddInputFromArray<int32>(TensorShape({2}), {0, 0});
271   AddInputFromArray<int32>(TensorShape({2}), {2, 2});
272   TF_ASSERT_OK(RunOpKernel());
273 
274   Tensor expected(allocator(), DT_FLOAT, TensorShape({2, 2, 2, 1}));
275 
276   // clang-format off
277   test::FillValues<float>(&expected,
278     {1,  3,
279      7,  9,
280      1,  2,
281      4,  5});
282   // clang-format on
283   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
284 }
285 
TEST_F(CropAndResizeOpTest,TestCropAndResize3x3To2x2Flipped)286 TEST_F(CropAndResizeOpTest, TestCropAndResize3x3To2x2Flipped) {
287   MakeOp<float>(0, "bilinear");
288   // Input:
289   //  1, 2, 3
290   //  4, 5, 6
291   //  7, 8, 9
292   AddInputFromArray<float>(TensorShape({1, 3, 3, 1}),
293                            {1, 2, 3, 4, 5, 6, 7, 8, 9});
294   AddInputFromArray<float>(TensorShape({2, 4}), {1, 1, 0, 0, 0.5, 0.5, 0, 0});
295   AddInputFromArray<int32>(TensorShape({2}), {0, 0});
296   AddInputFromArray<int32>(TensorShape({2}), {2, 2});
297   TF_ASSERT_OK(RunOpKernel());
298 
299   Tensor expected(allocator(), DT_FLOAT, TensorShape({2, 2, 2, 1}));
300 
301   // clang-format off
302   test::FillValues<float>(&expected,
303     {9,  7,
304      3,  1,
305      5,  4,
306      2,  1});
307   // clang-format on
308   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
309 }
310 
TEST_F(CropAndResizeOpTest,TestCropAndResize3x3To2x2FlippedNearestNeighbor)311 TEST_F(CropAndResizeOpTest, TestCropAndResize3x3To2x2FlippedNearestNeighbor) {
312   MakeOp<float>(0, "nearest");
313   // Input:
314   //  1, 2, 3
315   //  4, 5, 6
316   //  7, 8, 9
317   AddInputFromArray<float>(TensorShape({1, 3, 3, 1}),
318                            {1, 2, 3, 4, 5, 6, 7, 8, 9});
319   AddInputFromArray<float>(TensorShape({2, 4}), {1, 1, 0, 0, 0.5, 0.5, 0, 0});
320   AddInputFromArray<int32>(TensorShape({2}), {0, 0});
321   AddInputFromArray<int32>(TensorShape({2}), {2, 2});
322   TF_ASSERT_OK(RunOpKernel());
323 
324   Tensor expected(allocator(), DT_FLOAT, TensorShape({2, 2, 2, 1}));
325 
326   // clang-format off
327   test::FillValues<float>(&expected,
328     {9,  7,
329      3,  1,
330      5,  4,
331      2,  1});
332   // clang-format on
333   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
334 }
335 
TEST_F(CropAndResizeOpTest,TestCropAndResize2x2To3x3Extrapolated)336 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To3x3Extrapolated) {
337   const float v = -1;
338   MakeOp<float>(v, "bilinear");
339   // Input:
340   //  1, 2
341   //  3, 4
342   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
343   AddInputFromArray<float>(TensorShape({1, 4}), {-1, -1, 1, 1});
344   AddInputFromArray<int32>(TensorShape({1}), {0});
345   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
346   TF_ASSERT_OK(RunOpKernel());
347 
348   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));
349   // clang-format off
350   test::FillValues<float>(&expected,
351     {v,  v,  v,
352      v,  1,  2,
353      v,  3,  4});
354   // clang-format on
355   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
356 }
357 
TEST_F(CropAndResizeOpTest,TestCropAndResize2x2To3x3NoCrop)358 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To3x3NoCrop) {
359   MakeOp<float>(0, "bilinear");
360   // Input:
361   //  1, 2
362   //  3, 4
363   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
364   AddInputFromArray<float>(TensorShape({0, 4}), {});
365   AddInputFromArray<int32>(TensorShape({0}), {});
366   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
367   TF_ASSERT_OK(RunOpKernel());
368 
369   Tensor expected(allocator(), DT_FLOAT, TensorShape({0, 3, 3, 1}));
370   // clang-format off
371   test::FillValues<float>(&expected, {});
372   // clang-format on
373   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
374 }
375 
TEST_F(CropAndResizeOpTest,TestInvalidInputShape)376 TEST_F(CropAndResizeOpTest, TestInvalidInputShape) {
377   MakeOp<float>(0, "bilinear");
378   AddInputFromArray<float>(TensorShape({2, 2, 1}), {1, 2, 3, 4});
379   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
380   AddInputFromArray<int32>(TensorShape({1}), {0});
381   AddInputFromArray<int32>(TensorShape({2}), {4, 4});
382   Status s = RunOpKernel();
383   ASSERT_FALSE(s.ok());
384   EXPECT_TRUE(absl::StrContains(s.ToString(), "input image must be 4-D")) << s;
385 }
386 
TEST_F(CropAndResizeOpTest,TestInvalidBoxIndexShape)387 TEST_F(CropAndResizeOpTest, TestInvalidBoxIndexShape) {
388   MakeOp<float>(0, "bilinear");
389   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
390   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
391   AddInputFromArray<int32>(TensorShape({2}), {0, 0});
392   AddInputFromArray<int32>(TensorShape({2}), {4, 4});
393   Status s = RunOpKernel();
394   ASSERT_FALSE(s.ok());
395   EXPECT_TRUE(
396       absl::StrContains(s.ToString(), "box_index has incompatible shape"))
397       << s;
398 }
399 
TEST_F(CropAndResizeOpTest,TestInvalidBoxIndex)400 TEST_F(CropAndResizeOpTest, TestInvalidBoxIndex) {
401   MakeOp<float>(0, "bilinear");
402   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
403   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
404   AddInputFromArray<int32>(TensorShape({1}), {1});
405   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
406   Status s = RunOpKernel();
407   ASSERT_FALSE(s.ok());
408   EXPECT_TRUE(absl::StrContains(s.ToString(),
409                                 "box_index has values outside [0, batch_size)"))
410       << s;
411 }
412 
TEST_F(CropAndResizeOpTest,TestWithSharding)413 TEST_F(CropAndResizeOpTest, TestWithSharding) {
414   MakeOp<float>(0, "bilinear");
415   // Generate a relatively large input (999x999) so that sharding happens.
416   const int kLength = 999;  // Length of the input. Must use an odd number.
417   const int kHalf = (kLength + 1) / 2;  // Half size for the cropped result.
418 
419   // Input:
420   //  0, 1, 2, ..., 998
421   //  0, 1, 2, ..., 998
422   //  ... (altogether 999 lines)
423   //  0, 1, 2, ..., 998
424   AddInput<float>(TensorShape({1, kLength, kLength, 1}),
425                   [=](int i) -> float { return i % kLength; });
426   AddInputFromArray<float>(TensorShape({2, 4}),
427                            {0, 0, 0.5, 0.5, 0.5, 0.5, 1, 1});
428   AddInputFromArray<int32>(TensorShape({2}), {0, 0});
429   AddInputFromArray<int32>(TensorShape({2}), {kHalf, kHalf});
430 
431   TF_ASSERT_OK(RunOpKernel());
432 
433   // Generate result tensor.
434   // Result 1:
435   //  0, 1, 2, ..., 499
436   //  ... (altogether 500 lines)
437   //  0, 1, 2, ..., 499
438   Tensor result1(allocator(), DT_FLOAT, TensorShape({1, kHalf, kHalf, 1}));
439   test::FillFn<float>(&result1, [=](int i) -> float { return i % kHalf; });
440 
441   // Result 2:
442   //  499, 500, 501, ..., 998
443   //  ... (altogether 500 lines)
444   //  499, 500, 501, ..., 998
445   Tensor result2(allocator(), DT_FLOAT, TensorShape({1, kHalf, kHalf, 1}));
446   test::FillFn<float>(&result2,
447                       [=](int i) -> float { return i % kHalf + kHalf - 1; });
448 
449   // Expected result is the concat of the two tensors.
450   Tensor expected(allocator(), DT_FLOAT, TensorShape({2, kHalf, kHalf, 1}));
451   TF_ASSERT_OK(tensor::Concat({result1, result2}, &expected));
452 
453   // Compare result.
454   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
455 }
456 
457 }  // namespace tensorflow
458