test_image.py 15.2 KB
Newer Older
Kai Chen's avatar
Kai Chen committed
1
# Copyright (c) Open-MMLab. All rights reserved.
2
3
4
5
import os
import os.path as osp
import tempfile

6
import cv2
7
8
import numpy as np
import pytest
Kai Chen's avatar
Kai Chen committed
9
10
11
from numpy.testing import assert_array_almost_equal, assert_array_equal

import mmcv
12
13
14
15
16
17
18
19
20
21


class TestImage(object):

    @classmethod
    def setup_class(cls):
        # the test img resolution is 400x300
        cls.img_path = osp.join(osp.dirname(__file__), 'data/color.jpg')
        cls.gray_img_path = osp.join(
            osp.dirname(__file__), 'data/grayscale.jpg')
22
        cls.img = cv2.imread(cls.img_path)
23
24
25
26
27
28
29
30

    def assert_img_equal(self, img, ref_img, ratio_thr=0.999):
        assert img.shape == ref_img.shape
        assert img.dtype == ref_img.dtype
        area = ref_img.shape[0] * ref_img.shape[1]
        diff = np.abs(img.astype('int32') - ref_img.astype('int32'))
        assert np.sum(diff <= 1) / float(area) > ratio_thr

31
32
    def test_imread(self):
        img = mmcv.imread(self.img_path)
33
        assert img.shape == (300, 400, 3)
34
        img = mmcv.imread(self.img_path, 'grayscale')
35
        assert img.shape == (300, 400)
36
        img = mmcv.imread(self.gray_img_path)
37
        assert img.shape == (300, 400, 3)
38
        img = mmcv.imread(self.gray_img_path, 'unchanged')
39
        assert img.shape == (300, 400)
40
41
        img = mmcv.imread(img)
        assert_array_equal(img, mmcv.imread(img))
42
        with pytest.raises(TypeError):
43
            mmcv.imread(1)
44

45
    def test_imfrombytes(self):
46
47
        with open(self.img_path, 'rb') as f:
            img_bytes = f.read()
48
        img = mmcv.imfrombytes(img_bytes)
49
50
        assert img.shape == (300, 400, 3)

51
52
    def test_imwrite(self):
        img = mmcv.imread(self.img_path)
53
        out_file = osp.join(tempfile.gettempdir(), 'mmcv_test.jpg')
54
55
        mmcv.imwrite(img, out_file)
        rewrite_img = mmcv.imread(out_file)
56
57
58
59
60
61
        os.remove(out_file)
        self.assert_img_equal(img, rewrite_img)

    def test_bgr2gray(self):
        in_img = np.random.rand(10, 10, 3).astype(np.float32)
        out_img = mmcv.bgr2gray(in_img)
Kai Chen's avatar
Kai Chen committed
62
63
64
        computed_gray = (
            in_img[:, :, 0] * 0.114 + in_img[:, :, 1] * 0.587 +
            in_img[:, :, 2] * 0.299)
65
66
67
68
69
        assert_array_almost_equal(out_img, computed_gray, decimal=4)
        out_img_3d = mmcv.bgr2gray(in_img, True)
        assert out_img_3d.shape == (10, 10, 1)
        assert_array_almost_equal(out_img_3d[..., 0], out_img, decimal=4)

Kai Chen's avatar
Kai Chen committed
70
71
72
73
74
75
76
77
78
79
80
    def test_rgb2gray(self):
        in_img = np.random.rand(10, 10, 3).astype(np.float32)
        out_img = mmcv.rgb2gray(in_img)
        computed_gray = (
            in_img[:, :, 0] * 0.299 + in_img[:, :, 1] * 0.587 +
            in_img[:, :, 2] * 0.114)
        assert_array_almost_equal(out_img, computed_gray, decimal=4)
        out_img_3d = mmcv.rgb2gray(in_img, True)
        assert out_img_3d.shape == (10, 10, 1)
        assert_array_almost_equal(out_img_3d[..., 0], out_img, decimal=4)

