scikit-image

Форк
0
312 строк · 13.3 Кб
1
#cython: cdivision=True
2
#cython: boundscheck=False
3
#cython: nonecheck=False
4
#cython: wraparound=False
5

6
import numpy as np
7

8
cimport numpy as cnp
9
from libcpp.vector cimport vector
10

11
from .._shared.fused_numerics cimport np_real_numeric
12
from .._shared.transform cimport integrate
13

14
FEATURE_TYPE = {'type-2-x': 0, 'type-2-y': 1,
15
                'type-3-x': 2, 'type-3-y': 3,
16
                'type-4': 4}
17

18
N_RECTANGLE = {'type-2-x': 2, 'type-2-y': 2,
19
               'type-3-x': 3, 'type-3-y': 3,
20
               'type-4': 4}
21

22

23
cdef vector[vector[Rectangle]] _haar_like_feature_coord(
24
    Py_ssize_t width,
25
    Py_ssize_t height,
26
    unsigned int feature_type) noexcept nogil:
27
    """Private function to compute the coordinates of all Haar-like features.
28
    """
29
    cdef:
30
        vector[vector[Rectangle]] rect_feat
31
        Rectangle single_rect
32
        Py_ssize_t n_rectangle
33
        Py_ssize_t x, y, dx, dy
34

35
    if feature_type == 0 or feature_type == 1:
36
        n_rectangle = 2
37
    elif feature_type == 2 or feature_type == 3:
38
        n_rectangle = 3
39
    else:
40
        n_rectangle = 4
41

42
    # Allocate for the number of rectangle (we know from the start)
43
    rect_feat = vector[vector[Rectangle]](n_rectangle)
44

45
    for y in range(height):
46
        for x in range(width):
47
            for dy in range(1, height + 1):
48
                for dx in range(1, width + 1):
49
                    # type -> 2 rectangles split along x axis
50
                    if (feature_type == 0 and
51
                            (y + dy <= height and x + 2 * dx <= width)):
52
                        set_rectangle_feature(&single_rect,
53
                                              y, x,
54
                                              y + dy - 1, x + dx - 1)
55
                        rect_feat[0].push_back(single_rect)
56
                        set_rectangle_feature(&single_rect,
57
                                              y, x + dx,
58
                                              y + dy - 1, x + 2 * dx - 1)
59
                        rect_feat[1].push_back(single_rect)
60
                    # type -> 2 rectangles split along y axis
61
                    elif (feature_type == 1 and
62
                          (y + 2 * dy <= height and x + dx <= width)):
63
                        set_rectangle_feature(&single_rect,
64
                                              y, x,
65
                                              y + dy - 1, x + dx - 1)
66
                        rect_feat[0].push_back(single_rect)
67
                        set_rectangle_feature(&single_rect,
68
                                              y + dy, x,
69
                                              y + 2 * dy - 1, x + dx - 1)
70
                        rect_feat[1].push_back(single_rect)
71
                    # type -> 3 rectangles split along x axis
72
                    elif (feature_type == 2 and
73
                          (y + dy <= height and x + 3 * dx <= width)):
74
                        set_rectangle_feature(&single_rect,
75
                                              y, x,
76
                                              y + dy - 1, x + dx - 1)
77
                        rect_feat[0].push_back(single_rect)
78
                        set_rectangle_feature(&single_rect,
79
                                              y, x + dx,
80
                                              y + dy - 1, x + 2 * dx - 1)
81
                        rect_feat[1].push_back(single_rect)
82
                        set_rectangle_feature(&single_rect,
83
                                              y, x + 2 * dx,
84
                                              y + dy - 1, x + 3 * dx - 1)
85
                        rect_feat[2].push_back(single_rect)
86
                    # type -> 3 rectangles split along y axis
87
                    elif (feature_type == 3 and
88
                          (y + 3 * dy <= height and x + dx <= width)):
89
                        set_rectangle_feature(&single_rect,
90
                                              y, x,
91
                                              y + dy - 1, x + dx - 1)
92
                        rect_feat[0].push_back(single_rect)
93
                        set_rectangle_feature(&single_rect,
94
                                              y + dy, x,
95
                                              y + 2 * dy - 1, x + dx - 1)
96
                        rect_feat[1].push_back(single_rect)
97
                        set_rectangle_feature(&single_rect,
98
                                              y + 2 * dy, x,
99
                                              y + 3 * dy - 1, x + dx - 1)
100
                        rect_feat[2].push_back(single_rect)
101
                    # type -> 4 rectangles split along x and y axis
102
                    elif (feature_type == 4 and
103
                          (y + 2 * dy <= height and x + 2 * dx <= width)):
