biomedisa 2024.5.14__py3-none-any.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.
- biomedisa/__init__.py +53 -0
- biomedisa/__main__.py +18 -0
- biomedisa/biomedisa_features/DataGenerator.py +299 -0
- biomedisa/biomedisa_features/DataGeneratorCrop.py +121 -0
- biomedisa/biomedisa_features/PredictDataGenerator.py +87 -0
- biomedisa/biomedisa_features/PredictDataGeneratorCrop.py +74 -0
- biomedisa/biomedisa_features/__init__.py +0 -0
- biomedisa/biomedisa_features/active_contour.py +434 -0
- biomedisa/biomedisa_features/amira_to_np/__init__.py +0 -0
- biomedisa/biomedisa_features/amira_to_np/amira_data_stream.py +980 -0
- biomedisa/biomedisa_features/amira_to_np/amira_grammar.py +369 -0
- biomedisa/biomedisa_features/amira_to_np/amira_header.py +290 -0
- biomedisa/biomedisa_features/amira_to_np/amira_helper.py +72 -0
- biomedisa/biomedisa_features/assd.py +167 -0
- biomedisa/biomedisa_features/biomedisa_helper.py +801 -0
- biomedisa/biomedisa_features/create_slices.py +286 -0
- biomedisa/biomedisa_features/crop_helper.py +586 -0
- biomedisa/biomedisa_features/curvop_numba.py +149 -0
- biomedisa/biomedisa_features/django_env.py +172 -0
- biomedisa/biomedisa_features/keras_helper.py +1219 -0
- biomedisa/biomedisa_features/nc_reader.py +179 -0
- biomedisa/biomedisa_features/pid.py +52 -0
- biomedisa/biomedisa_features/process_image.py +253 -0
- biomedisa/biomedisa_features/pycuda_test.py +84 -0
- biomedisa/biomedisa_features/random_walk/__init__.py +0 -0
- biomedisa/biomedisa_features/random_walk/gpu_kernels.py +183 -0
- biomedisa/biomedisa_features/random_walk/pycuda_large.py +826 -0
- biomedisa/biomedisa_features/random_walk/pycuda_large_allx.py +806 -0
- biomedisa/biomedisa_features/random_walk/pycuda_small.py +414 -0
- biomedisa/biomedisa_features/random_walk/pycuda_small_allx.py +493 -0
- biomedisa/biomedisa_features/random_walk/pyopencl_large.py +760 -0
- biomedisa/biomedisa_features/random_walk/pyopencl_small.py +441 -0
- biomedisa/biomedisa_features/random_walk/rw_large.py +390 -0
- biomedisa/biomedisa_features/random_walk/rw_small.py +310 -0
- biomedisa/biomedisa_features/remove_outlier.py +399 -0
- biomedisa/biomedisa_features/split_volume.py +274 -0
- biomedisa/deeplearning.py +519 -0
- biomedisa/interpolation.py +371 -0
- biomedisa/mesh.py +406 -0
- biomedisa-2024.5.14.dist-info/LICENSE +191 -0
- biomedisa-2024.5.14.dist-info/METADATA +306 -0
- biomedisa-2024.5.14.dist-info/RECORD +44 -0
- biomedisa-2024.5.14.dist-info/WHEEL +5 -0
- biomedisa-2024.5.14.dist-info/top_level.txt +1 -0
@@ -0,0 +1,371 @@
|
|
1
|
+
#!/usr/bin/python3
|
2
|
+
##########################################################################
|
3
|
+
## ##
|
4
|
+
## Copyright (c) 2024 Philipp Lösel. All rights reserved. ##
|
5
|
+
## ##
|
6
|
+
## This file is part of the open source project biomedisa. ##
|
7
|
+
## ##
|
8
|
+
## Licensed under the European Union Public Licence (EUPL) ##
|
9
|
+
## v1.2, or - as soon as they will be approved by the ##
|
10
|
+
## European Commission - subsequent versions of the EUPL; ##
|
11
|
+
## ##
|
12
|
+
## You may redistribute it and/or modify it under the terms ##
|
13
|
+
## of the EUPL v1.2. You may not use this work except in ##
|
14
|
+
## compliance with this Licence. ##
|
15
|
+
## ##
|
16
|
+
## You can obtain a copy of the Licence at: ##
|
17
|
+
## ##
|
18
|
+
## https://joinup.ec.europa.eu/page/eupl-text-11-12 ##
|
19
|
+
## ##
|
20
|
+
## Unless required by applicable law or agreed to in ##
|
21
|
+
## writing, software distributed under the Licence is ##
|
22
|
+
## distributed on an "AS IS" basis, WITHOUT WARRANTIES ##
|
23
|
+
## OR CONDITIONS OF ANY KIND, either express or implied. ##
|
24
|
+
## ##
|
25
|
+
## See the Licence for the specific language governing ##
|
26
|
+
## permissions and limitations under the Licence. ##
|
27
|
+
## ##
|
28
|
+
##########################################################################
|
29
|
+
|
30
|
+
import sys, os
|
31
|
+
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
32
|
+
sys.path.append(BASE_DIR)
|
33
|
+
import biomedisa
|
34
|
+
from biomedisa_features.biomedisa_helper import (_get_platform, smooth_img_3x3,
|
35
|
+
pre_processing, _error_, read_labeled_slices, read_labeled_slices_allx,
|
36
|
+
read_indices_allx, predict_blocksize)
|
37
|
+
from multiprocessing import freeze_support
|
38
|
+
import numpy as np
|
39
|
+
import argparse
|
40
|
+
import time
|
41
|
+
|
42
|
+
class Biomedisa(object):
|
43
|
+
pass
|
44
|
+
|
45
|
+
def smart_interpolation(data, labelData, nbrw=10, sorw=4000, acwe=False, acwe_alpha=1.0, acwe_smooth=1, acwe_steps=3,
|
46
|
+
path_to_data=None, path_to_labels=None, denoise=False, uncertainty=False, platform=None,
|
47
|
+
allaxis=False, ignore='none', only='all', smooth=0, no_compression=False, return_hits=False,
|
48
|
+
img_id=None, label_id=None, remote=False, queue=0, clean=None, fill=None):
|
49
|
+
|
50
|
+
freeze_support()
|
51
|
+
|
52
|
+
from mpi4py import MPI
|
53
|
+
comm = MPI.COMM_WORLD
|
54
|
+
rank = comm.Get_rank()
|
55
|
+
size = comm.Get_size()
|
56
|
+
|
57
|
+
if rank == 0:
|
58
|
+
|
59
|
+
# create biomedisa
|
60
|
+
bm = Biomedisa()
|
61
|
+
bm.process = 'smart_interpolation'
|
62
|
+
bm.success = True
|
63
|
+
|
64
|
+
# time
|
65
|
+
bm.TIC = time.time()
|
66
|
+
|
67
|
+
# transfer arguments
|
68
|
+
key_copy = tuple(locals().keys())
|
69
|
+
for arg in key_copy:
|
70
|
+
bm.__dict__[arg] = locals()[arg]
|
71
|
+
|
72
|
+
# django environment
|
73
|
+
if bm.img_id is not None:
|
74
|
+
bm.django_env = True
|
75
|
+
else:
|
76
|
+
bm.django_env = False
|
77
|
+
|
78
|
+
# compression
|
79
|
+
if no_compression:
|
80
|
+
bm.compression = False
|
81
|
+
else:
|
82
|
+
bm.compression = True
|
83
|
+
|
84
|
+
# disable file saving when called as a function
|
85
|
+
if bm.data is not None:
|
86
|
+
bm.path_to_data = None
|
87
|
+
bm.path_to_labels = None
|
88
|
+
|
89
|
+
# set pid and write in logfile
|
90
|
+
if bm.django_env:
|
91
|
+
from biomedisa_features.django_env import create_pid_object
|
92
|
+
create_pid_object(os.getpid(), bm.remote, bm.queue, bm.img_id)
|
93
|
+
|
94
|
+
# write in logfile
|
95
|
+
bm.username = os.path.basename(os.path.dirname(bm.path_to_data))
|
96
|
+
bm.shortfilename = os.path.basename(bm.path_to_data)
|
97
|
+
bm.path_to_logfile = BASE_DIR + '/log/logfile.txt'
|
98
|
+
bm.path_to_time = BASE_DIR + '/log/time.txt'
|
99
|
+
with open(bm.path_to_logfile, 'a') as logfile:
|
100
|
+
print('%s %s %s %s' %(time.ctime(), bm.username, bm.shortfilename, 'Process was started.'), file=logfile)
|
101
|
+
|
102
|
+
# pre-processing
|
103
|
+
bm = pre_processing(bm)
|
104
|
+
|
105
|
+
# get platform
|
106
|
+
if bm.success:
|
107
|
+
if bm.platform == 'cuda_force':
|
108
|
+
bm.platform = 'cuda'
|
109
|
+
else:
|
110
|
+
bm = _get_platform(bm)
|
111
|
+
if bm.success == False:
|
112
|
+
bm = _error_(bm, f'No {bm.platform} device found.')
|
113
|
+
|
114
|
+
# smooth, uncertainty and allx are not supported for opencl
|
115
|
+
if bm.success and bm.platform.split('_')[0] == 'opencl':
|
116
|
+
if bm.smooth:
|
117
|
+
bm.smooth = 0
|
118
|
+
print('Warning: Smoothing is not yet supported for opencl. Process starts without smoothing.')
|
119
|
+
if bm.uncertainty:
|
120
|
+
bm.uncertainty = False
|
121
|
+
print('Warning: Uncertainty is not yet supported for opencl. Process starts without uncertainty.')
|
122
|
+
if bm.allaxis:
|
123
|
+
bm = _error_(bm, 'Allx is not yet supported for opencl.')
|
124
|
+
|
125
|
+
if not bm.success:
|
126
|
+
|
127
|
+
# send not executable
|
128
|
+
for dest in range(1, size):
|
129
|
+
comm.send(bm.success, dest=dest, tag=0)
|
130
|
+
|
131
|
+
else:
|
132
|
+
|
133
|
+
# create path_to_final
|
134
|
+
if bm.path_to_data:
|
135
|
+
filename, extension = os.path.splitext(os.path.basename(bm.path_to_data))
|
136
|
+
if extension == '.gz':
|
137
|
+
filename = filename[:-4]
|
138
|
+
filename = 'final.' + filename
|
139
|
+
bm.path_to_final = bm.path_to_data.replace(os.path.basename(bm.path_to_data), filename + bm.final_image_type)
|
140
|
+
|
141
|
+
# paths to optional results
|
142
|
+
filename, extension = os.path.splitext(bm.path_to_final)
|
143
|
+
if extension == '.gz':
|
144
|
+
filename = filename[:-4]
|
145
|
+
bm.path_to_smooth = filename + '.smooth' + bm.final_image_type
|
146
|
+
bm.path_to_smooth_cleaned = filename + '.smooth.cleand' + bm.final_image_type
|
147
|
+
bm.path_to_cleaned = filename + '.cleaned' + bm.final_image_type
|
148
|
+
bm.path_to_filled = filename + '.filled' + bm.final_image_type
|
149
|
+
bm.path_to_cleaned_filled = filename + '.cleaned.filled' + bm.final_image_type
|
150
|
+
bm.path_to_refined = filename + '.refined' + bm.final_image_type
|
151
|
+
bm.path_to_acwe = filename + '.acwe' + bm.final_image_type
|
152
|
+
bm.path_to_uq = filename + '.uncertainty.tif'
|
153
|
+
|
154
|
+
# data type
|
155
|
+
if bm.data.dtype == 'uint8':
|
156
|
+
pass
|
157
|
+
elif bm.data.dtype == 'int8':
|
158
|
+
bm.data = bm.data.astype(np.int16)
|
159
|
+
bm.data += 128
|
160
|
+
bm.data = bm.data.astype(np.uint8)
|
161
|
+
else:
|
162
|
+
bm.data = bm.data.astype(float)
|
163
|
+
bm.data -= np.amin(bm.data)
|
164
|
+
bm.data /= np.amax(bm.data)
|
165
|
+
bm.data *= 255.0
|
166
|
+
bm.data = bm.data.astype(np.float32)
|
167
|
+
|
168
|
+
# denoise image data
|
169
|
+
if bm.denoise:
|
170
|
+
bm.data = smooth_img_3x3(bm.data)
|
171
|
+
|
172
|
+
# image size
|
173
|
+
bm.imageSize = int(bm.data.nbytes * 10e-7)
|
174
|
+
|
175
|
+
# add boundaries
|
176
|
+
zsh, ysh, xsh = bm.data.shape
|
177
|
+
tmp = np.zeros((1+zsh+1, 1+ysh+1, 1+xsh+1), dtype=bm.labelData.dtype)
|
178
|
+
tmp[1:-1, 1:-1, 1:-1] = bm.labelData
|
179
|
+
bm.labelData = tmp.copy(order='C')
|
180
|
+
tmp = np.zeros((1+zsh+1, 1+ysh+1, 1+xsh+1), dtype=bm.data.dtype)
|
181
|
+
tmp[1:-1, 1:-1, 1:-1] = bm.data
|
182
|
+
bm.data = tmp.copy(order='C')
|
183
|
+
bm.zsh, bm.ysh, bm.xsh = bm.data.shape
|
184
|
+
|
185
|
+
# check if labeled slices are adjacent
|
186
|
+
if bm.allaxis:
|
187
|
+
bm.indices = []
|
188
|
+
indices_tmp = read_indices_allx(bm.labelData, 0)
|
189
|
+
bm.indices.extend(indices_tmp)
|
190
|
+
tmp = np.swapaxes(bm.labelData, 0, 1)
|
191
|
+
tmp = np.ascontiguousarray(tmp)
|
192
|
+
indices_tmp = read_indices_allx(tmp, 1)
|
193
|
+
bm.indices.extend(indices_tmp)
|
194
|
+
tmp = np.swapaxes(tmp, 0, 2)
|
195
|
+
tmp = np.ascontiguousarray(tmp)
|
196
|
+
indices_tmp = read_indices_allx(tmp, 2)
|
197
|
+
bm.indices.extend(indices_tmp)
|
198
|
+
|
199
|
+
# labels must not be adjacent
|
200
|
+
neighbours = False
|
201
|
+
for k in range(3):
|
202
|
+
sub_indices = [x for (x, y) in bm.indices if y == k]
|
203
|
+
sub_indices_minus_one = [x - 1 for x in sub_indices]
|
204
|
+
if any(i in sub_indices for i in sub_indices_minus_one):
|
205
|
+
neighbours = True
|
206
|
+
if neighbours:
|
207
|
+
bm = _error_(bm, 'At least one empty slice between labels required.')
|
208
|
+
|
209
|
+
# send executable
|
210
|
+
for dest in range(1, size):
|
211
|
+
comm.send(bm.success, dest=dest, tag=0)
|
212
|
+
|
213
|
+
if bm.success:
|
214
|
+
|
215
|
+
# When is domain decomposition faster?
|
216
|
+
bm = predict_blocksize(bm)
|
217
|
+
nbytes = (bm.argmax_z - bm.argmin_z) * (bm.argmax_y - bm.argmin_y) * (bm.argmax_x - bm.argmin_x) * 4
|
218
|
+
|
219
|
+
# small or large
|
220
|
+
if nbytes * bm.nol < 1e10 and nbytes < 2e9:
|
221
|
+
|
222
|
+
# send "small" to childs
|
223
|
+
for dest in range(1, size):
|
224
|
+
comm.send(1, dest=dest, tag=1)
|
225
|
+
|
226
|
+
# reduce blocksize
|
227
|
+
bm.data = np.copy(bm.data[bm.argmin_z:bm.argmax_z, bm.argmin_y:bm.argmax_y, bm.argmin_x:bm.argmax_x], order='C')
|
228
|
+
bm.labelData = np.copy(bm.labelData[bm.argmin_z:bm.argmax_z, bm.argmin_y:bm.argmax_y, bm.argmin_x:bm.argmax_x], order='C')
|
229
|
+
|
230
|
+
# read labeled slices
|
231
|
+
if bm.allaxis:
|
232
|
+
bm.indices, bm.labels = [], []
|
233
|
+
indices_tmp, labels_tmp = read_labeled_slices_allx(bm.labelData, 0)
|
234
|
+
bm.indices.extend(indices_tmp)
|
235
|
+
bm.labels.append(labels_tmp)
|
236
|
+
tmp = np.swapaxes(bm.labelData, 0, 1)
|
237
|
+
tmp = np.ascontiguousarray(tmp)
|
238
|
+
indices_tmp, labels_tmp = read_labeled_slices_allx(tmp, 1)
|
239
|
+
bm.indices.extend(indices_tmp)
|
240
|
+
bm.labels.append(labels_tmp)
|
241
|
+
tmp = np.swapaxes(tmp, 0, 2)
|
242
|
+
tmp = np.ascontiguousarray(tmp)
|
243
|
+
indices_tmp, labels_tmp = read_labeled_slices_allx(tmp, 2)
|
244
|
+
bm.indices.extend(indices_tmp)
|
245
|
+
bm.labels.append(labels_tmp)
|
246
|
+
else:
|
247
|
+
bm.indices, bm.labels = read_labeled_slices(bm.labelData)
|
248
|
+
|
249
|
+
# number of ngpus
|
250
|
+
ngpus = min(len(bm.indices), size)
|
251
|
+
|
252
|
+
# send number of GPUs to childs
|
253
|
+
for dest in range(1, size):
|
254
|
+
comm.send(ngpus, dest=dest, tag=2)
|
255
|
+
|
256
|
+
# create subcommunicator
|
257
|
+
sub_comm = MPI.Comm.Split(comm, 1, rank)
|
258
|
+
|
259
|
+
from biomedisa_features.random_walk.rw_small import _diffusion_child
|
260
|
+
results = _diffusion_child(sub_comm, bm)
|
261
|
+
|
262
|
+
else:
|
263
|
+
|
264
|
+
# send "large" to childs
|
265
|
+
for dest in range(1, size):
|
266
|
+
comm.send(0, dest=dest, tag=1)
|
267
|
+
|
268
|
+
# number of ngpus
|
269
|
+
ngpus = min((bm.argmax_z - bm.argmin_z) // 100, size)
|
270
|
+
ngpus = max(ngpus, 1)
|
271
|
+
|
272
|
+
# send number of GPUs to childs
|
273
|
+
for dest in range(1, size):
|
274
|
+
comm.send(ngpus, dest=dest, tag=2)
|
275
|
+
|
276
|
+
# create subcommunicator
|
277
|
+
sub_comm = MPI.Comm.Split(comm, 1, rank)
|
278
|
+
|
279
|
+
from biomedisa_features.random_walk.rw_large import _diffusion_child
|
280
|
+
results = _diffusion_child(sub_comm, bm)
|
281
|
+
|
282
|
+
return results
|
283
|
+
|
284
|
+
else:
|
285
|
+
|
286
|
+
# check if executable
|
287
|
+
executable = comm.recv(source=0, tag=0)
|
288
|
+
|
289
|
+
if executable:
|
290
|
+
|
291
|
+
# get small or large
|
292
|
+
small = comm.recv(source=0, tag=1)
|
293
|
+
|
294
|
+
# get number of gpus
|
295
|
+
ngpus = comm.recv(source=0, tag=2)
|
296
|
+
|
297
|
+
# create sub communicator
|
298
|
+
if rank >= ngpus:
|
299
|
+
sub_comm = MPI.Comm.Split(comm, 0, rank) # set process to idle
|
300
|
+
else:
|
301
|
+
sub_comm = MPI.Comm.Split(comm, 1, rank)
|
302
|
+
|
303
|
+
if small:
|
304
|
+
from biomedisa_features.random_walk.rw_small import _diffusion_child
|
305
|
+
_diffusion_child(sub_comm)
|
306
|
+
else:
|
307
|
+
from biomedisa_features.random_walk.rw_large import _diffusion_child
|
308
|
+
_diffusion_child(sub_comm)
|
309
|
+
|
310
|
+
if __name__ == '__main__':
|
311
|
+
|
312
|
+
# initialize arguments
|
313
|
+
parser = argparse.ArgumentParser(description='Biomedisa interpolation.',
|
314
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
315
|
+
|
316
|
+
# required arguments
|
317
|
+
parser.add_argument('path_to_data', type=str, metavar='PATH_TO_IMAGE',
|
318
|
+
help='Location of image data')
|
319
|
+
parser.add_argument('path_to_labels', type=str, metavar='PATH_TO_LABELS',
|
320
|
+
help='Location of label data')
|
321
|
+
|
322
|
+
# optional arguments
|
323
|
+
parser.add_argument('-v', '--version', action='version', version=f'{biomedisa.__version__}',
|
324
|
+
help='Biomedisa version')
|
325
|
+
parser.add_argument('--nbrw', type=int, default=10,
|
326
|
+
help='Number of random walks starting at each pre-segmented pixel')
|
327
|
+
parser.add_argument('--sorw', type=int, default=4000,
|
328
|
+
help='Steps of a random walk')
|
329
|
+
parser.add_argument('--acwe', action='store_true', default=False,
|
330
|
+
help='Post-processing with active contour')
|
331
|
+
parser.add_argument('--acwe_alpha', metavar='ALPHA', type=float, default=1.0,
|
332
|
+
help='Pushing force of active contour')
|
333
|
+
parser.add_argument('--acwe_smooth', metavar='SMOOTH', type=int, default=1,
|
334
|
+
help='Smoothing steps of active contour')
|
335
|
+
parser.add_argument('--acwe_steps', metavar='STEPS', type=int, default=3,
|
336
|
+
help='Iterations of active contour')
|
337
|
+
parser.add_argument('-nc', '--no_compression', action='store_true', default=False,
|
338
|
+
help='Disable compression of segmentation results')
|
339
|
+
parser.add_argument('-allx', '--allaxis', action='store_true', default=False,
|
340
|
+
help='If pre-segmentation is not exlusively in xy-plane')
|
341
|
+
parser.add_argument('-d', '--denoise', action='store_true', default=False,
|
342
|
+
help='Smooth/denoise image data before processing')
|
343
|
+
parser.add_argument('-u', '--uncertainty', action='store_true', default=False,
|
344
|
+
help='Return uncertainty of segmentation result')
|
345
|
+
parser.add_argument('-i', '--ignore', type=str, default='none',
|
346
|
+
help='Ignore specific label(s), e.g. 2,5,6')
|
347
|
+
parser.add_argument('-o', '--only', type=str, default='all',
|
348
|
+
help='Segment only specific label(s), e.g. 1,3,5')
|
349
|
+
parser.add_argument('-s', '--smooth', nargs='?', type=int, const=100, default=0,
|
350
|
+
help='Number of smoothing iterations for segmentation result')
|
351
|
+
parser.add_argument('-c','--clean', nargs='?', type=float, const=0.1, default=None,
|
352
|
+
help='Remove outliers, e.g. 0.5 means that objects smaller than 50 percent of the size of the largest object will be removed')
|
353
|
+
parser.add_argument('-f','--fill', nargs='?', type=float, const=0.9, default=None,
|
354
|
+
help='Fill holes, e.g. 0.5 means that all holes smaller than 50 percent of the entire label will be filled')
|
355
|
+
parser.add_argument('-p', '--platform', default=None,
|
356
|
+
help='One of "cuda", "opencl_NVIDIA_GPU", "opencl_Intel_CPU"')
|
357
|
+
parser.add_argument('-rh','--return_hits', action='store_true', default=False,
|
358
|
+
help='Return hits from each label. Only works for small image data')
|
359
|
+
parser.add_argument('-iid','--img_id', type=str, default=None,
|
360
|
+
help='Image ID within django environment/browser version')
|
361
|
+
parser.add_argument('-lid','--label_id', type=str, default=None,
|
362
|
+
help='Label ID within django environment/browser version')
|
363
|
+
parser.add_argument('-r','--remote', action='store_true', default=False,
|
364
|
+
help='The interpolation is carried out on a remote server. Must be set up in config.py')
|
365
|
+
parser.add_argument('-q','--queue', type=int, default=0,
|
366
|
+
help='Processing queue when using a remote server')
|
367
|
+
kwargs = vars(parser.parse_args())
|
368
|
+
|
369
|
+
# run interpolation
|
370
|
+
smart_interpolation(None, None, **kwargs)
|
371
|
+
|