81
82
83
84
85
86
87
    def test_gray2bgr(self):
        in_img = np.random.rand(10, 10).astype(np.float32)
        out_img = mmcv.gray2bgr(in_img)
        assert out_img.shape == (10, 10, 3)
        for i in range(3):
            assert_array_almost_equal(out_img[..., i], in_img, decimal=4)

Kai Chen's avatar
Kai Chen committed
88
89
90
91
92
93
94
    def test_gray2rgb(self):
        in_img = np.random.rand(10, 10).astype(np.float32)
        out_img = mmcv.gray2rgb(in_img)
        assert out_img.shape == (10, 10, 3)
        for i in range(3):
            assert_array_almost_equal(out_img[..., i], in_img, decimal=4)

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
    def test_bgr2rgb(self):
        in_img = np.random.rand(10, 10, 3).astype(np.float32)
        out_img = mmcv.bgr2rgb(in_img)
        assert out_img.shape == in_img.shape
        assert_array_equal(out_img[..., 0], in_img[..., 2])
        assert_array_equal(out_img[..., 1], in_img[..., 1])
        assert_array_equal(out_img[..., 2], in_img[..., 0])

    def test_rgb2bgr(self):
        in_img = np.random.rand(10, 10, 3).astype(np.float32)
        out_img = mmcv.rgb2bgr(in_img)
        assert out_img.shape == in_img.shape
        assert_array_equal(out_img[..., 0], in_img[..., 2])
        assert_array_equal(out_img[..., 1], in_img[..., 1])
        assert_array_equal(out_img[..., 2], in_img[..., 0])

    def test_bgr2hsv(self):
        in_img = np.random.rand(10, 10, 3).astype(np.float32)
        out_img = mmcv.bgr2hsv(in_img)
        argmax = in_img.argmax(axis=2)
        computed_hsv = np.empty_like(in_img, dtype=in_img.dtype)
        for i in range(in_img.shape[0]):
            for j in range(in_img.shape[1]):
                b = in_img[i, j, 0]
                g = in_img[i, j, 1]
                r = in_img[i, j, 2]
                v = max(r, g, b)
                s = (v - min(r, g, b)) / v if v != 0 else 0
                if argmax[i, j] == 0:
                    h = 240 + 60 * (r - g) / (v - min(r, g, b))
                elif argmax[i, j] == 1:
                    h = 120 + 60 * (b - r) / (v - min(r, g, b))
                else:
                    h = 60 * (g - b) / (v - min(r, g, b))
                if h < 0:
                    h += 360
                computed_hsv[i, j, :] = [h, s, v]
        assert_array_almost_equal(out_img, computed_hsv, decimal=2)

Gu Wang's avatar
Gu Wang committed
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
    def test_bgr2hls(self):
        in_img = np.random.rand(10, 10, 3).astype(np.float32)
        out_img = mmcv.bgr2hls(in_img)
        argmax = in_img.argmax(axis=2)
        computed_hls = np.empty_like(in_img, dtype=in_img.dtype)
        for i in range(in_img.shape[0]):
            for j in range(in_img.shape[1]):
                b = in_img[i, j, 0]
                g = in_img[i, j, 1]
                r = in_img[i, j, 2]
                maxc = max(r, g, b)
                minc = min(r, g, b)
                _l = (minc + maxc) / 2.0
                if minc == maxc:
                    h = 0.0
                    s = 0.0
                if _l <= 0.5:
                    s = (maxc - minc) / (maxc + minc)
                else:
                    s = (maxc - minc) / (2.0 - maxc - minc)
                if argmax[i, j] == 2:
                    h = 60 * (g - b) / (maxc - minc)
                elif argmax[i, j] == 1:
                    h = 60 * (2.0 + (b - r) / (maxc - minc))
                else:
                    h = 60 * (4.0 + (r - g) / (maxc - minc))
                if h < 0:
                    h += 360
                computed_hls[i, j, :] = [h, _l, s]
        assert_array_almost_equal(out_img, computed_hls, decimal=2)