104
                        set_rectangle_feature(&single_rect,
105
                                              y, x,
106
                                              y + dy - 1, x + dx - 1)
107
                        rect_feat[0].push_back(single_rect)
108
                        set_rectangle_feature(&single_rect,
109
                                              y, x + dx,
110
                                              y + dy - 1, x + 2 * dx - 1)
111
                        rect_feat[1].push_back(single_rect)
112
                        set_rectangle_feature(&single_rect,
113
                                              y + dy, x,
114
                                              y + 2 * dy - 1, x + dx - 1)
115
                        rect_feat[3].push_back(single_rect)
116
                        set_rectangle_feature(&single_rect,
117
                                              y + dy, x + dx,
118
                                              y + 2 * dy - 1, x + 2 * dx - 1)
119
                        rect_feat[2].push_back(single_rect)
120

121
    return rect_feat
122

123

124
cpdef haar_like_feature_coord_wrapper(width, height, feature_type):
125
    """Compute the coordinates of Haar-like features.
126

127
    Parameters
128
    ----------
129
    width : int
130
        Width of the detection window.
131
    height : int
132
        Height of the detection window.
133
    feature_type : str
134
        The type of feature to consider:
135

136
        - 'type-2-x': 2 rectangles varying along the x axis;
137
        - 'type-2-y': 2 rectangles varying along the y axis;
138
        - 'type-3-x': 3 rectangles varying along the x axis;
139
        - 'type-3-y': 3 rectangles varying along the y axis;
140
        - 'type-4': 4 rectangles varying along x and y axis.
141

142
    Returns
143
    -------
144
    feature_coord : (n_features, n_rectangles, 2, 2), ndarray of list of \
145
tuple coord
146
        Coordinates of the rectangles for each feature.
147
    feature_type : (n_features,), ndarray of str
148
        The corresponding type for each feature.
149

150
    """
151
    cdef:
152
        vector[vector[Rectangle]] rect
153
        Py_ssize_t n_rectangle, n_feature
154
        Py_ssize_t i, j
155
        # cast the height and width to the right type
156
        Py_ssize_t height_win = <Py_ssize_t> height
157
        Py_ssize_t width_win = <Py_ssize_t> width
158

159
    rect = _haar_like_feature_coord(width_win, height_win,
160
                                    FEATURE_TYPE[feature_type])
161
    n_feature = rect[0].size()
162
    n_rectangle = rect.size()
163

164
    # allocate the output based on the number of rectangle
165
    output = np.empty((n_feature,), dtype=object)
166
    for j in range(n_feature):
167
        coord_feature = []
168
        for i in range(n_rectangle):
169
            coord_feature.append([(rect[i][j].top_left.row,
170
                                   rect[i][j].top_left.col),
171
                                  (rect[i][j].bottom_right.row,
172
                                   rect[i][j].bottom_right.col)])
173
        output[j] = coord_feature
174

175
    return output, np.array([feature_type] * n_feature, dtype=object)
176

177

178
cdef np_real_numeric[:, ::1] _haar_like_feature(
179
        np_real_numeric[:, ::1] int_image,
180
        vector[vector[Rectangle]] coord,
181
        Py_ssize_t n_rectangle, Py_ssize_t n_feature):
182
    """Private function releasing the GIL to compute the integral for the
183
    different rectangle."""
184
    cdef:
185
        np_real_numeric[:, ::1] rect_feature = np.empty(
186
            (n_rectangle, n_feature), dtype=int_image.base.dtype)
187

188
        Py_ssize_t idx_rect, idx_feature
189

190
    with nogil:
191
        for idx_rect in range(n_rectangle):
192
            for idx_feature in range(n_feature):
193
                rect_feature[idx_rect, idx_feature] = integrate(
194
                    int_image,
195
                    coord[idx_rect][idx_feature].top_left.row,
196
                    coord[idx_rect][idx_feature].top_left.col,
197
                    coord[idx_rect][idx_feature].bottom_right.row,
198
                    coord[idx_rect][idx_feature].bottom_right.col)
199

200
    return rect_feature
201

202

203
cpdef haar_like_feature_wrapper(
204
    cnp.ndarray[np_real_numeric, ndim=2] int_image,
205
    r, c, width, height, feature_type, feature_coord):
