image_ops_test.cc revision 9d56f419cf3a92fb4c66943f216d3632c940b9db
1/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
2
3Licensed under the Apache License, Version 2.0 (the "License");
4
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/node_def_builder.h"
17#include "tensorflow/core/framework/op.h"
18#include "tensorflow/core/framework/shape_inference_testutil.h"
19#include "tensorflow/core/framework/tensor_testutil.h"
20#include "tensorflow/core/lib/core/status_test_util.h"
21#include "tensorflow/core/platform/test.h"
22
23namespace tensorflow {
24
25TEST(ImageOpsTest, SampleDistortedBoundingBox_ShapeFn) {
26  ShapeInferenceTestOp op("SampleDistortedBoundingBox");
27  INFER_OK(op, "?;?", "[3];[3];[1,1,4]");
28}
29
30TEST(ImageOpsTest, Resize_ShapeFn) {
31  for (const char* op_name : {"ResizeArea", "ResizeBicubic", "ResizeBilinear",
32                              "ResizeNearestNeighbor"}) {
33    ShapeInferenceTestOp op(op_name);
34    op.input_tensors.resize(2);
35
36    // Inputs are images and size.
37
38    // Rank and size checks.
39    INFER_ERROR("Shape must be rank 4 but is rank 5", op, "[1,2,3,4,5];?");
40    INFER_ERROR("Shape must be rank 4 but is rank 3", op, "[1,2,3];?");
41    INFER_ERROR("Shape must be rank 1 but is rank 0", op, "?;[]");
42    INFER_ERROR("Dimension must be 2 but is 3", op, "?;[3]");
43
44    // When the size tensor is not a constant, the middle dims are unknown.
45    INFER_OK(op, "[1,?,3,?];[2]", "[d0_0,?,?,d0_3]");
46
47    Tensor size_tensor = test::AsTensor<int32>({20, 30});
48    op.input_tensors[1] = &size_tensor;
49    INFER_OK(op, "[1,?,3,?];[2]", "[d0_0,20,30,d0_3]");
50  }
51}
52
53TEST(ImageOpsTest, DecodeGif) {
54  ShapeInferenceTestOp op("DecodeGif");
55
56  // Rank check.
57  INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1]");
58
59  // Output is always ?,?,?,3.
60  INFER_OK(op, "?", "[?,?,?,3]");
61  INFER_OK(op, "[]", "[?,?,?,3]");
62}
63
64TEST(ImageOpsTest, DecodeImage_ShapeFn) {
65  for (const char* op_name : {"DecodeJpeg", "DecodePng"}) {
66    ShapeInferenceTestOp op(op_name);
67
68    // Rank check.
69    INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1]");
70
71    // Set the channel to zero - output is not known.
72    TF_ASSERT_OK(NodeDefBuilder("test", op_name)
73                     .Input({"a", 0, DT_STRING})
74                     .Finalize(&op.node_def));
75    INFER_OK(op, "[]", "[?,?,?]");
76
77    // Set the channel and so that part of output shape is known.
78    TF_ASSERT_OK(NodeDefBuilder("test", op_name)
79                     .Input({"a", 0, DT_STRING})
80                     .Attr("channels", 4)
81                     .Finalize(&op.node_def));
82    INFER_OK(op, "[]", "[?,?,4]");
83
84    // Negative channel value is rejected.
85    TF_ASSERT_OK(NodeDefBuilder("test", op_name)
86                     .Input({"a", 0, DT_STRING})
87                     .Attr("channels", -1)
88                     .Finalize(&op.node_def));
89    INFER_ERROR("channels must be non-negative, got -1", op, "[]");
90  }
91}
92
93TEST(ImageOpsTest, DecodeAndCropJpeg_ShapeFn) {
94  const char* op_name = "DecodeAndCropJpeg";
95  ShapeInferenceTestOp op(op_name);
96
97  // Check the number of inputs.
98  INFER_ERROR("Wrong number of inputs passed: 1 while 2 expected", op, "[1]");
99
100  // Rank check.
101  INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1];?");
102
103  // Set the channel to zero - output is not known.
104  TF_ASSERT_OK(NodeDefBuilder("test", op_name)
105                   .Input({"img", 0, DT_STRING})
106                   .Input({"crop_window", 1, DT_INT32})
107                   .Finalize(&op.node_def));
108  INFER_OK(op, "[];[]", "[?,?,?]");
109
110  // Set the channel, so that part of output shape is known.
111  TF_ASSERT_OK(NodeDefBuilder("test", op_name)
112                   .Input({"img", 0, DT_STRING})
113                   .Input({"crop_window", 1, DT_INT32})
114                   .Attr("channels", 4)
115                   .Finalize(&op.node_def));
116  INFER_OK(op, "[];[]", "[?,?,4]");
117
118  // Negative channel value is rejected.
119  TF_ASSERT_OK(NodeDefBuilder("test", op_name)
120                   .Input({"img", 0, DT_STRING})
121                   .Input({"crop_window", 1, DT_INT32})
122                   .Attr("channels", -1)
123                   .Finalize(&op.node_def));
124  INFER_ERROR("channels must be non-negative, got -1", op, "[];[]");
125}
126
127TEST(ImageOpsTest, DecodeAndCropJpeg_InvalidCropWindow) {
128  const char* op_name = "DecodeAndCropJpeg";
129  ShapeInferenceTestOp op(op_name);
130
131  // Check the number of inputs.
132  INFER_ERROR("Wrong number of inputs passed: 1 while 2 expected", op, "[1]");
133
134  // Rank check.
135  INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1];?");
136
137  // Set the channel to zero - output is not known.
138  TF_ASSERT_OK(NodeDefBuilder("test", op_name)
139                   .Input({"img", 0, DT_STRING})
140                   .Input({"crop_window", 1, DT_INT32})
141                   .Finalize(&op.node_def));
142  INFER_OK(op, "[];[]", "[?,?,?]");
143}
144
145TEST(ImageOpsTest, EncodeImage_ShapeFn) {
146  for (const char* op_name : {"EncodeJpeg", "EncodePng"}) {
147    ShapeInferenceTestOp op(op_name);
148
149    // Rank check.
150    INFER_ERROR("Shape must be rank 3 but is rank 2", op, "[1,2]");
151
152    INFER_OK(op, "[1,?,3]", "[]");  // output is always scalar.
153  }
154}
155
156TEST(ImageOpsTest, ExtractJpegShape_ShapeFn) {
157  ShapeInferenceTestOp op("ExtractJpegShape");
158
159  // Rank check.
160  INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1]");
161
162  // Only specify input data. Output must be a 1-D tensor with 3 elements.
163  INFER_OK(op, "?", "[3]");
164}
165
166TEST(ImageOpsTest, Colorspace_ShapeFn) {
167  for (const char* op_name : {"HSVToRGB", "RGBToHSV"}) {
168    ShapeInferenceTestOp op(op_name);
169
170    // Rank check.
171    INFER_ERROR("Shape must be at least rank 1 but is rank 0", op, "[]");
172
173    // Input's last dim is required to be 3.
174    INFER_ERROR("Dimension must be 3 but is 4", op, "[1,2,4]");
175    INFER_OK(op, "[1,2,3]", "[d0_0,d0_1,d0_2]");
176    INFER_OK(op, "[1,2,?]", "[d0_0,d0_1,3]");
177    INFER_OK(op, "?", "?");
178  }
179}
180
181TEST(ImageOpsTest, ExtractGlimpse_ShapeFn) {
182  ShapeInferenceTestOp op("ExtractGlimpse");
183  op.input_tensors.resize(2);
184
185  // Inputs are input, size, offsets.
186
187  // Rank and size checks.
188  INFER_ERROR("Shape must be rank 4 but is rank 5", op, "[1,2,3,4,5];?;?");
189  INFER_ERROR("Shape must be rank 4 but is rank 3", op, "[1,2,3];?;?");
190  INFER_ERROR("Shape must be rank 1 but is rank 0", op, "?;[];?");
191  INFER_ERROR("Dimension must be 2 but is 3", op, "?;[3];?");
192  INFER_ERROR("Shape must be rank 2 but is rank 3", op, "?;?;[1,2,3]");
193
194  // When the size tensor is not a constant, the middle dims are unknown.
195  INFER_OK(op, "[1,?,3,?];[2];?", "[d0_0,?,?,d0_3]");
196
197  Tensor size_tensor = test::AsTensor<int32>({20, 30});
198  op.input_tensors[1] = &size_tensor;
199  INFER_OK(op, "[1,?,3,?];[2];?", "[d0_0,20,30,d0_3]");
200
201  // input.dim(0) and offsets.dim(0) are both the batch dimension.
202  INFER_OK(op, "[?,?,3,?];[2];[1,?]", "[d2_0,20,30,d0_3]");
203  INFER_OK(op, "[1,?,3,?];[2];[1,?]", "[d0_0|d2_0,20,30,d_0|d0_3]");
204  INFER_ERROR("Dimensions must be equal, but are 10 and 1", op,
205              "[10,?,?,?];?;[1,2]");
206}
207
208TEST(ImageOpsTest, CropAndResize_ShapeFn) {
209  ShapeInferenceTestOp op("CropAndResize");
210  op.input_tensors.resize(4);
211
212  // Inputs are:  input, boxes, box_ind, and crop_size.
213
214  // Rank and size checks.
215  INFER_ERROR("Shape must be rank 4 but is rank 5", op, "[1,2,3,4,5];?;?;?");
216  INFER_ERROR("Shape must be rank 4 but is rank 3", op, "[1,2,3];?;?;?");
217  INFER_ERROR("Shape must be rank 2 but is rank 3", op, "?;[1,2,3];?;?");
218  INFER_ERROR("Shape must be rank 1 but is rank 2", op, "?;?;[1,2];?");
219  INFER_ERROR("Shape must be rank 1 but is rank 2", op, "?;?;?;[1,2]");
220  INFER_ERROR("Dimension must be 2 but is 1", op, "?;?;?;[1]");
221
222  // When the size tensor is not a constant, the middle dims are unknown.
223  INFER_OK(op, "[1,?,3,?];?;?;[2]", "[?,?,?,d0_3]");
224
225  Tensor size_tensor = test::AsTensor<int32>({20, 30});
226  op.input_tensors[3] = &size_tensor;
227  INFER_OK(op, "[1,?,3,?];?;?;[2]", "[?,20,30,d0_3]");
228
229  // boxes.dim(0) and box_ind.dim(0) are both the num_boxes dim.
230  INFER_OK(op, "[1,?,3,?];[2,4];?;[2]", "[d1_0,20,30,d0_3]");
231  INFER_OK(op, "[1,?,3,?];?;[2];[2]", "[d2_0,20,30,d0_3]");
232  INFER_OK(op, "[1,?,3,?];[?,4];[?];[2]", "[d1_0|d3_0,20,30,d0_3]");
233  INFER_ERROR("Dimensions must be equal, but are 2 and 1", op, "?;[2,?];[1];?");
234
235  // boxes.dim(1) must be 4.
236  INFER_ERROR("Dimension must be 4 but is 3", op, "?;[?,3];?;?");
237}
238
239TEST(ImageOpsTest, ResizeNearestNeighborGrad_ShapeFn) {
240  ShapeInferenceTestOp op("ResizeNearestNeighborGrad");
241  op.input_tensors.resize(2);
242
243  // Rank and size checks.
244  INFER_ERROR("Shape must be rank 4 but is rank 3", op, "[1,2,3];?");
245  INFER_ERROR("Shape must be rank 1 but is rank 2", op, "?;[1,2]")
246  INFER_ERROR("Dimension must be 2 but is 1", op, "?;[1]");
247
248  // When the size tensor is not a constant, the middle dims are unknown.
249  INFER_OK(op, "[1,?,3,?];[2]", "[d0_0,?,?,d0_3]");
250
251  Tensor size_tensor = test::AsTensor<int32>({20, 30});
252  op.input_tensors[1] = &size_tensor;
253  INFER_OK(op, "[1,?,3,?];[2]", "[d0_0,20,30,d0_3]");
254}
255
256TEST(ImageOpsTest, CropAndResizeGradImage_ShapeFn) {
257  ShapeInferenceTestOp op("CropAndResizeGradImage");
258  op.input_tensors.resize(4);
259
260  // Rank checks.
261  INFER_ERROR("Shape must be rank 1 but is rank 2", op, "?;?;?;[1,2]");
262
263  // Unknown image_size should result in output of rank 4 with unknown dims.
264  INFER_OK(op, "?;?;?;?", "[?,?,?,?]");
265
266  // Known image_size should result in full shape information.
267  Tensor image_size = test::AsTensor<int32>({10, 20, 30, 40});
268  op.input_tensors[3] = &image_size;
269  INFER_OK(op, "?;?;?;[1]", "[10, 20, 30, 40]");
270}
271
272TEST(ImageOpsTest, RandomCrop_ShapeFn) {
273  ShapeInferenceTestOp op("RandomCrop");
274  op.input_tensors.resize(2);
275
276  // Rank checks.
277  INFER_ERROR("must be rank 3", op, "[1,2];?");
278  INFER_ERROR("must be equal", op, "?;[3]");
279  INFER_ERROR("must be equal", op, "?;[1,2]");
280
281  // Unknown size tensor values.
282  INFER_OK(op, "[?,?,?];[2]", "[?,?,d0_2]");
283
284  // Known size should result in full shape information.
285  Tensor size = test::AsTensor<int64>({10, 20});
286  op.input_tensors[1] = &size;
287  INFER_OK(op, "[?,?,?];[2]", "[10,20,d0_2]");
288}
289
290TEST(ImageOpsTest, QuantizedResizeBilinear_ShapeFn) {
291  ShapeInferenceTestOp op("QuantizedResizeBilinear");
292  op.input_tensors.resize(4);
293
294  NodeDefBuilder builder =
295      NodeDefBuilder("test", "QuantizedResizeBilinear")
296          .Input(NodeDefBuilder::NodeOut{"images", 0, DT_QINT32})
297          .Input(NodeDefBuilder::NodeOut{"size", 0, DT_INT32})
298          .Input(NodeDefBuilder::NodeOut{"min", 0, DT_FLOAT})
299          .Input(NodeDefBuilder::NodeOut{"max", 0, DT_FLOAT})
300          .Attr("T", DT_QINT32)
301          .Attr("Toutput", DT_QINT32);
302  TF_ASSERT_OK(builder.Finalize(&op.node_def));
303
304  // When the size tensor is not a constant, the middle dims are unknown.
305  INFER_OK(op, "[1,?,3,?];[2];[];[]",
306           "[d0_0,?,?,d0_3];[];[]");  // output rank unknown
307  INFER_ERROR("must be rank 0", op, "[1,?,3,?];[2];[?];[]");
308  INFER_ERROR("must be rank 0", op, "[1,?,3,?];[2];[];[?]");
309
310  const Tensor size_tensor = test::AsTensor<int32>({20, 30});
311  op.input_tensors.at(1) = &size_tensor;
312  INFER_OK(op, "[1,?,3,?];[2];[];[]", "[d0_0,20,30,d0_3];[];[]");
313}
314
315}  // end namespace tensorflow
316