165
166
    def test_imresize(self):
        resized_img = mmcv.imresize(self.img, (1000, 600))
167
        assert resized_img.shape == (600, 1000, 3)
168
169
        resized_img, w_scale, h_scale = mmcv.imresize(self.img, (1000, 600),
                                                      True)
170
171
172
        assert (resized_img.shape == (600, 1000, 3) and w_scale == 2.5
                and h_scale == 2.0)
        for mode in ['nearest', 'bilinear', 'bicubic', 'area', 'lanczos']:
173
174
            resized_img = mmcv.imresize(
                self.img, (1000, 600), interpolation=mode)
175
176
            assert resized_img.shape == (600, 1000, 3)

177
    def test_imresize_like(self):
178
        a = np.zeros((100, 200, 3))
179
        resized_img = mmcv.imresize_like(self.img, a)
180
181
        assert resized_img.shape == (100, 200, 3)

182
183
184
    def test_imrescale(self):
        # rescale by a certain factor
        resized_img = mmcv.imrescale(self.img, 1.5)
185
        assert resized_img.shape == (450, 600, 3)
186
        resized_img = mmcv.imrescale(self.img, 0.934)
187
188
        assert resized_img.shape == (280, 374, 3)

189
        # rescale by a certain max_size
190
        # resize (400, 300) to (max_1000, max_600)
191
        resized_img = mmcv.imrescale(self.img, (1000, 600))
192
        assert resized_img.shape == (600, 800, 3)
193
194
        resized_img, scale = mmcv.imrescale(
            self.img, (1000, 600), return_scale=True)
195
196
        assert resized_img.shape == (600, 800, 3) and scale == 2.0
        # resize (400, 300) to (max_200, max_180)
197
        resized_img = mmcv.imrescale(self.img, (180, 200))
198
        assert resized_img.shape == (150, 200, 3)
199
200
        resized_img, scale = mmcv.imrescale(
            self.img, (180, 200), return_scale=True)
201
        assert resized_img.shape == (150, 200, 3) and scale == 0.5
202
203

        # test exceptions
204
        with pytest.raises(ValueError):
205
206
207
            mmcv.imrescale(self.img, -0.5)
        with pytest.raises(TypeError):
            mmcv.imrescale(self.img, [100, 100])
208

Kai Chen's avatar
Kai Chen committed
209
    def test_imflip(self):
Kai Chen's avatar
Kai Chen committed
210
        # test horizontal flip (color image)
Kai Chen's avatar
Kai Chen committed
211
212
        img = np.random.rand(80, 60, 3)
        h, w, c = img.shape
Kai Chen's avatar
Kai Chen committed
213
214
        flipped_img = mmcv.imflip(img)
        assert flipped_img.shape == img.shape
Kai Chen's avatar
Kai Chen committed
215
216
217
        for i in range(h):
            for j in range(w):
                for k in range(c):
Kai Chen's avatar
Kai Chen committed
218
219
220
221
                    assert flipped_img[i, j, k] == img[i, w - 1 - j, k]
        # test vertical flip (color image)
        flipped_img = mmcv.imflip(img, direction='vertical')
        assert flipped_img.shape == img.shape
Kai Chen's avatar
Kai Chen committed
222
223
224
        for i in range(h):
            for j in range(w):
                for k in range(c):
Kai Chen's avatar
Kai Chen committed
225
226
                    assert flipped_img[i, j, k] == img[h - 1 - i, j, k]
        # test horizontal flip (grayscale image)
Kai Chen's avatar
Kai Chen committed
227
        img = np.random.rand(80, 60)
Kai Chen's avatar
Kai Chen committed
228
229
230
        h, w = img.shape
        flipped_img = mmcv.imflip(img)
        assert flipped_img.shape == img.shape
