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