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