• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2016 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"""Tests for image_ops."""
16
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import print_function
20
21import numpy as np
22
23from tensorflow.contrib.image.ops import gen_image_ops
24from tensorflow.contrib.image.python.ops import image_ops
25from tensorflow.python.framework import constant_op
26from tensorflow.python.framework import dtypes
27from tensorflow.python.framework import test_util
28from tensorflow.python.ops import array_ops
29from tensorflow.python.ops import gradient_checker
30from tensorflow.python.ops import math_ops
31from tensorflow.python.ops import random_ops
32from tensorflow.python.platform import googletest
33
34_DTYPES = set(
35    [dtypes.uint8, dtypes.int32, dtypes.int64,
36     dtypes.float16, dtypes.float32, dtypes.float64])
37
38
39class ImageOpsTest(test_util.TensorFlowTestCase):
40
41  def test_zeros(self):
42    for dtype in _DTYPES:
43      with self.cached_session():
44        for shape in [(5, 5), (24, 24), (2, 24, 24, 3)]:
45          for angle in [0, 1, np.pi / 2.0]:
46            image = array_ops.zeros(shape, dtype)
47            self.assertAllEqual(
48                image_ops.rotate(image, angle).eval(),
49                np.zeros(shape, dtype.as_numpy_dtype()))
50
51  def test_rotate_even(self):
52    for dtype in _DTYPES:
53      with self.cached_session():
54        image = array_ops.reshape(
55            math_ops.cast(math_ops.range(36), dtype), (6, 6))
56        image_rep = array_ops.tile(image[None, :, :, None], [3, 1, 1, 1])
57        angles = constant_op.constant([0.0, np.pi / 4.0, np.pi / 2.0],
58                                      dtypes.float32)
59        image_rotated = image_ops.rotate(image_rep, angles)
60        self.assertAllEqual(image_rotated[:, :, :, 0].eval(),
61                            [[[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11],
62                              [12, 13, 14, 15, 16, 17],
63                              [18, 19, 20, 21, 22, 23],
64                              [24, 25, 26, 27, 28, 29],
65                              [30, 31, 32, 33, 34, 35]],
66                             [[0, 3, 4, 11, 17, 0], [2, 3, 9, 16, 23, 23],
67                              [1, 8, 15, 21, 22, 29], [6, 13, 20, 21, 27, 34],
68                              [12, 18, 19, 26, 33, 33], [0, 18, 24, 31, 32, 0]],
69                             [[5, 11, 17, 23, 29, 35], [4, 10, 16, 22, 28, 34],
70                              [3, 9, 15, 21, 27, 33], [2, 8, 14, 20, 26, 32],
71                              [1, 7, 13, 19, 25, 31], [0, 6, 12, 18, 24, 30]]])
72
73  def test_rotate_odd(self):
74    for dtype in _DTYPES:
75      with self.cached_session():
76        image = array_ops.reshape(
77            math_ops.cast(math_ops.range(25), dtype), (5, 5))
78        image_rep = array_ops.tile(image[None, :, :, None], [3, 1, 1, 1])
79        angles = constant_op.constant([np.pi / 4.0, 1.0, -np.pi / 2.0],
80                                      dtypes.float32)
81        image_rotated = image_ops.rotate(image_rep, angles)
82        self.assertAllEqual(image_rotated[:, :, :, 0].eval(),
83                            [[[0, 3, 8, 9, 0], [1, 7, 8, 13, 19],
84                              [6, 6, 12, 18, 18], [5, 11, 16, 17, 23],
85                              [0, 15, 16, 21, 0]],
86                             [[0, 3, 9, 14, 0], [2, 7, 8, 13, 19],
87                              [1, 6, 12, 18, 23], [5, 11, 16, 17, 22],
88                              [0, 10, 15, 21, 0]],
89                             [[20, 15, 10, 5, 0], [21, 16, 11, 6, 1],
90                              [22, 17, 12, 7, 2], [23, 18, 13, 8, 3],
91                              [24, 19, 14, 9, 4]]])
92
93  def test_translate(self):
94    for dtype in _DTYPES:
95      with self.cached_session():
96        image = constant_op.constant(
97            [[1, 0, 1, 0],
98             [0, 1, 0, 1],
99             [1, 0, 1, 0],
100             [0, 1, 0, 1]], dtype=dtype)
101        translation = constant_op.constant([-1, -1], dtypes.float32)
102        image_translated = image_ops.translate(image, translation)
103        self.assertAllEqual(image_translated.eval(),
104                            [[1, 0, 1, 0],
105                             [0, 1, 0, 0],
106                             [1, 0, 1, 0],
107                             [0, 0, 0, 0]])
108
109  def test_compose(self):
110    for dtype in _DTYPES:
111      with self.cached_session():
112        image = constant_op.constant(
113            [[1, 1, 1, 0],
114             [1, 0, 0, 0],
115             [1, 1, 1, 0],
116             [0, 0, 0, 0]], dtype=dtype)
117        # Rotate counter-clockwise by pi / 2.
118        rotation = image_ops.angles_to_projective_transforms(np.pi / 2, 4, 4)
119        # Translate right by 1 (the transformation matrix is always inverted,
120        # hence the -1).
121        translation = constant_op.constant([1, 0, -1,
122                                            0, 1, 0,
123                                            0, 0],
124                                           dtype=dtypes.float32)
125        composed = image_ops.compose_transforms(rotation, translation)
126        image_transformed = image_ops.transform(image, composed)
127        self.assertAllEqual(image_transformed.eval(),
128                            [[0, 0, 0, 0],
129                             [0, 1, 0, 1],
130                             [0, 1, 0, 1],
131                             [0, 1, 1, 1]])
132
133  def test_extreme_projective_transform(self):
134    for dtype in _DTYPES:
135      with self.cached_session():
136        image = constant_op.constant(
137            [[1, 0, 1, 0],
138             [0, 1, 0, 1],
139             [1, 0, 1, 0],
140             [0, 1, 0, 1]], dtype=dtype)
141        transformation = constant_op.constant([1, 0, 0, 0, 1, 0, -1, 0],
142                                              dtypes.float32)
143        image_transformed = image_ops.transform(image, transformation)
144        self.assertAllEqual(image_transformed.eval(),
145                            [[1, 0, 0, 0],
146                             [0, 0, 0, 0],
147                             [1, 0, 0, 0],
148                             [0, 0, 0, 0]])
149
150  def test_bilinear(self):
151    with self.cached_session():
152      image = constant_op.constant(
153          [[0, 0, 0, 0, 0],
154           [0, 1, 1, 1, 0],
155           [0, 1, 0, 1, 0],
156           [0, 1, 1, 1, 0],
157           [0, 0, 0, 0, 0]],
158          dtypes.float32)
159      # The following result matches:
160      # >>> scipy.ndimage.rotate(image, 45, order=1, reshape=False)
161      # which uses spline interpolation of order 1, equivalent to bilinear
162      # interpolation.
163      self.assertAllClose(
164          image_ops.rotate(image, np.pi / 4.0, interpolation="BILINEAR").eval(),
165          [[0.000, 0.000, 0.343, 0.000, 0.000],
166           [0.000, 0.586, 0.914, 0.586, 0.000],
167           [0.343, 0.914, 0.000, 0.914, 0.343],
168           [0.000, 0.586, 0.914, 0.586, 0.000],
169           [0.000, 0.000, 0.343, 0.000, 0.000]],
170          atol=0.001)
171      self.assertAllClose(
172          image_ops.rotate(image, np.pi / 4.0, interpolation="NEAREST").eval(),
173          [[0, 0, 1, 0, 0],
174           [0, 1, 1, 1, 0],
175           [1, 1, 0, 1, 1],
176           [0, 1, 1, 1, 0],
177           [0, 0, 1, 0, 0]])
178
179  def test_bilinear_uint8(self):
180    with self.cached_session():
181      image = constant_op.constant(
182          np.asarray(
183              [[0.0, 0.0, 0.0, 0.0, 0.0],
184               [0.0, 255, 255, 255, 0.0],
185               [0.0, 255, 0.0, 255, 0.0],
186               [0.0, 255, 255, 255, 0.0],
187               [0.0, 0.0, 0.0, 0.0, 0.0]],
188              np.uint8),
189          dtypes.uint8)
190      # == np.rint((expected image above) * 255)
191      self.assertAllEqual(
192          image_ops.rotate(image, np.pi / 4.0, interpolation="BILINEAR").eval(),
193          [[0.0, 0.0, 87., 0.0, 0.0],
194           [0.0, 149, 233, 149, 0.0],
195           [87., 233, 0.0, 233, 87.],
196           [0.0, 149, 233, 149, 0.0],
197           [0.0, 0.0, 87., 0.0, 0.0]])
198
199  def test_rotate_static_shape(self):
200    image = array_ops.diag([1., 2., 3.])
201    result = image_ops.rotate(
202        image, random_ops.random_uniform((), -1, 1), interpolation="BILINEAR")
203    self.assertEqual(image.get_shape(), result.get_shape())
204
205  def test_transform_static_output_shape(self):
206    image = constant_op.constant([[1., 2.], [3., 4.]])
207    result = image_ops.transform(
208        image, random_ops.random_uniform([8], -1, 1),
209        output_shape=constant_op.constant([3, 5]))
210    self.assertAllEqual([3, 5], result.get_shape())
211
212  def _test_grad(self, shape_to_test):
213    with self.cached_session():
214      test_image_shape = shape_to_test
215      test_image = np.random.randn(*test_image_shape)
216      test_image_tensor = constant_op.constant(
217          test_image, shape=test_image_shape)
218      test_transform = image_ops.angles_to_projective_transforms(
219          np.pi / 2, 4, 4)
220
221      output_shape = test_image_shape
222      output = image_ops.transform(test_image_tensor, test_transform)
223      left_err = gradient_checker.compute_gradient_error(
224          test_image_tensor,
225          test_image_shape,
226          output,
227          output_shape,
228          x_init_value=test_image)
229      self.assertLess(left_err, 1e-10)
230
231  def _test_grad_different_shape(self, input_shape, output_shape):
232    with self.cached_session():
233      test_image_shape = input_shape
234      test_image = np.random.randn(*test_image_shape)
235      test_image_tensor = constant_op.constant(
236          test_image, shape=test_image_shape)
237      test_transform = image_ops.angles_to_projective_transforms(
238          np.pi / 2, 4, 4)
239
240      if len(output_shape) == 2:
241        resize_shape = output_shape
242      elif len(output_shape) == 3:
243        resize_shape = output_shape[0:2]
244      elif len(output_shape) == 4:
245        resize_shape = output_shape[1:3]
246      output = image_ops.transform(
247          images=test_image_tensor,
248          transforms=test_transform,
249          output_shape=resize_shape)
250      left_err = gradient_checker.compute_gradient_error(
251          test_image_tensor,
252          test_image_shape,
253          output,
254          output_shape,
255          x_init_value=test_image)
256      self.assertLess(left_err, 1e-10)
257
258  def test_grad(self):
259    self._test_grad([16, 16])
260    self._test_grad([4, 12, 12])
261    self._test_grad([3, 4, 12, 12])
262    self._test_grad_different_shape([16, 16], [8, 8])
263    self._test_grad_different_shape([4, 12, 3], [8, 24, 3])
264    self._test_grad_different_shape([3, 4, 12, 3], [3, 8, 24, 3])
265
266  def test_projective_transform_v1(self):
267    """The original ImageProjectiveTransform op should take 2 arguments."""
268    image = constant_op.constant([[[[1], [0]], [[0], [1]]]])
269    transform = constant_op.constant([[1., 0., 0., 0., 1., 0., 0., 0.]])
270    result = gen_image_ops.image_projective_transform(
271        image, transform, interpolation="NEAREST")
272    with self.cached_session():
273      self.assertAllEqual([[[[1], [0]], [[0], [1]]]], result.eval())
274
275  def test_transform_data_types(self):
276    for dtype in _DTYPES:
277      image = constant_op.constant([[1, 2], [3, 4]], dtype=dtype)
278      value = image_ops.transform(image, [1] * 8)
279      with self.test_session(use_gpu=True):
280        self.assertAllEqual(
281            value.eval(),
282            np.array([[4, 4], [4, 4]]).astype(dtype.as_numpy_dtype()))
283
284  @test_util.run_in_graph_and_eager_modes
285  def test_transform_eager(self):
286    image = constant_op.constant([[1., 2.], [3., 4.]])
287    value = image_ops.transform(image, [1] * 8)
288    with self.test_session(use_gpu=True):
289      self.assertAllEqual(self.evaluate(value), np.array([[4, 4], [4, 4]]))
290
291
292class BipartiteMatchTest(test_util.TensorFlowTestCase):
293
294  def _BipartiteMatchTest(self, distance_mat, distance_mat_shape,
295                          num_valid_rows,
296                          expected_row_to_col_match,
297                          expected_col_to_row_match):
298    distance_mat_np = np.array(distance_mat, dtype=np.float32).reshape(
299        distance_mat_shape)
300    expected_row_to_col_match_np = np.array(expected_row_to_col_match,
301                                            dtype=np.int32)
302    expected_col_to_row_match_np = np.array(expected_col_to_row_match,
303                                            dtype=np.int32)
304
305    with self.cached_session():
306      distance_mat_tf = constant_op.constant(distance_mat_np,
307                                             shape=distance_mat_shape)
308      location_to_prior, prior_to_location = image_ops.bipartite_match(
309          distance_mat_tf, num_valid_rows)
310      location_to_prior_np = location_to_prior.eval()
311      prior_to_location_np = prior_to_location.eval()
312      self.assertAllEqual(location_to_prior_np, expected_row_to_col_match_np)
313      self.assertAllEqual(prior_to_location_np, expected_col_to_row_match_np)
314
315  def testBipartiteMatch(self):
316    distance_mat = [0.5, 0.8, 0.1,
317                    0.3, 0.2, 0.15]
318    num_valid_rows = 2
319    expected_row_to_col_match = [2, 1]
320    expected_col_to_row_match = [-1, 1, 0]
321    self._BipartiteMatchTest(distance_mat, [2, 3], num_valid_rows,
322                             expected_row_to_col_match,
323                             expected_col_to_row_match)
324
325    # The case of num_valid_rows less than num-of-rows-in-distance-mat.
326    num_valid_rows = 1
327    expected_row_to_col_match = [2, -1]
328    expected_col_to_row_match = [-1, -1, 0]
329    self._BipartiteMatchTest(distance_mat, [2, 3], num_valid_rows,
330                             expected_row_to_col_match,
331                             expected_col_to_row_match)
332
333    # The case of num_valid_rows being 0.
334    num_valid_rows = 0
335    expected_row_to_col_match = [-1, -1]
336    expected_col_to_row_match = [-1, -1, -1]
337    self._BipartiteMatchTest(distance_mat, [2, 3], num_valid_rows,
338                             expected_row_to_col_match,
339                             expected_col_to_row_match)
340
341    # The case of num_valid_rows less being -1.
342    num_valid_rows = -1
343    # The expected results are the same as num_valid_rows being 2.
344    expected_row_to_col_match = [2, 1]
345    expected_col_to_row_match = [-1, 1, 0]
346    self._BipartiteMatchTest(distance_mat, [2, 3], num_valid_rows,
347                             expected_row_to_col_match,
348                             expected_col_to_row_match)
349
350
351if __name__ == "__main__":
352  googletest.main()
353