Kai Chen's avatar
Kai Chen committed
231
232
        for i in range(h):
            for j in range(w):
Kai Chen's avatar
Kai Chen committed
233
234
235
236
                assert flipped_img[i, j] == img[i, w - 1 - j]
        # test vertical flip (grayscale image)
        flipped_img = mmcv.imflip(img, direction='vertical')
        assert flipped_img.shape == img.shape
Kai Chen's avatar
Kai Chen committed
237
238
        for i in range(h):
            for j in range(w):
Kai Chen's avatar
Kai Chen committed
239
                assert flipped_img[i, j] == img[h - 1 - i, j]
Kai Chen's avatar
Kai Chen committed
240

241
    def test_imcrop(self):
242
243
244
245
246
247
248
        # yapf: disable
        bboxes = np.array([[100, 100, 199, 199],  # center
                           [0, 0, 150, 100],  # left-top corner
                           [250, 200, 399, 299],  # right-bottom corner
                           [0, 100, 399, 199],  # wide
                           [150, 0, 299, 299]])  # tall
        # yapf: enable
249

250
        # crop one bbox
251
252
        patch = mmcv.imcrop(self.img, bboxes[0, :])
        patches = mmcv.imcrop(self.img, bboxes[[0], :])
253
254
255
256
257
258
        assert patch.shape == (100, 100, 3)
        patch_path = osp.join(osp.dirname(__file__), 'data/patches')
        ref_patch = np.load(patch_path + '/0.npy')
        self.assert_img_equal(patch, ref_patch)
        assert isinstance(patches, list) and len(patches) == 1
        self.assert_img_equal(patches[0], ref_patch)
259

260
        # crop with no scaling and padding
261
        patches = mmcv.imcrop(self.img, bboxes)
262
263
264
265
        assert len(patches) == bboxes.shape[0]
        for i in range(len(patches)):
            ref_patch = np.load(patch_path + '/{}.npy'.format(i))
            self.assert_img_equal(patches[i], ref_patch)
266

267
        # crop with scaling and no padding
268
        patches = mmcv.imcrop(self.img, bboxes, 1.2)
269
270
271
        for i in range(len(patches)):
            ref_patch = np.load(patch_path + '/scale_{}.npy'.format(i))
            self.assert_img_equal(patches[i], ref_patch)
272

273
        # crop with scaling and padding
274
        patches = mmcv.imcrop(self.img, bboxes, 1.2, pad_fill=[255, 255, 0])
275
276
277
        for i in range(len(patches)):
            ref_patch = np.load(patch_path + '/pad_{}.npy'.format(i))
            self.assert_img_equal(patches[i], ref_patch)
278
        patches = mmcv.imcrop(self.img, bboxes, 1.2, pad_fill=0)
279
280
281
282
        for i in range(len(patches)):
            ref_patch = np.load(patch_path + '/pad0_{}.npy'.format(i))
            self.assert_img_equal(patches[i], ref_patch)

283
    def test_impad(self):
284
        img = np.random.rand(10, 10, 3).astype(np.float32)
285
        padded_img = mmcv.impad(img, (15, 12), 0)
286
287
288
289
290
        assert_array_equal(img, padded_img[:10, :10, :])
        assert_array_equal(
            np.zeros((5, 12, 3), dtype='float32'), padded_img[10:, :, :])
        assert_array_equal(
            np.zeros((15, 2, 3), dtype='float32'), padded_img[:, 10:, :])
291

292
        img = np.random.randint(256, size=(10, 10, 3)).astype('uint8')
293
        padded_img = mmcv.impad(img, (15, 12, 3), [100, 110, 120])
294
295
296
297
298
299
300
        assert_array_equal(img, padded_img[:10, :10, :])
        assert_array_equal(
            np.array([100, 110, 120], dtype='uint8') * np.ones(
                (5, 12, 3), dtype='uint8'), padded_img[10:, :, :])
        assert_array_equal(
            np.array([100, 110, 120], dtype='uint8') * np.ones(
                (15, 2, 3), dtype='uint8'), padded_img[:, 10:, :])
