test_image.py 16.5 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)
lizz's avatar
lizz committed
23
24
        cls.mean = np.float32(np.array([123.675, 116.28, 103.53]))
        cls.std = np.float32(np.array([58.395, 57.12, 57.375]))
25
26
27
28
29
30
31
32

    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

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

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

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

lizz's avatar
lizz committed
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
    def test_imnormalize(self):
        rgbimg = self.img[:, :, ::-1]
        baseline = (rgbimg - self.mean) / self.std
        img = mmcv.imnormalize(self.img, self.mean, self.std)
        assert np.allclose(img, baseline)
        img = mmcv.imnormalize(rgbimg, self.mean, self.std, to_rgb=False)
        assert np.allclose(img, baseline)

    def test_imdenormalize(self):
        normimg = (self.img[:, :, ::-1] - self.mean) / self.std
        rgbbaseline = (normimg * self.std + self.mean)
        bgrbaseline = rgbbaseline[:, :, ::-1]
        img = mmcv.imdenormalize(normimg, self.mean, self.std)
        assert np.allclose(img, bgrbaseline)
        img = mmcv.imdenormalize(normimg, self.mean, self.std, to_bgr=False)
        assert np.allclose(img, rgbbaseline)

78
79
80
    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
81
82
83
        computed_gray = (
            in_img[:, :, 0] * 0.114 + in_img[:, :, 1] * 0.587 +
            in_img[:, :, 2] * 0.299)
84
85
86
87
88
        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
89
90
91
92
93
94
95
96
97
98
99
    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)

100
101
102
103
104
105
106
    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
107
108
109
110
111
112
113
    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)

114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
    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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
    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)

184
185
    def test_imresize(self):
        resized_img = mmcv.imresize(self.img, (1000, 600))
186
        assert resized_img.shape == (600, 1000, 3)
187
188
        resized_img, w_scale, h_scale = mmcv.imresize(self.img, (1000, 600),
                                                      True)
189
190
191
        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']:
192
193
            resized_img = mmcv.imresize(
                self.img, (1000, 600), interpolation=mode)
194
195
            assert resized_img.shape == (600, 1000, 3)

196
    def test_imresize_like(self):
197
        a = np.zeros((100, 200, 3))
198
        resized_img = mmcv.imresize_like(self.img, a)
199
200
        assert resized_img.shape == (100, 200, 3)

201
202
203
    def test_imrescale(self):
        # rescale by a certain factor
        resized_img = mmcv.imrescale(self.img, 1.5)
204
        assert resized_img.shape == (450, 600, 3)
205
        resized_img = mmcv.imrescale(self.img, 0.934)
206
207
        assert resized_img.shape == (280, 374, 3)

208
        # rescale by a certain max_size
209
        # resize (400, 300) to (max_1000, max_600)
210
        resized_img = mmcv.imrescale(self.img, (1000, 600))
211
        assert resized_img.shape == (600, 800, 3)
212
213
        resized_img, scale = mmcv.imrescale(
            self.img, (1000, 600), return_scale=True)
214
215
        assert resized_img.shape == (600, 800, 3) and scale == 2.0
        # resize (400, 300) to (max_200, max_180)
216
        resized_img = mmcv.imrescale(self.img, (180, 200))
217
        assert resized_img.shape == (150, 200, 3)
218
219
        resized_img, scale = mmcv.imrescale(
            self.img, (180, 200), return_scale=True)
220
        assert resized_img.shape == (150, 200, 3) and scale == 0.5
221
222

        # test exceptions
223
        with pytest.raises(ValueError):
224
225
226
            mmcv.imrescale(self.img, -0.5)
        with pytest.raises(TypeError):
            mmcv.imrescale(self.img, [100, 100])
227

Kai Chen's avatar
Kai Chen committed
228
    def test_imflip(self):
Kai Chen's avatar
Kai Chen committed
229
        # test horizontal flip (color image)
Kai Chen's avatar
Kai Chen committed
230
231
        img = np.random.rand(80, 60, 3)
        h, w, c = img.shape
Kai Chen's avatar
Kai Chen committed
232
233
        flipped_img = mmcv.imflip(img)
        assert flipped_img.shape == img.shape
Kai Chen's avatar
Kai Chen committed
234
235
236
        for i in range(h):
            for j in range(w):
                for k in range(c):
Kai Chen's avatar
Kai Chen committed
237
238
239
240
                    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
241
242
243
        for i in range(h):
            for j in range(w):
                for k in range(c):
Kai Chen's avatar
Kai Chen committed
244
245
                    assert flipped_img[i, j, k] == img[h - 1 - i, j, k]
        # test horizontal flip (grayscale image)
