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,430 @@
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.curvop_numba import curvop, evolution
33
+ from biomedisa.features.biomedisa_helper import (unique_file_path, load_data, save_data,
34
+ pre_processing, img_to_uint8, silent_remove)
35
+ import numpy as np
36
+ import numba
37
+ import argparse
38
+ import traceback
39
+ import subprocess
40
+
41
+ class Biomedisa(object):
42
+ pass
43
+
44
+ @numba.jit(nopython=True)
45
+ def geodis(c,sqrt2,sqrt3,iterations):
46
+ zsh, ysh, xsh = c.shape
47
+ for i in range(iterations):
48
+ for z in range(1,zsh):
49
+ for y in range(1,ysh-1):
50
+ for x in range(1,xsh-1):
51
+ a1 = c[z-1,y-1,x-1] + sqrt3
52
+ a2 = c[z-1,y-1,x] + sqrt2
53
+ a3 = c[z-1,y-1,x+1] + sqrt3
54
+ a4 = c[z-1,y,x-1] + sqrt2
55
+ a5 = c[z-1,y,x] + 1
56
+ a6 = c[z-1,y,x+1] + sqrt2
57
+ a7 = c[z-1,y+1,x-1] + sqrt3
58
+ a8 = c[z-1,y+1,x] + sqrt2
59
+ a9 = c[z-1,y+1,x+1] + sqrt3
60
+ a10 = c[z,y-1,x-1] + sqrt2
61
+ a11 = c[z,y-1,x] + 1
62
+ a12 = c[z,y-1,x+1] + sqrt2
63
+ a13 = c[z,y,x-1] + 1
64
+ a14 = c[z,y,x]
65
+ c[z,y,x] = min(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14)
66
+ for z in range(zsh-2,-1,-1):
67
+ for y in range(ysh-2,0,-1):
68
+ for x in range(xsh-2,0,-1):
69
+ a1 = c[z+1,y-1,x-1] + sqrt3
70
+ a2 = c[z+1,y-1,x] + sqrt2
71
+ a3 = c[z+1,y-1,x+1] + sqrt3
72
+ a4 = c[z+1,y,x-1] + sqrt2
73
+ a5 = c[z+1,y,x] + 1
74
+ a6 = c[z+1,y,x+1] + sqrt2
75
+ a7 = c[z+1,y+1,x-1] + sqrt3
76
+ a8 = c[z+1,y+1,x] + sqrt2
77
+ a9 = c[z+1,y+1,x+1] + sqrt3
78
+ a10 = c[z,y+1,x+1] + sqrt2
79
+ a11 = c[z,y+1,x] + 1
80
+ a12 = c[z,y+1,x-1] + sqrt2
81
+ a13 = c[z,y,x+1] + 1
82
+ a14 = c[z,y,x]
83
+ c[z,y,x] = min(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14)
84
+ return c
85
+
86
+ def reduce_blocksize(raw, slices):
87
+ zsh, ysh, xsh = slices.shape
88
+ argmin_z, argmax_z, argmin_y, argmax_y, argmin_x, argmax_x = zsh, 0, ysh, 0, xsh, 0
89
+ for k in range(zsh):
90
+ y, x = np.nonzero(slices[k])
91
+ if x.any():
92
+ argmin_x = min(argmin_x, np.amin(x))
93
+ argmax_x = max(argmax_x, np.amax(x))
94
+ argmin_y = min(argmin_y, np.amin(y))
95
+ argmax_y = max(argmax_y, np.amax(y))
96
+ argmin_z = min(argmin_z, k)
97
+ argmax_z = max(argmax_z, k)
98
+ argmin_x = argmin_x - 100 if argmin_x - 100 > 0 else 0
99
+ argmax_x = argmax_x + 100 if argmax_x + 100 < xsh else xsh
100
+ argmin_y = argmin_y - 100 if argmin_y - 100 > 0 else 0
101
+ argmax_y = argmax_y + 100 if argmax_y + 100 < ysh else ysh
102
+ argmin_z = argmin_z - 100 if argmin_z - 100 > 0 else 0
103
+ argmax_z = argmax_z + 100 if argmax_z + 100 < zsh else zsh
104
+ raw = raw[argmin_z:argmax_z, argmin_y:argmax_y, argmin_x:argmax_x]
105
+ slices = slices[argmin_z:argmax_z, argmin_y:argmax_y, argmin_x:argmax_x]
106
+ return raw, slices, argmin_z, argmax_z, argmin_y, argmax_y, argmin_x, argmax_x
107
+
108
+ def activeContour(data, labelData, alpha=1.0, smooth=1, steps=3,
109
+ path_to_data=None, path_to_labels=None, no_compression=False,
110
+ ignore='none', only='all', simple=False,
111
+ img_id=None, friend_id=None, remote=False):
112
+
113
+ # create biomedisa
114
+ bm = Biomedisa()
115
+ bm.process = 'acwe'
116
+ bm.success = True
117
+
118
+ # transfer arguments
119
+ key_copy = tuple(locals().keys())
120
+ for arg in key_copy:
121
+ bm.__dict__[arg] = locals()[arg]
122
+
123
+ # django environment
124
+ if bm.img_id is not None:
125
+ bm.django_env = True
126
+ else:
127
+ bm.django_env = False
128
+
129
+ # compression
130
+ if bm.no_compression:
131
+ bm.compression = False
132
+ else:
133
+ bm.compression = True
134
+
135
+ # disable file saving when called as a function
136
+ if bm.data is not None:
137
+ bm.path_to_data = None
138
+ bm.path_to_labels = None
139
+
140
+ if bm.django_env:
141
+ bm.username = os.path.basename(os.path.dirname(bm.path_to_data))
142
+ bm.shortfilename = os.path.basename(bm.path_to_data)
143
+ bm.path_to_logfile = biomedisa.BASE_DIR + '/log/logfile.txt'
144
+
145
+ # pre-processing
146
+ bm = pre_processing(bm)
147
+
148
+ # create path_to_acwe
149
+ if bm.path_to_data:
150
+ filename, extension = os.path.splitext(bm.path_to_labels)
151
+ if extension == '.gz':
152
+ filename = filename[:-4]
153
+ suffix='.refined' if simple else '.acwe'
154
+ path_to_acwe = filename + suffix + bm.final_image_type
155
+
156
+ if bm.success:
157
+
158
+ # data type
159
+ bm.data = img_to_uint8(bm.data)
160
+
161
+ # append data
162
+ zsh, ysh, xsh = bm.data.shape
163
+ tmp = np.zeros((2+zsh, 2+ysh, 2+xsh), dtype=bm.data.dtype)
164
+ tmp[1:-1,1:-1,1:-1] = bm.data
165
+ bm.data = np.copy(tmp, order='C')
166
+ tmp = np.zeros((2+zsh, 2+ysh, 2+xsh), dtype=bm.labelData.dtype)
167
+ tmp[1:-1,1:-1,1:-1] = bm.labelData
168
+ bm.labelData = np.copy(tmp, order='C')
169
+ zsh, ysh, xsh = bm.data.shape
170
+
171
+ # reduce blocksize
172
+ bm.data, bm.labelData, argmin_z, argmax_z, argmin_y, argmax_y, argmin_x, argmax_x = reduce_blocksize(bm.data, bm.labelData)
173
+ bm.labelData = np.copy(bm.labelData, order='C')
174
+ bm.data = np.copy(bm.data, order='C')
175
+
176
+ # active contour
177
+ if simple:
178
+ bm.labelData = refinement(bm)
179
+ else:
180
+ for n in range(bm.steps):
181
+ print('Step:', n+1, '/', bm.steps)
182
+ mean = np.zeros(256, dtype=np.float32)
183
+ for k in bm.allLabels:
184
+ inside = bm.labelData==k
185
+ if np.any(inside):
186
+ mean[k] = np.mean(bm.data[inside])
187
+ bm.labelData = evolution(mean, bm.labelData, bm.data, bm.alpha)
188
+ for k in bm.allLabels:
189
+ bm.labelData = curvop(bm.labelData, bm.smooth, k, bm.allLabels)
190
+
191
+ # return to original data size
192
+ final = np.zeros((zsh, ysh, xsh), dtype=np.uint8)
193
+ final[argmin_z:argmax_z, argmin_y:argmax_y, argmin_x:argmax_x] = bm.labelData
194
+ final = np.copy(final[1:-1, 1:-1, 1:-1], order='C')
195
+
196
+ # save result
197
+ if bm.django_env and not bm.remote:
198
+ path_to_acwe = unique_file_path(path_to_acwe)
199
+ if bm.path_to_data:
200
+ save_data(path_to_acwe, final, bm.header, bm.final_image_type, bm.compression)
201
+
202
+ # post processing
203
+ if bm.django_env:
204
+ post_processing(path_to_acwe, bm.img_id, bm.friend_id, bm.simple, bm.remote)
205
+
206
+ return final
207
+
208
+ def refinement(bm):
209
+ zsh, ysh, xsh = bm.data.shape
210
+ distance = np.zeros(bm.data.shape, dtype=np.float32)
211
+ distance[bm.labelData==0] = 100
212
+ distance = geodis(distance,np.sqrt(2),np.sqrt(3),1)
213
+ distance[distance<=10] = 0
214
+ distance[distance>10] = 1
215
+ distance = distance.astype(np.uint8)
216
+ result = np.zeros_like(bm.labelData)
217
+ for l in bm.allLabels[1:]:
218
+ for k in range(zsh):
219
+ img = bm.data[k]
220
+ mask = bm.labelData[k]
221
+ d = distance[k]
222
+ if np.any(np.logical_and(d==0,mask==l)) and np.any(np.logical_and(d==0,mask!=l)):
223
+ m1,s1 = np.mean(img[np.logical_and(d==0,mask==l)]), np.std(img[np.logical_and(d==0,mask==l)])
224
+ m2,s2 = np.mean(img[np.logical_and(d==0,mask!=l)]), np.std(img[np.logical_and(d==0,mask!=l)])
225
+ s1 = max(s1,1)
226
+ s2 = max(s2,1)
227
+ p1 = np.exp(-(img-m1)**2/(2*s1**2))/np.sqrt(2*np.pi*s1**2)
228
+ p2 = np.exp(-(img-m2)**2/(2*s2**2))/np.sqrt(2*np.pi*s2**2)
229
+ result[k] = np.logical_and(d==0, p1 > p2) * l
230
+ return result
231
+
232
+ def post_processing(path_to_acwe, image_id=None, friend_id=None, simple=False, remote=False):
233
+ if remote:
234
+ with open(biomedisa.BASE_DIR + '/log/config_4', 'w') as configfile:
235
+ print(path_to_acwe, 'phantom', file=configfile)
236
+ else:
237
+ import django
238
+ django.setup()
239
+ from biomedisa_app.models import Upload
240
+ from biomedisa.features.create_slices import create_slices
241
+ from redis import Redis
242
+ from rq import Queue
243
+
244
+ # check if reference data still exists
245
+ image = Upload.objects.filter(pk=image_id)
246
+ friend = Upload.objects.filter(pk=friend_id)
247
+ if len(friend)>0:
248
+ friend = friend[0]
249
+
250
+ # create django object
251
+ shortfilename = os.path.basename(path_to_acwe)
252
+ pic_path = 'images/' + friend.user.username + '/' + shortfilename
253
+ Upload.objects.create(pic=pic_path, user=friend.user, project=friend.project, final=(10 if simple else 3), imageType=3, shortfilename=shortfilename, friend=friend_id)
254
+
255
+ # create slices
256
+ if len(image)>0:
257
+ q = Queue('slices', connection=Redis())
258
+ job = q.enqueue_call(create_slices, args=(image[0].pic.path, path_to_acwe,), timeout=-1)
259
+ else:
260
+ silent_remove(path_to_acwe)
261
+
262
+ def init_active_contour(image_id, friend_id, label_id, simple=False):
263
+ '''
264
+ Runs activeContour() within django environment/webbrowser version
265
+
266
+ Parameters
267
+ ---------
268
+ image_id: int
269
+ Django id of image data
270
+ friend_id: int
271
+ Django id of result data to be processed
272
+ label_id: int
273
+ Django id of label data used for configuration parameters
274
+ simple: bool
275
+ Use simplified version of active contour
276
+
277
+ Returns
278
+ -------
279
+ No returns
280
+ Fails silently
281
+ '''
282
+
283
+ import django
284
+ django.setup()
285
+ from biomedisa_app.models import Upload
286
+ from biomedisa_app.config import config
287
+ from biomedisa_app.views import send_data_to_host, qsub_start, qsub_stop
288
+
289
+ # get objects
290
+ try:
291
+ image = Upload.objects.get(pk=image_id)
292
+ label = Upload.objects.get(pk=label_id)
293
+ friend = Upload.objects.get(pk=friend_id)
294
+ success = True
295
+ except Upload.DoesNotExist:
296
+ success = False
297
+
298
+ # get host information
299
+ host = ''
300
+ host_base = biomedisa.BASE_DIR
301
+ subhost, qsub_pid = None, None
302
+ if 'REMOTE_QUEUE_HOST' in config:
303
+ host = config['REMOTE_QUEUE_HOST']
304
+ if host and 'REMOTE_QUEUE_BASE_DIR' in config:
305
+ host_base = config['REMOTE_QUEUE_BASE_DIR']
306
+
307
+ if success:
308
+
309
+ # remote server
310
+ if host:
311
+
312
+ # command
313
+ cmd = ['python3', host_base+'/biomedisa/features/active_contour.py']
314
+ cmd += [image.pic.path.replace(biomedisa.BASE_DIR,host_base), friend.pic.path.replace(biomedisa.BASE_DIR,host_base)]
315
+ cmd += [f'-iid={image.id}', f'-fid={friend.id}', '-r']
316
+
317
+ # command (append only on demand)
318
+ if simple:
319
+ cmd += ['-si']
320
+ if not label.compression:
321
+ cmd += ['-nc']
322
+ if label.ignore != 'none':
323
+ cmd += [f'-i={label.ignore}']
324
+ if label.only != 'all':
325
+ cmd += [f'-o={label.only}']
326
+ if label.ac_smooth != 1:
327
+ cmd += [f'-s={label.ac_smooth}']
328
+ if label.ac_steps != 3:
329
+ cmd += [f'-st={label.ac_steps}']
330
+ if label.ac_alpha != 1.0:
331
+ cmd += [f'-a={label.ac_alpha}']
332
+
333
+ # create user directory
334
+ subprocess.Popen(['ssh', host, 'mkdir', '-p', host_base+'/private_storage/images/'+image.user.username]).wait()
335
+
336
+ # send data to host
337
+ success=0
338
+ success+=send_data_to_host(image.pic.path, host+':'+image.pic.path.replace(biomedisa.BASE_DIR,host_base))
339
+ success+=send_data_to_host(friend.pic.path, host+':'+friend.pic.path.replace(biomedisa.BASE_DIR,host_base))
340
+
341
+ if success==0:
342
+
343
+ # qsub start
344
+ if 'REMOTE_QUEUE_QSUB' in config and config['REMOTE_QUEUE_QSUB']:
345
+ subhost, qsub_pid = qsub_start(host, host_base, 4)
346
+
347
+ # start active contour
348
+ if subhost:
349
+ cmd = ['ssh', '-t', host, 'ssh', subhost] + cmd
350
+ else:
351
+ cmd = ['ssh', host] + cmd
352
+ subprocess.Popen(cmd).wait()
353
+
354
+ # config
355
+ success = subprocess.Popen(['scp', host+':'+host_base+'/log/config_4', biomedisa.BASE_DIR+'/log/config_4']).wait()
356
+
357
+ if success==0:
358
+ with open(biomedisa.BASE_DIR + '/log/config_4', 'r') as configfile:
359
+ acwe_on_host, _ = configfile.read().split()
360
+
361
+ # local file names
362
+ path_to_acwe = unique_file_path(acwe_on_host.replace(host_base,biomedisa.BASE_DIR))
363
+
364
+ # get results
365
+ subprocess.Popen(['scp', host+':'+acwe_on_host, path_to_acwe]).wait()
366
+
367
+ # post processing
368
+ post_processing(path_to_acwe, image_id=image_id, friend_id=friend_id, simple=simple)
369
+
370
+ # remove config file
371
+ subprocess.Popen(['ssh', host, 'rm', host_base + '/log/config_4']).wait()
372
+
373
+ # local server
374
+ else:
375
+ try:
376
+ activeContour(None, None, path_to_data=image.pic.path, path_to_labels=friend.pic.path,
377
+ alpha=label.ac_alpha, smooth=label.ac_smooth, steps=label.ac_steps,
378
+ no_compression=(False if label.compression else True),
379
+ simple=simple, img_id=image_id, friend_id=friend_id, remote=False)
380
+ except Exception as e:
381
+ print(traceback.format_exc())
382
+
383
+ # qsub stop
384
+ if 'REMOTE_QUEUE_QSUB' in config and config['REMOTE_QUEUE_QSUB']:
385
+ qsub_stop(host, host_base, 4, 'acwe', subhost, qsub_pid)
386
+
387
+ if __name__ == '__main__':
388
+
389
+ # initialize arguments
390
+ parser = argparse.ArgumentParser(description='Biomedisa active contour.',
391
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
392
+
393
+ # required arguments
394
+ parser.add_argument('path_to_data', type=str, metavar='PATH_TO_IMAGE',
395
+ help='Location of image data')
396
+ parser.add_argument('path_to_labels', type=str, metavar='PATH_TO_LABELS',
397
+ help='Location of label data')
398
+
399
+ # optional arguments
400
+ parser.add_argument('-v', '--version', action='version', version=f'{biomedisa.__version__}',
401
+ help='Biomedisa version')
402
+ parser.add_argument('-si','--simple', action='store_true', default=False,
403
+ help='Simplified version of active contour')
404
+ parser.add_argument('-a', '--alpha', type=float, default=1.0,
405
+ help='Driving force of contour')
406
+ parser.add_argument('-s', '--smooth', type=int, default=1,
407
+ help='Number of smoothing steps')
408
+ parser.add_argument('-st', '--steps', type=int, default=3,
409
+ help='Number of iterations')
410
+ parser.add_argument('-nc', '--no_compression', action='store_true', default=False,
411
+ help='Disable compression of segmentation results')
412
+ parser.add_argument('-i', '--ignore', type=str, default='none',
413
+ help='Ignore specific label(s), e.g. 2,5,6')
414
+ parser.add_argument('-o', '--only', type=str, default='all',
415
+ help='Segment only specific label(s), e.g. 1,3,5')
416
+ parser.add_argument('-iid','--img_id', type=str, default=None,
417
+ help='Image ID within django environment/browser version')
418
+ parser.add_argument('-fid','--friend_id', type=str, default=None,
419
+ help='Label ID within django environment/browser version')
420
+ parser.add_argument('-r','--remote', action='store_true', default=False,
421
+ help='Process is carried out on a remote server. Must be set up in config.py')
422
+
423
+ kwargs = vars(parser.parse_args())
424
+
425
+ # run active contour
426
+ try:
427
+ activeContour(None, None, **kwargs)
428
+ except Exception as e:
429
+ print(traceback.format_exc())
430
+
File without changes