-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathfill_voids.pyx
193 lines (154 loc) · 5.9 KB
/
fill_voids.pyx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
"""
Fill in holes in 3D binary images.
Similar to scipy.morphology.binary_fill_holes
but designed to be more performant.
The power of this library derives from the emptiness of space and the
latent energies of the void.
Author: William Silversmith
Affiliation: Seung Lab, Princeton Neuroscience Institute
Date: December 2019
*****************************************************************
This file is part of fill_voids.
fill_voids is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
fill_voids is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with fill_voids. If not, see <https://www.gnu.org/licenses/>.
*****************************************************************
"""
cimport cython
from libc.stdlib cimport calloc, free
from libc.stdint cimport (
int8_t, int16_t, int32_t, int64_t,
uint8_t, uint16_t, uint32_t, uint64_t
)
from libcpp cimport bool as native_bool
from cpython cimport array
import array
import sys
from libcpp.vector cimport vector
from libcpp.unordered_map cimport unordered_map
from libcpp.utility cimport pair as cpp_pair
cimport numpy as cnp
import numpy as np
import fastremap
cdef extern from "math.h":
float INFINITY
ctypedef fused NUMBER:
int8_t
int16_t
int32_t
int64_t
uint8_t
uint16_t
uint32_t
uint64_t
unsigned char
float
double
cdef extern from "fill_voids.hpp" namespace "fill_voids":
cdef size_t binary_fill_holes2d[T](
T* labels,
size_t sx, size_t sy
)
cdef size_t binary_fill_holes3d[T](
T* labels,
size_t sx, size_t sy, size_t sz
)
class DimensionError(Exception):
pass
@cython.binding(True)
def fill(labels, in_place=False, return_fill_count=False):
"""
Fills holes in a 1D, 2D, or 3D binary image.
labels: a binary valued numpy array of any common
integer or floating dtype
in_place: bool, Allow modification of the input array (saves memory)
return_fill_count: Also return the number of voxels that were filled in.
Let IMG = a void filled binary image of the same dtype as labels
if return_fill_count:
Return: (IMG, number of filled in background voxels)
else:
Return: IMG
"""
ndim = labels.ndim
shape = labels.shape
if labels.ndim < 2:
labels = labels[..., np.newaxis]
while labels.ndim > 3:
if labels.shape[-1] == 1:
labels = labels[..., 0]
else:
raise DimensionError("The input volume must be (effectively) a 1D, 2D or 3D image: " + str(shape))
dtype = labels.dtype
if labels.dtype == bool:
labels = labels.view(np.uint8)
if labels.size == 0:
num_filled = 0
elif labels.ndim == 2:
(labels, num_filled) = _fill2d(labels, in_place)
elif labels.ndim == 3:
(labels, num_filled) = _fill3d(labels, in_place)
else:
raise DimensionError("fill_voids only handles 1D, 2D, and 3D data. Got: " + str(shape))
while labels.ndim > ndim:
labels = labels[..., 0]
while labels.ndim < ndim:
labels = labels[..., np.newaxis]
labels = labels.view(dtype)
if return_fill_count:
return (labels, num_filled)
else:
return labels
def _fill3d(cnp.ndarray[NUMBER, cast=True, ndim=3] labels, in_place=False):
if not in_place:
labels = np.copy(labels, order='F')
else:
labels = fastremap.asfortranarray(labels)
dtype = labels.dtype
cdef size_t num_filled = 0
if dtype in (np.uint8, np.int8, bool):
num_filled = binary_fill_holes3d[uint8_t](<uint8_t*>&labels[0,0,0], labels.shape[0], labels.shape[1], labels.shape[2])
elif dtype in (np.uint16, np.int16):
num_filled = binary_fill_holes3d[uint16_t](<uint16_t*>&labels[0,0,0], labels.shape[0], labels.shape[1], labels.shape[2])
elif dtype in (np.uint32, np.int32):
num_filled = binary_fill_holes3d[uint32_t](<uint32_t*>&labels[0,0,0], labels.shape[0], labels.shape[1], labels.shape[2])
elif dtype in (np.uint64, np.int64):
num_filled = binary_fill_holes3d[uint64_t](<uint64_t*>&labels[0,0,0], labels.shape[0], labels.shape[1], labels.shape[2])
elif dtype == np.float32:
num_filled = binary_fill_holes3d[float](<float*>&labels[0,0,0], labels.shape[0], labels.shape[1], labels.shape[2])
elif dtype == np.float64:
num_filled = binary_fill_holes3d[double](<double*>&labels[0,0,0], labels.shape[0], labels.shape[1], labels.shape[2])
else:
raise TypeError("Type {} not supported.".format(dtype))
return (labels, num_filled)
def _fill2d(cnp.ndarray[NUMBER, cast=True, ndim=2] labels, in_place=False):
if not in_place:
labels = np.copy(labels, order='F')
else:
labels = fastremap.asfortranarray(labels)
dtype = labels.dtype
cdef size_t num_filled = 0
if dtype in (np.uint8, np.int8, bool):
num_filled = binary_fill_holes2d[uint8_t](<uint8_t*>&labels[0,0], labels.shape[0], labels.shape[1])
elif dtype in (np.uint16, np.int16):
num_filled = binary_fill_holes2d[uint16_t](<uint16_t*>&labels[0,0], labels.shape[0], labels.shape[1])
elif dtype in (np.uint32, np.int32):
num_filled = binary_fill_holes2d[uint32_t](<uint32_t*>&labels[0,0], labels.shape[0], labels.shape[1])
elif dtype in (np.uint64, np.int64):
num_filled = binary_fill_holes2d[uint64_t](<uint64_t*>&labels[0,0], labels.shape[0], labels.shape[1])
elif dtype == np.float32:
num_filled = binary_fill_holes2d[float](<float*>&labels[0,0], labels.shape[0], labels.shape[1])
elif dtype == np.float64:
num_filled = binary_fill_holes2d[double](<double*>&labels[0,0], labels.shape[0], labels.shape[1])
else:
raise TypeError("Type {} not supported.".format(dtype))
return (labels, num_filled)
def void_shard():
"""??? what's this ???"""
print("Play Starcraft 2!")