206
    """Compute the Haar-like features for a region of interest (ROI) of an
207
    integral image.
208

209
    Haar-like features have been successfully used for image classification and
210
    object detection [1]_. It has been used for real-time face detection
211
    algorithm proposed in [2]_.
212

213
    Parameters
214
    ----------
215
    int_image : (M, N) ndarray
216
        Integral image for which the features need to be computed.
217
    r : int
218
        Row-coordinate of top left corner of the detection window.
219
    c : int
220
        Column-coordinate of top left corner of the detection window.
221
    width : int
222
        Width of the detection window.
223
    height : int
224
        Height of the detection window.
225
    feature_type : str
226
        The type of feature to consider:
227

228
        - 'type-2-x': 2 rectangles varying along the x axis;
229
        - 'type-2-y': 2 rectangles varying along the y axis;
230
        - 'type-3-x': 3 rectangles varying along the x axis;
231
        - 'type-3-y': 3 rectangles varying along the y axis;
232
        - 'type-4': 4 rectangles varying along x and y axis.
233

234
    Returns
235
    -------
236
    haar_features : (n_features,) ndarray
237
        Resulting Haar-like features. Each value is equal to the subtraction of
238
        sums of the positive and negative rectangles. The data type depends of
239
        the data type of `int_image`: `int` when the data type of `int_image`
240
        is `uint` or `int` and `float` when the data type of `int_image` is
241
        `float`.
242

243
    References
244
    ----------
245
    .. [1] https://en.wikipedia.org/wiki/Haar-like_feature
246
    .. [2] Oren, M., Papageorgiou, C., Sinha, P., Osuna, E., & Poggio, T.
247
           (1997, June). Pedestrian detection using wavelet templates.
248
           In Computer Vision and Pattern Recognition, 1997. Proceedings.,
249
           1997 IEEE Computer Society Conference on (pp. 193-199). IEEE.
250
           http://tinyurl.com/y6ulxfta
251
           :DOI:`10.1109/CVPR.1997.609319`
252
    .. [3] Viola, Paul, and Michael J. Jones. "Robust real-time face
253
           detection." International journal of computer vision 57.2
254
           (2004): 137-154.
255
           https://www.merl.com/publications/docs/TR2004-043.pdf
256
           :DOI:`10.1109/CVPR.2001.990517`
257

258
    """
259
    cdef:
260
        vector[vector[Rectangle]] coord
261
        Py_ssize_t n_rectangle, n_feature
262
        Py_ssize_t idx_rect, idx_feature
263
        np_real_numeric[:, ::1] rect_feature
264
        # FIXME: currently cython does not support read-only memory views.
265
        # Those are used with joblib when using Parallel. Therefore, we use
266
        # ndarray as input. We take a copy of this ndarray to create a memory
267
        # view to be able to release the GIL in some later processing.
268
        # Check the following issue to check the status of read-only memory
269
        # views in cython:
270
        # https://github.com/cython/cython/issues/1605 to be resolved
271
        np_real_numeric[:, ::1] int_image_memview = int_image[
272
            r : r + height, c : c + width].copy()
273

274
    if feature_coord is None:
275
        # compute all possible coordinates with a specific type of feature
276
        coord = _haar_like_feature_coord(width, height,
277
                                         FEATURE_TYPE[feature_type])
278
        n_feature = coord[0].size()
279
        n_rectangle = coord.size()
280
    else:
281
        # build the coordinate from the set provided
282
        n_rectangle = N_RECTANGLE[feature_type]
283
        n_feature = len(feature_coord)
284

285
        # the vector can be directly pre-allocated since that the size is known
286
        coord = vector[vector[Rectangle]](n_rectangle,
287
                                          vector[Rectangle](n_feature))
288

289
        for idx_rect in range(n_rectangle):
290
            for idx_feature in range(n_feature):
291
                set_rectangle_feature(
292
                    &coord[idx_rect][idx_feature],
293
                    feature_coord[idx_feature][idx_rect][0][0],
294
                    feature_coord[idx_feature][idx_rect][0][1],
295
                    feature_coord[idx_feature][idx_rect][1][0],
296
                    feature_coord[idx_feature][idx_rect][1][1])
297

298
    rect_feature = _haar_like_feature(int_image_memview,
299
                                      coord, n_rectangle, n_feature)
300

301
    # convert the memory view to numpy array and convert it to signed array if
302
    # necessary to avoid overflow during subtraction
303
    rect_feature_ndarray = np.asarray(rect_feature)
304
    data_type = rect_feature_ndarray.dtype
305
    if 'uint' in data_type.name:
306
        rect_feature_ndarray = rect_feature_ndarray.astype(
307
            data_type.name.replace('u', ''))
308

309
    # the rectangles with odd indices can always be subtracted to the rectangle
310
    # with even indices
311
    return (np.sum(rect_feature_ndarray[1::2], axis=0) -
312
            np.sum(rect_feature_ndarray[::2], axis=0))
313

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

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

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

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