Kai Chen's avatar
Kai Chen committed
246
        img = np.random.rand(80, 60)
Kai Chen's avatar
Kai Chen committed
247
248
249
        h, w = img.shape
        flipped_img = mmcv.imflip(img)
        assert flipped_img.shape == img.shape
Kai Chen's avatar
Kai Chen committed
250
251
        for i in range(h):
            for j in range(w):
Kai Chen's avatar
Kai Chen committed
252
253
254
255
                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
256
257
        for i in range(h):
            for j in range(w):
Kai Chen's avatar
Kai Chen committed
258
                assert flipped_img[i, j] == img[h - 1 - i, j]
Kai Chen's avatar
Kai Chen committed
259

260
    def test_imcrop(self):
261
262
263
264
265
266
267
        # 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
268

269
        # crop one bbox
270
271
        patch = mmcv.imcrop(self.img, bboxes[0, :])
        patches = mmcv.imcrop(self.img, bboxes[[0], :])
272
273
274
275
276
277
        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)
278

279
        # crop with no scaling and padding
280
        patches = mmcv.imcrop(self.img, bboxes)
281
282
283
284
        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)
285

286
        # crop with scaling and no padding
287
        patches = mmcv.imcrop(self.img, bboxes, 1.2)
288
289
290
        for i in range(len(patches)):
            ref_patch = np.load(patch_path + '/scale_{}.npy'.format(i))
            self.assert_img_equal(patches[i], ref_patch)
291

292
        # crop with scaling and padding
293
        patches = mmcv.imcrop(self.img, bboxes, 1.2, pad_fill=[255, 255, 0])
294
295
296
        for i in range(len(patches)):
            ref_patch = np.load(patch_path + '/pad_{}.npy'.format(i))
            self.assert_img_equal(patches[i], ref_patch)
297
        patches = mmcv.imcrop(self.img, bboxes, 1.2, pad_fill=0)
298
299
300
301
        for i in range(len(patches)):
            ref_patch = np.load(patch_path + '/pad0_{}.npy'.format(i))
            self.assert_img_equal(patches[i], ref_patch)

302
    def test_impad(self):
303
304
305
306
307
308
309
310
311
312
        # grayscale image
        img = np.random.rand(10, 10).astype(np.float32)
        padded_img = mmcv.impad(img, (15, 12), 0)
        assert_array_equal(img, padded_img[:10, :10])
        assert_array_equal(
            np.zeros((5, 12), dtype='float32'), padded_img[10:, :])
        assert_array_equal(
            np.zeros((15, 2), dtype='float32'), padded_img[:, 10:])

        # RGB image
313
        img = np.random.rand(10, 10, 3).astype(np.float32)
314
        padded_img = mmcv.impad(img, (15, 12), 0)
315
316
317
318
319
        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:, :])
320

321
        img = np.random.randint(256, size=(10, 10, 3)).astype('uint8')
322
        padded_img = mmcv.impad(img, (15, 12, 3), [100, 110, 120])
323
324
325
326
327
328
329
        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:, :])
330

331
        with pytest.raises(AssertionError):
332
            mmcv.impad(img, (15, ), 0)
333
        with pytest.raises(AssertionError):
334
            mmcv.impad(img, (5, 5), 0)
335
        with pytest.raises(AssertionError):
336
            mmcv.impad(img, (5, 5), [0, 1])
337

Kai Chen's avatar
Kai Chen committed
338
339
340
341
342
343
344
345
346
347
348
    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)

349
    def test_imrotate(self):
350
        img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).astype(np.uint8)
351
        assert_array_equal(mmcv.imrotate(img, 0), img)
352
        img_r = np.array([[7, 4, 1], [8, 5, 2], [9, 6, 3]])
353
        assert_array_equal(mmcv.imrotate(img, 90), img_r)
354
        img_r = np.array([[3, 6, 9], [2, 5, 8], [1, 4, 7]])
355
        assert_array_equal(mmcv.imrotate(img, -90), img_r)
356
357
358

        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]])
359
        assert_array_equal(mmcv.imrotate(img, 90), img_r)
360
        img_r = np.array([[1, 0, 0, 0], [2, 0, 0, 0]])
361
        assert_array_equal(mmcv.imrotate(img, 90, center=(0, 0)), img_r)
362
        img_r = np.array([[255, 6, 2, 255], [255, 7, 3, 255]])
363
        assert_array_equal(mmcv.imrotate(img, 90, border_value=255), img_r)
364
        img_r = np.array([[5, 1], [6, 2], [7, 3], [8, 4]])
365
366
367
368
        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
369
370
371
372
373
374
375

    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)
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395

    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)