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.
Files changed (44) hide show
  1. biomedisa/__init__.py +53 -0
  2. biomedisa/__main__.py +18 -0
  3. biomedisa/biomedisa_features/DataGenerator.py +299 -0
  4. biomedisa/biomedisa_features/DataGeneratorCrop.py +121 -0
  5. biomedisa/biomedisa_features/PredictDataGenerator.py +87 -0
  6. biomedisa/biomedisa_features/PredictDataGeneratorCrop.py +74 -0
  7. biomedisa/biomedisa_features/__init__.py +0 -0
  8. biomedisa/biomedisa_features/active_contour.py +434 -0
  9. biomedisa/biomedisa_features/amira_to_np/__init__.py +0 -0
  10. biomedisa/biomedisa_features/amira_to_np/amira_data_stream.py +980 -0
  11. biomedisa/biomedisa_features/amira_to_np/amira_grammar.py +369 -0
  12. biomedisa/biomedisa_features/amira_to_np/amira_header.py +290 -0
  13. biomedisa/biomedisa_features/amira_to_np/amira_helper.py +72 -0
  14. biomedisa/biomedisa_features/assd.py +167 -0
  15. biomedisa/biomedisa_features/biomedisa_helper.py +801 -0
  16. biomedisa/biomedisa_features/create_slices.py +286 -0
  17. biomedisa/biomedisa_features/crop_helper.py +586 -0
  18. biomedisa/biomedisa_features/curvop_numba.py +149 -0
  19. biomedisa/biomedisa_features/django_env.py +172 -0
  20. biomedisa/biomedisa_features/keras_helper.py +1219 -0
  21. biomedisa/biomedisa_features/nc_reader.py +179 -0
  22. biomedisa/biomedisa_features/pid.py +52 -0
  23. biomedisa/biomedisa_features/process_image.py +253 -0
  24. biomedisa/biomedisa_features/pycuda_test.py +84 -0
  25. biomedisa/biomedisa_features/random_walk/__init__.py +0 -0
  26. biomedisa/biomedisa_features/random_walk/gpu_kernels.py +183 -0
  27. biomedisa/biomedisa_features/random_walk/pycuda_large.py +826 -0
  28. biomedisa/biomedisa_features/random_walk/pycuda_large_allx.py +806 -0
  29. biomedisa/biomedisa_features/random_walk/pycuda_small.py +414 -0
  30. biomedisa/biomedisa_features/random_walk/pycuda_small_allx.py +493 -0
  31. biomedisa/biomedisa_features/random_walk/pyopencl_large.py +760 -0
  32. biomedisa/biomedisa_features/random_walk/pyopencl_small.py +441 -0
  33. biomedisa/biomedisa_features/random_walk/rw_large.py +390 -0
  34. biomedisa/biomedisa_features/random_walk/rw_small.py +310 -0
  35. biomedisa/biomedisa_features/remove_outlier.py +399 -0
  36. biomedisa/biomedisa_features/split_volume.py +274 -0
  37. biomedisa/deeplearning.py +519 -0
  38. biomedisa/interpolation.py +371 -0
  39. biomedisa/mesh.py +406 -0
  40. biomedisa-2024.5.14.dist-info/LICENSE +191 -0
  41. biomedisa-2024.5.14.dist-info/METADATA +306 -0
  42. biomedisa-2024.5.14.dist-info/RECORD +44 -0
  43. biomedisa-2024.5.14.dist-info/WHEEL +5 -0
  44. 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
+