imops 0.8.1__cp38-cp38-win32.whl → 0.8.3__cp38-cp38-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of imops might be problematic. Click here for more details.
- _build_utils.py +87 -0
- imops/__init__.py +1 -0
- imops/__version__.py +1 -1
- imops/backend.py +14 -10
- imops/box.py +20 -29
- imops/crop.py +18 -2
- imops/interp1d.py +16 -13
- imops/measure.py +12 -9
- imops/morphology.py +155 -35
- imops/numeric.py +376 -0
- imops/pad.py +41 -5
- imops/radon.py +9 -7
- imops/src/_backprojection.c +83 -83
- imops/src/_backprojection.cp38-win32.pyd +0 -0
- imops/src/_fast_backprojection.c +98 -98
- imops/src/_fast_backprojection.cp38-win32.pyd +0 -0
- imops/src/_fast_measure.c +98 -98
- imops/src/_fast_measure.cp38-win32.pyd +0 -0
- imops/src/_fast_morphology.c +2783 -1568
- imops/src/_fast_morphology.cp38-win32.pyd +0 -0
- imops/src/_fast_morphology.pyx +315 -131
- imops/src/_fast_numeric.c +20547 -4998
- imops/src/_fast_numeric.cp38-win32.pyd +0 -0
- imops/src/_fast_numeric.pyx +208 -30
- imops/src/_fast_radon.c +98 -98
- imops/src/_fast_radon.cp38-win32.pyd +0 -0
- imops/src/_fast_zoom.c +5947 -3344
- imops/src/_fast_zoom.cp38-win32.pyd +0 -0
- imops/src/_fast_zoom.pyx +1 -0
- imops/src/_measure.c +83 -83
- imops/src/_measure.cp38-win32.pyd +0 -0
- imops/src/_morphology.c +2768 -1553
- imops/src/_morphology.cp38-win32.pyd +0 -0
- imops/src/_morphology.pyx +315 -131
- imops/src/_numeric.c +20532 -4983
- imops/src/_numeric.cp38-win32.pyd +0 -0
- imops/src/_numeric.pyx +208 -30
- imops/src/_radon.c +83 -83
- imops/src/_radon.cp38-win32.pyd +0 -0
- imops/src/_zoom.c +5932 -3329
- imops/src/_zoom.cp38-win32.pyd +0 -0
- imops/src/_zoom.pyx +1 -0
- imops/utils.py +113 -13
- imops/zoom.py +9 -9
- {imops-0.8.1.dist-info → imops-0.8.3.dist-info}/METADATA +40 -19
- imops-0.8.3.dist-info/RECORD +60 -0
- {imops-0.8.1.dist-info → imops-0.8.3.dist-info}/WHEEL +1 -1
- imops-0.8.3.dist-info/top_level.txt +2 -0
- _pyproject_build.py +0 -49
- imops/_numeric.py +0 -124
- imops-0.8.1.dist-info/RECORD +0 -60
- imops-0.8.1.dist-info/top_level.txt +0 -2
- {imops-0.8.1.dist-info → imops-0.8.3.dist-info}/LICENSE +0 -0
|
Binary file
|
imops/src/_fast_morphology.pyx
CHANGED
|
@@ -11,135 +11,319 @@ cimport numpy as np
|
|
|
11
11
|
|
|
12
12
|
from cython.parallel import prange
|
|
13
13
|
|
|
14
|
+
from libc.stdlib cimport abort, free, malloc
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
cdef
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
for
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
16
|
+
|
|
17
|
+
cdef struct array_iterator:
|
|
18
|
+
int rank_m1
|
|
19
|
+
int dimensions[3]
|
|
20
|
+
int coordinates[3]
|
|
21
|
+
int strides[3]
|
|
22
|
+
int backstrides[3]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
cdef int init_array_iterator(array_iterator *arr_iter, int *shape, int *strides) nogil:
|
|
26
|
+
cdef int i
|
|
27
|
+
|
|
28
|
+
arr_iter.rank_m1 = 2
|
|
29
|
+
|
|
30
|
+
for i in range(3):
|
|
31
|
+
arr_iter[0].dimensions[i] = shape[i] - 1
|
|
32
|
+
arr_iter[0].coordinates[i] = 0
|
|
33
|
+
arr_iter[0].strides[i] = strides[i]
|
|
34
|
+
arr_iter[0].backstrides[i] = strides[i] * arr_iter[0].dimensions[i]
|
|
35
|
+
|
|
36
|
+
return 0
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
cdef struct filter_iterator:
|
|
40
|
+
int strides[3]
|
|
41
|
+
int backstrides[3]
|
|
42
|
+
int bound1[3]
|
|
43
|
+
int bound2[3]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
cdef int init_filter_iterator(
|
|
47
|
+
filter_iterator *filter_iter,
|
|
48
|
+
int *a_shape,
|
|
49
|
+
int *f_shape,
|
|
50
|
+
int filter_size,
|
|
51
|
+
np.uint8_t is_dilation
|
|
52
|
+
) nogil:
|
|
53
|
+
cdef int i, rank = 3, step, orgn
|
|
54
|
+
|
|
55
|
+
filter_iter[0].strides[rank - 1] = filter_size
|
|
56
|
+
for i in range(rank - 2, -1, -1):
|
|
57
|
+
step = a_shape[i + 1] if a_shape[i + 1] < f_shape[i + 1] else f_shape[i + 1]
|
|
58
|
+
filter_iter[0].strides[i] = filter_iter[0].strides[i + 1] * step
|
|
59
|
+
|
|
60
|
+
for i in range(rank):
|
|
61
|
+
step = a_shape[i] if a_shape[i] < f_shape[i] else f_shape[i]
|
|
62
|
+
orgn = f_shape[i] // 2
|
|
63
|
+
if is_dilation and f_shape[i] % 2 == 0:
|
|
64
|
+
orgn -= 1
|
|
65
|
+
|
|
66
|
+
filter_iter[0].backstrides[i] = (step - 1) * filter_iter[0].strides[i]
|
|
67
|
+
filter_iter[0].bound1[i] = orgn
|
|
68
|
+
filter_iter[0].bound2[i] = a_shape[i] - f_shape[i] + orgn
|
|
69
|
+
|
|
70
|
+
return 0
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
cdef int init_filter_offsets(
|
|
74
|
+
int *a_shape, int *a_strides,
|
|
75
|
+
np.uint8_t *footprint, int *f_shape,
|
|
76
|
+
int footprint_size,
|
|
77
|
+
int **offsets, int *border_flag_value,
|
|
78
|
+
np.uint8_t is_dilation
|
|
79
|
+
) nogil:
|
|
80
|
+
cdef int i, j, k
|
|
81
|
+
cdef int filter_size = 1, offsets_size = 1
|
|
82
|
+
cdef int max_size = 0, max_stride = 0
|
|
83
|
+
cdef int coordinates[3]
|
|
84
|
+
cdef int position[3]
|
|
85
|
+
cdef int *po
|
|
86
|
+
cdef int stride, offset, orgn, cc
|
|
87
|
+
|
|
88
|
+
for i in range(3):
|
|
89
|
+
filter_size *= f_shape[i]
|
|
90
|
+
|
|
91
|
+
for i in range(3):
|
|
92
|
+
offsets_size *= (a_shape[i] if a_shape[i] < f_shape[i] else f_shape[i])
|
|
93
|
+
|
|
94
|
+
offsets[0] = <int*>malloc(offsets_size * footprint_size * sizeof(int))
|
|
95
|
+
if offsets[0] == NULL:
|
|
96
|
+
abort()
|
|
97
|
+
|
|
98
|
+
for i in range(3):
|
|
99
|
+
if a_shape[i] > max_size:
|
|
100
|
+
max_size = a_shape[i]
|
|
101
|
+
|
|
102
|
+
stride = -a_strides[i] if a_strides[i] < 0 else a_strides[i]
|
|
103
|
+
|
|
104
|
+
if stride > max_stride:
|
|
105
|
+
max_stride = stride
|
|
106
|
+
|
|
107
|
+
coordinates[i] = 0
|
|
108
|
+
position[i] = 0
|
|
109
|
+
|
|
110
|
+
border_flag_value[0] = max_size * max_stride + 1
|
|
111
|
+
po = offsets[0]
|
|
112
|
+
|
|
113
|
+
for j in range(offsets_size):
|
|
114
|
+
for k in range(filter_size):
|
|
115
|
+
offset = 0
|
|
116
|
+
|
|
117
|
+
# only calculate an offset if the footprint is 1:
|
|
118
|
+
if footprint[k]:
|
|
119
|
+
# find offsets along all axes:
|
|
120
|
+
for i in range(3):
|
|
121
|
+
orgn = f_shape[i] // 2
|
|
122
|
+
if is_dilation and f_shape[i] % 2 == 0:
|
|
123
|
+
orgn -= 1
|
|
124
|
+
cc = coordinates[i] - orgn + position[i]
|
|
125
|
+
|
|
126
|
+
if cc < 0 or cc >= a_shape[i]:
|
|
127
|
+
offset = border_flag_value[0]
|
|
128
|
+
break
|
|
129
|
+
else:
|
|
130
|
+
# use an offset that is possibly mapped from outside the border:
|
|
131
|
+
cc -= position[i]
|
|
132
|
+
offset += a_strides[i] * cc
|
|
133
|
+
|
|
134
|
+
# store the offset
|
|
135
|
+
po[0] = offset
|
|
136
|
+
po += 1
|
|
137
|
+
|
|
138
|
+
# next point in the filter:
|
|
139
|
+
for i in range(3 - 1, -1, -1):
|
|
140
|
+
if coordinates[i] < f_shape[i] - 1:
|
|
141
|
+
coordinates[i] += 1
|
|
142
|
+
break
|
|
143
|
+
else:
|
|
144
|
+
coordinates[i] = 0
|
|
145
|
+
|
|
146
|
+
# move to the next array region:
|
|
147
|
+
for i in range(3 - 1, -1, -1):
|
|
148
|
+
orgn = f_shape[i] // 2
|
|
149
|
+
if is_dilation and f_shape[i] % 2 == 0:
|
|
150
|
+
orgn -= 1
|
|
151
|
+
|
|
152
|
+
if position[i] == orgn:
|
|
153
|
+
position[i] += a_shape[i] - f_shape[i] + 1
|
|
154
|
+
|
|
155
|
+
if position[i] <= orgn:
|
|
156
|
+
position[i] = orgn + 1
|
|
157
|
+
else:
|
|
158
|
+
position[i] += 1
|
|
159
|
+
|
|
160
|
+
if position[i] < a_shape[i]:
|
|
161
|
+
break
|
|
162
|
+
else:
|
|
163
|
+
position[i] = 0
|
|
164
|
+
|
|
165
|
+
return 0
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
cdef inline int filter_iterator_offset(filter_iterator *filter_iter, int *coordinates) nogil:
|
|
169
|
+
cdef int i, position, offset = 0
|
|
170
|
+
|
|
171
|
+
for i in range(3):
|
|
172
|
+
if filter_iter[0].bound1[i] > filter_iter[0].bound2[i]:
|
|
173
|
+
position = coordinates[i]
|
|
174
|
+
elif coordinates[i] < filter_iter[0].bound1[i]:
|
|
175
|
+
position = coordinates[i]
|
|
176
|
+
elif coordinates[i] >= filter_iter[0].bound2[i]:
|
|
177
|
+
position = filter_iter[0].bound1[i] + coordinates[i] - filter_iter[0].bound2[i]
|
|
178
|
+
else:
|
|
179
|
+
position = filter_iter[0].bound1[i]
|
|
180
|
+
|
|
181
|
+
offset += filter_iter[0].strides[i] * position
|
|
182
|
+
|
|
183
|
+
return offset
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
cdef inline int worker(
|
|
187
|
+
np.uint8_t *input, np.uint8_t *footprint, np.uint8_t *output,
|
|
188
|
+
int *a_shape, int *a_strides, int *f_shape,
|
|
189
|
+
int footprint_size,
|
|
190
|
+
int *offsets, int border_flag_value,
|
|
191
|
+
int start, int end,
|
|
192
|
+
np.uint8_t border_value,
|
|
193
|
+
np.uint8_t is_dilation,
|
|
194
|
+
) nogil:
|
|
195
|
+
cdef np.uint8_t _true = not is_dilation
|
|
196
|
+
cdef np.uint8_t _false = not _true
|
|
197
|
+
|
|
198
|
+
cdef array_iterator input_iter
|
|
199
|
+
cdef filter_iterator filter_iter
|
|
200
|
+
|
|
201
|
+
init_array_iterator(&input_iter, a_shape, a_strides)
|
|
202
|
+
|
|
203
|
+
init_filter_iterator(&filter_iter, a_shape, f_shape, footprint_size, is_dilation)
|
|
204
|
+
|
|
205
|
+
cdef int temp = start
|
|
206
|
+
for i in range(3):
|
|
207
|
+
input_iter.coordinates[i] = temp // input_iter.strides[i]
|
|
208
|
+
temp %= input_iter.strides[i]
|
|
209
|
+
|
|
210
|
+
cdef np.uint8_t *pi = input + start
|
|
211
|
+
cdef np.uint8_t *po = output + start
|
|
212
|
+
cdef int *oo = offsets + filter_iterator_offset(&filter_iter, <int*>input_iter.coordinates)
|
|
213
|
+
|
|
214
|
+
cdef np.uint8_t out
|
|
215
|
+
cdef int _oo, _pp
|
|
216
|
+
|
|
217
|
+
for j in range(start, end):
|
|
218
|
+
out = _true
|
|
219
|
+
|
|
220
|
+
for i in range(footprint_size):
|
|
221
|
+
_oo = oo[i]
|
|
222
|
+
|
|
223
|
+
if _oo == border_flag_value:
|
|
224
|
+
if border_value == _false:
|
|
225
|
+
out = _false
|
|
226
|
+
break
|
|
227
|
+
elif pi[_oo] == _false:
|
|
228
|
+
out = _false
|
|
229
|
+
break
|
|
230
|
+
|
|
231
|
+
po[0] = out
|
|
232
|
+
|
|
233
|
+
# pointers and filter next
|
|
234
|
+
for i in range(input_iter.rank_m1, -1, -1):
|
|
235
|
+
_pp = input_iter.coordinates[i]
|
|
236
|
+
|
|
237
|
+
if _pp < input_iter.dimensions[i]:
|
|
238
|
+
if _pp < filter_iter.bound1[i] or _pp >= filter_iter.bound2[i]:
|
|
239
|
+
oo += filter_iter.strides[i]
|
|
240
|
+
|
|
241
|
+
input_iter.coordinates[i] += 1
|
|
242
|
+
break
|
|
243
|
+
else:
|
|
244
|
+
input_iter.coordinates[i] = 0
|
|
245
|
+
|
|
246
|
+
oo -= filter_iter.backstrides[i]
|
|
247
|
+
|
|
248
|
+
pi += 1
|
|
249
|
+
po += 1
|
|
250
|
+
|
|
251
|
+
return 0
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _binary_operation(
|
|
255
|
+
np.uint8_t[:, :, :] input,
|
|
256
|
+
np.uint8_t[:, :, :] footprint,
|
|
257
|
+
np.uint8_t[:, :, ::1] out,
|
|
258
|
+
Py_ssize_t num_threads,
|
|
259
|
+
np.uint8_t border_value,
|
|
260
|
+
np.uint8_t is_dilation,
|
|
261
|
+
) -> np.ndarray:
|
|
262
|
+
cdef np.uint8_t[:, :, ::1] c_input = np.ascontiguousarray(input)
|
|
263
|
+
cdef np.uint8_t[:, :, ::1] c_footprint = np.ascontiguousarray(footprint)
|
|
264
|
+
|
|
265
|
+
cdef int f_shape[3]
|
|
266
|
+
cdef int a_shape[3]
|
|
267
|
+
cdef int a_strides[3]
|
|
268
|
+
for i in range(3):
|
|
269
|
+
f_shape[i] = c_footprint.shape[i]
|
|
270
|
+
a_shape[i] = c_input.shape[i]
|
|
271
|
+
a_strides[i] = c_input.strides[i]
|
|
272
|
+
|
|
273
|
+
cdef int footprint_size = np.sum(c_footprint)
|
|
274
|
+
cdef int size = np.size(c_input)
|
|
275
|
+
|
|
276
|
+
cdef int *offsets
|
|
277
|
+
cdef int border_flag_value
|
|
278
|
+
|
|
279
|
+
init_filter_offsets(
|
|
280
|
+
a_shape, a_strides,
|
|
281
|
+
&c_footprint[0, 0, 0], f_shape, footprint_size,
|
|
282
|
+
&offsets, &border_flag_value,
|
|
283
|
+
is_dilation
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
cdef int task, start, chunk
|
|
287
|
+
|
|
288
|
+
cdef int _mod = size % num_threads, _div = size // num_threads
|
|
289
|
+
|
|
290
|
+
for task in prange(num_threads, nogil=True, num_threads=num_threads):
|
|
291
|
+
if task < _mod:
|
|
292
|
+
chunk = _div + 1
|
|
293
|
+
start = chunk * task
|
|
294
|
+
else:
|
|
295
|
+
chunk = _div
|
|
296
|
+
start = chunk * task + _mod
|
|
297
|
+
|
|
298
|
+
worker(
|
|
299
|
+
&c_input[0, 0, 0], &c_footprint[0, 0, 0], &out[0, 0, 0],
|
|
300
|
+
a_shape, a_strides, f_shape,
|
|
301
|
+
footprint_size,
|
|
302
|
+
offsets, border_flag_value,
|
|
303
|
+
start, start + chunk,
|
|
304
|
+
border_value,
|
|
305
|
+
is_dilation
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
free(offsets)
|
|
309
|
+
|
|
310
|
+
return np.asarray(out)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def _binary_erosion(
|
|
314
|
+
np.uint8_t[:, :, :] input,
|
|
315
|
+
np.uint8_t[:, :, :] footprint,
|
|
316
|
+
np.uint8_t[:, :, ::1] out,
|
|
317
|
+
Py_ssize_t num_threads,
|
|
318
|
+
) -> np.ndarray:
|
|
319
|
+
return _binary_operation(input, footprint, out, num_threads, True, False)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def _binary_dilation(
|
|
323
|
+
np.uint8_t[:, :, :] input,
|
|
324
|
+
np.uint8_t[:, :, :] footprint,
|
|
325
|
+
np.uint8_t[:, :, ::1] out,
|
|
326
|
+
Py_ssize_t num_threads,
|
|
327
|
+
) -> np.ndarray:
|
|
328
|
+
inverted_footprint = np.array(footprint[::-1, ::-1, ::-1])
|
|
329
|
+
return _binary_operation(input, inverted_footprint, out, num_threads, False, True)
|