301

302
        with pytest.raises(AssertionError):
303
            mmcv.impad(img, (15, ), 0)
304
        with pytest.raises(AssertionError):
305
            mmcv.impad(img, (5, 5), 0)
306
        with pytest.raises(AssertionError):
307
            mmcv.impad(img, (5, 5), [0, 1])
308

Kai Chen's avatar
Kai Chen committed
309
310
311
312
313
314
315
316
317
318
319
    def test_impad_to_multiple(self):
        img = np.random.rand(11, 14, 3).astype(np.float32)
        padded_img = mmcv.impad_to_multiple(img, 4)
        assert padded_img.shape == (12, 16, 3)
        img = np.random.rand(20, 12).astype(np.float32)
        padded_img = mmcv.impad_to_multiple(img, 5)
        assert padded_img.shape == (20, 15)
        img = np.random.rand(20, 12).astype(np.float32)
        padded_img = mmcv.impad_to_multiple(img, 2)
        assert padded_img.shape == (20, 12)

320
    def test_imrotate(self):
321
        img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).astype(np.uint8)
322
        assert_array_equal(mmcv.imrotate(img, 0), img)
323
        img_r = np.array([[7, 4, 1], [8, 5, 2], [9, 6, 3]])
324
        assert_array_equal(mmcv.imrotate(img, 90), img_r)
325
        img_r = np.array([[3, 6, 9], [2, 5, 8], [1, 4, 7]])
326
        assert_array_equal(mmcv.imrotate(img, -90), img_r)
327
328
329

        img = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]).astype(np.uint8)
        img_r = np.array([[0, 6, 2, 0], [0, 7, 3, 0]])
330
        assert_array_equal(mmcv.imrotate(img, 90), img_r)
331
        img_r = np.array([[1, 0, 0, 0], [2, 0, 0, 0]])
332
        assert_array_equal(mmcv.imrotate(img, 90, center=(0, 0)), img_r)
333
        img_r = np.array([[255, 6, 2, 255], [255, 7, 3, 255]])
334
        assert_array_equal(mmcv.imrotate(img, 90, border_value=255), img_r)
335
        img_r = np.array([[5, 1], [6, 2], [7, 3], [8, 4]])
336
337
338
339
        assert_array_equal(mmcv.imrotate(img, 90, auto_bound=True), img_r)

        with pytest.raises(ValueError):
            mmcv.imrotate(img, 90, center=(0, 0), auto_bound=True)
Yue Zhao's avatar
Yue Zhao committed
340
341
342
343
344
345
346

    def test_iminvert(self):
        img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]],
                       dtype=np.uint8)
        img_r = np.array([[255, 127, 0], [254, 128, 1], [253, 126, 2]],
                         dtype=np.uint8)
        assert_array_equal(mmcv.iminvert(img), img_r)
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366

    def test_solarize(self):
        img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]],
                       dtype=np.uint8)
        img_r = np.array([[0, 127, 0], [1, 127, 1], [2, 126, 2]],
                         dtype=np.uint8)
        assert_array_equal(mmcv.solarize(img), img_r)
        img_r = np.array([[0, 127, 0], [1, 128, 1], [2, 126, 2]],
                         dtype=np.uint8)
        assert_array_equal(mmcv.solarize(img, 100), img_r)

    def test_posterize(self):
        img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]],
                       dtype=np.uint8)
        img_r = np.array([[0, 128, 128], [0, 0, 128], [0, 128, 128]],
                         dtype=np.uint8)
        assert_array_equal(mmcv.posterize(img, 1), img_r)
        img_r = np.array([[0, 128, 224], [0, 96, 224], [0, 128, 224]],
                         dtype=np.uint8)
        assert_array_equal(mmcv.posterize(img, 3), img_r)