scikit-image

Форк
0
360 строк · 11.4 Кб
1
import numpy as np
2
import pytest
3
from numpy.testing import assert_almost_equal
4

5
from skimage import color, data, draw, feature, img_as_float
6
from skimage._shared import filters
7
from skimage._shared.testing import fetch
8
from skimage._shared.utils import _supported_float_type
9

10

11
def test_hog_output_size():
12
    img = img_as_float(data.astronaut()[:256, :].mean(axis=2))
13

14
    fd = feature.hog(
15
        img,
16
        orientations=9,
17
        pixels_per_cell=(8, 8),
18
        cells_per_block=(1, 1),
19
        block_norm='L1',
20
    )
21

22
    assert len(fd) == 9 * (256 // 8) * (512 // 8)
23

24

25
@pytest.mark.parametrize('dtype', [np.float32, np.float64])
26
def test_hog_output_correctness_l1_norm(dtype):
27
    img = color.rgb2gray(data.astronaut()).astype(dtype=dtype, copy=False)
28
    correct_output = np.load(fetch('data/astronaut_GRAY_hog_L1.npy'))
29

30
    output = feature.hog(
31
        img,
32
        orientations=9,
33
        pixels_per_cell=(8, 8),
34
        cells_per_block=(3, 3),
35
        block_norm='L1',
36
        feature_vector=True,
37
        transform_sqrt=False,
38
        visualize=False,
39
    )
40
    float_dtype = _supported_float_type(dtype)
41
    assert output.dtype == float_dtype
42
    decimal = 7 if float_dtype == np.float64 else 5
43
    assert_almost_equal(output, correct_output, decimal=decimal)
44

45

46
@pytest.mark.parametrize('dtype', [np.float32, np.float64])
47
def test_hog_output_correctness_l2hys_norm(dtype):
48
    img = color.rgb2gray(data.astronaut()).astype(dtype=dtype, copy=False)
49
    correct_output = np.load(fetch('data/astronaut_GRAY_hog_L2-Hys.npy'))
50

51
    output = feature.hog(
52
        img,
53
        orientations=9,
54
        pixels_per_cell=(8, 8),
55
        cells_per_block=(3, 3),
56
        block_norm='L2-Hys',
57
        feature_vector=True,
58
        transform_sqrt=False,
59
        visualize=False,
60
    )
61
    float_dtype = _supported_float_type(dtype)
62
    assert output.dtype == float_dtype
63
    decimal = 7 if float_dtype == np.float64 else 5
64
    assert_almost_equal(output, correct_output, decimal=decimal)
65

66

67
def test_hog_image_size_cell_size_mismatch():
68
    image = data.camera()[:150, :200]
69
    fd = feature.hog(
70
        image,
71
        orientations=9,
72
        pixels_per_cell=(8, 8),
73
        cells_per_block=(1, 1),
74
        block_norm='L1',
75
    )
76
    assert len(fd) == 9 * (150 // 8) * (200 // 8)
77

78

79
def test_hog_odd_cell_size():
80
    img = np.zeros((3, 3))
81
    img[2, 2] = 1
82

83
    correct_output = np.zeros((9,))
84
    correct_output[0] = 0.5
85
    correct_output[4] = 0.5
86

87
    output = feature.hog(
88
        img, pixels_per_cell=(3, 3), cells_per_block=(1, 1), block_norm='L1'
89
    )
90

91
    assert_almost_equal(output, correct_output, decimal=1)
92

93

94
def test_hog_basic_orientations_and_data_types():
95
    # scenario:
96
    #  1) create image (with float values) where upper half is filled by
97
    #     zeros, bottom half by 100
98
    #  2) create unsigned integer version of this image
99
    #  3) calculate feature.hog() for both images, both with 'transform_sqrt'
100
    #     option enabled and disabled
101
    #  4) verify that all results are equal where expected
102
    #  5) verify that computed feature vector is as expected
103
    #  6) repeat the scenario for 90, 180 and 270 degrees rotated images
104

105
    # size of testing image
106
    width = height = 35
107

108
    image0 = np.zeros((height, width), dtype='float')
109
    image0[height // 2 :] = 100
110

111
    for rot in range(4):
112
        # rotate by 0, 90, 180 and 270 degrees
113
        image_float = np.rot90(image0, rot)
114

115
        # create uint8 image from image_float
116
        image_uint8 = image_float.astype('uint8')
117

118
        (hog_float, hog_img_float) = feature.hog(
119
            image_float,
120
            orientations=4,
121
            pixels_per_cell=(8, 8),
122
            cells_per_block=(1, 1),
123
            visualize=True,
124
            transform_sqrt=False,
125
            block_norm='L1',
126
        )
127
        (hog_uint8, hog_img_uint8) = feature.hog(
128
            image_uint8,
129
            orientations=4,
130
            pixels_per_cell=(8, 8),
131
            cells_per_block=(1, 1),
132
            visualize=True,
133
            transform_sqrt=False,
134
            block_norm='L1',
135
        )
136
        (hog_float_norm, hog_img_float_norm) = feature.hog(
137
            image_float,
138
            orientations=4,
139
            pixels_per_cell=(8, 8),
140
            cells_per_block=(1, 1),
141
            visualize=True,
142
            transform_sqrt=True,
143
            block_norm='L1',
144
        )
145
        (hog_uint8_norm, hog_img_uint8_norm) = feature.hog(
146
            image_uint8,
147
            orientations=4,
148
            pixels_per_cell=(8, 8),
149
            cells_per_block=(1, 1),
150
            visualize=True,
151
            transform_sqrt=True,
152
            block_norm='L1',
153
        )
154

155
        # set to True to enable manual debugging with graphical output,
156
        # must be False for automatic testing
157
        if False:
158
            import matplotlib.pyplot as plt
159

160
            plt.figure()
161
            plt.subplot(2, 3, 1)
162
            plt.imshow(image_float)
163
            plt.colorbar()
164
            plt.title('image')
165
            plt.subplot(2, 3, 2)
166
            plt.imshow(hog_img_float)
167
            plt.colorbar()
168
            plt.title('HOG result visualisation (float img)')
169
            plt.subplot(2, 3, 5)
170
            plt.imshow(hog_img_uint8)
171
            plt.colorbar()
172
            plt.title('HOG result visualisation (uint8 img)')
173
            plt.subplot(2, 3, 3)
174
            plt.imshow(hog_img_float_norm)
175
            plt.colorbar()
176
            plt.title('HOG result (transform_sqrt) visualisation (float img)')
177
            plt.subplot(2, 3, 6)
178
            plt.imshow(hog_img_uint8_norm)
179
            plt.colorbar()
180
            plt.title('HOG result (transform_sqrt) visualisation (uint8 img)')
181
            plt.show()
182

183
        # results (features and visualisation) for float and uint8 images must
184
        # be almost equal
185
        assert_almost_equal(hog_float, hog_uint8)
186
        assert_almost_equal(hog_img_float, hog_img_uint8)
187

188
        # resulting features should be almost equal
189
        # when 'transform_sqrt' is enabled
190
        # or disabled (for current simple testing image)
191
        assert_almost_equal(hog_float, hog_float_norm, decimal=4)
192
        assert_almost_equal(hog_float, hog_uint8_norm, decimal=4)
193

194
        # reshape resulting feature vector to matrix with 4 columns (each
195
        # corresponding to one of 4 directions); only one direction should
196
        # contain nonzero values (this is manually determined for testing
197
        # image)
198
        actual = np.max(hog_float.reshape(-1, 4), axis=0)
199

200
        if rot in [0, 2]:
201
            # image is rotated by 0 and 180 degrees
202
            desired = [0, 0, 1, 0]
203
        elif rot in [1, 3]:
204
            # image is rotated by 90 and 270 degrees
205
            desired = [1, 0, 0, 0]
206
        else:
207
            raise Exception('Result is not determined for this rotation.')
208

209
        assert_almost_equal(actual, desired, decimal=2)
210

211

212
def test_hog_orientations_circle():
213
    # scenario:
214
    #  1) create image with blurred circle in the middle
215
    #  2) calculate feature.hog()
216
    #  3) verify that the resulting feature vector contains uniformly
217
    #     distributed values for all orientations, i.e. no orientation is
218
    #     lost or emphasized
219
    #  4) repeat the scenario for other 'orientations' option
220

221
    # size of testing image
222
    width = height = 100
223

224
    image = np.zeros((height, width))
225
    rr, cc = draw.disk((int(height / 2), int(width / 2)), int(width / 3))
226
    image[rr, cc] = 100
227
    image = filters.gaussian(image, sigma=2, mode='reflect')
228

229
    for orientations in range(2, 15):
230
        (hog, hog_img) = feature.hog(
231
            image,
232
            orientations=orientations,
233
            pixels_per_cell=(8, 8),
234
            cells_per_block=(1, 1),
235
            visualize=True,
236
            transform_sqrt=False,
237
            block_norm='L1',
238
        )
239

240
        # set to True to enable manual debugging with graphical output,
241
        # must be False for automatic testing
242
        if False:
243
            import matplotlib.pyplot as plt
244

245
            plt.figure()
246
            plt.subplot(1, 2, 1)
247
            plt.imshow(image)
248
            plt.colorbar()
249
            plt.title('image_float')
250
            plt.subplot(1, 2, 2)
251
            plt.imshow(hog_img)
252
            plt.colorbar()
253
            plt.title('HOG result visualisation, ' f'orientations={orientations}')
254
            plt.show()
255

256
        # reshape resulting feature vector to matrix with N columns (each
257
        # column corresponds to one direction),
258
        hog_matrix = hog.reshape(-1, orientations)
259

260
        # compute mean values in the resulting feature vector for each
261
        # direction, these values should be almost equal to the global mean
262
        # value (since the image contains a circle), i.e., all directions have
263
        # same contribution to the result
264
        actual = np.mean(hog_matrix, axis=0)
265
        desired = np.mean(hog_matrix)
266
        assert_almost_equal(actual, desired, decimal=1)
267

268

269
def test_hog_visualization_orientation():
270
    """Test that the visualization produces a line with correct orientation
271

272
    The hog visualization is expected to draw line segments perpendicular to
273
    the midpoints of orientation bins.  This example verifies that when
274
    orientations=3 and the gradient is entirely in the middle bin (bisected
275
    by the y-axis), the line segment drawn by the visualization is horizontal.
276
    """
277

278
    width = height = 11
279

280
    image = np.zeros((height, width), dtype='float')
281
    image[height // 2 :] = 1
282

283
    _, hog_image = feature.hog(
284
        image,
285
        orientations=3,
286
        pixels_per_cell=(width, height),
287
        cells_per_block=(1, 1),
288
        visualize=True,
289
        block_norm='L1',
290
    )
291

292
    middle_index = height // 2
293
    indices_excluding_middle = [x for x in range(height) if x != middle_index]
294

295
    assert (hog_image[indices_excluding_middle, :] == 0).all()
296
    assert (hog_image[middle_index, 1:-1] > 0).all()
297

298

299
def test_hog_block_normalization_incorrect_error():
300
    img = np.eye(4)
301
    with pytest.raises(ValueError):
302
        feature.hog(img, block_norm='Linf')
303

304

305
@pytest.mark.parametrize(
306
    "shape,channel_axis",
307
    [
308
        ((3, 3, 3), None),
309
        ((3, 3), -1),
310
        ((3, 3, 3, 3), -1),
311
    ],
312
)
313
def test_hog_incorrect_dimensions(shape, channel_axis):
314
    img = np.zeros(shape)
315
    with pytest.raises(ValueError):
316
        feature.hog(img, channel_axis=channel_axis, block_norm='L1')
317

318

319
def test_hog_output_equivariance_deprecated_multichannel():
320
    img = data.astronaut()
321
    img[:, :, (1, 2)] = 0
322
    hog_ref = feature.hog(img, channel_axis=-1, block_norm='L1')
323

324
    for n in (1, 2):
325
        hog_fact = feature.hog(
326
            np.roll(img, n, axis=2), channel_axis=-1, block_norm='L1'
327
        )
328
        assert_almost_equal(hog_ref, hog_fact)
329

330

331
@pytest.mark.parametrize('channel_axis', [0, 1, -1, -2])
332
def test_hog_output_equivariance_channel_axis(channel_axis):
333
    img = data.astronaut()[:64, :32]
334
    img[:, :, (1, 2)] = 0
335
    img = np.moveaxis(img, -1, channel_axis)
336
    hog_ref = feature.hog(img, channel_axis=channel_axis, block_norm='L1')
337

338
    for n in (1, 2):
339
        hog_fact = feature.hog(
340
            np.roll(img, n, axis=channel_axis),
341
            channel_axis=channel_axis,
342
            block_norm='L1',
343
        )
344
        assert_almost_equal(hog_ref, hog_fact)
345

346

347
def test_hog_small_image():
348
    """Test that an exception is thrown whenever the input image is
349
    too small for the given parameters.
350
    """
351
    img = np.zeros((24, 24))
352
    feature.hog(img, pixels_per_cell=(8, 8), cells_per_block=(3, 3))
353

354
    img = np.zeros((23, 23))
355
    with pytest.raises(ValueError, match=".*image is too small given"):
356
        feature.hog(
357
            img,
358
            pixels_per_cell=(8, 8),
359
            cells_per_block=(3, 3),
360
        )
361

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.