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,396 @@
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 (load_data, save_data,
33
+ unique_file_path, silent_remove)
34
+ import numpy as np
35
+ from scipy import ndimage
36
+ import argparse
37
+ import traceback
38
+ import subprocess
39
+
40
+ def reduce_blocksize(data):
41
+ zsh, ysh, xsh = data.shape
42
+ argmin_z, argmax_z, argmin_y, argmax_y, argmin_x, argmax_x = zsh, 0, ysh, 0, xsh, 0
43
+ for k in range(zsh):
44
+ y, x = np.nonzero(data[k])
45
+ if x.any():
46
+ argmin_x = min(argmin_x, np.amin(x))
47
+ argmax_x = max(argmax_x, np.amax(x))
48
+ argmin_y = min(argmin_y, np.amin(y))
49
+ argmax_y = max(argmax_y, np.amax(y))
50
+ argmin_z = min(argmin_z, k)
51
+ argmax_z = max(argmax_z, k)
52
+ argmin_x = max(argmin_x - 1, 0)
53
+ argmax_x = min(argmax_x + 1, xsh-1) + 1
54
+ argmin_y = max(argmin_y - 1, 0)
55
+ argmax_y = min(argmax_y + 1, ysh-1) + 1
56
+ argmin_z = max(argmin_z - 1, 0)
57
+ argmax_z = min(argmax_z + 1, zsh-1) + 1
58
+ data = np.copy(data[argmin_z:argmax_z, argmin_y:argmax_y, argmin_x:argmax_x], order='C')
59
+ return data, argmin_z, argmax_z, argmin_y, argmax_y, argmin_x, argmax_x
60
+
61
+ def clean(image, threshold=0.1):
62
+ image_i = np.copy(image, order='C')
63
+ allLabels = np.unique(image_i)
64
+ mask = np.empty_like(image_i)
65
+ s = [[[0,0,0], [0,1,0], [0,0,0]], [[0,1,0], [1,1,1], [0,1,0]], [[0,0,0], [0,1,0], [0,0,0]]]
66
+ for k in allLabels[1:]:
67
+
68
+ # get mask
69
+ label = image_i==k
70
+ mask.fill(0)
71
+ mask[label] = 1
72
+
73
+ # reduce size
74
+ reduced, argmin_z, argmax_z, argmin_y, argmax_y, argmin_x, argmax_x = reduce_blocksize(mask)
75
+
76
+ # get clusters
77
+ labeled_array, _ = ndimage.label(reduced, structure=s)
78
+ size = np.bincount(labeled_array.ravel())
79
+
80
+ # get reference size
81
+ biggest_label = np.argmax(size[1:]) + 1
82
+ label_size = size[biggest_label]
83
+
84
+ # preserve large segments
85
+ reduced.fill(0)
86
+ for l, m in enumerate(size[1:]):
87
+ if m > threshold * label_size:
88
+ reduced[labeled_array==l+1] = 1
89
+
90
+ # get original size
91
+ mask.fill(0)
92
+ mask[argmin_z:argmax_z, argmin_y:argmax_y, argmin_x:argmax_x] = reduced
93
+
94
+ # write cleaned label to array
95
+ image_i[label] = 0
96
+ image_i[mask==1] = k
97
+
98
+ return image_i
99
+
100
+ def fill(image, threshold=0.9):
101
+ image_i = np.copy(image, order='C')
102
+ allLabels = np.unique(image_i)
103
+ mask = np.empty_like(image_i)
104
+ s = [[[0,0,0], [0,1,0], [0,0,0]], [[0,1,0], [1,1,1], [0,1,0]], [[0,0,0], [0,1,0], [0,0,0]]]
105
+ for k in allLabels[1:]:
106
+
107
+ # get mask
108
+ label = image_i==k
109
+ mask.fill(0)
110
+ mask[label] = 1
111
+
112
+ # reduce size
113
+ reduced, argmin_z, argmax_z, argmin_y, argmax_y, argmin_x, argmax_x = reduce_blocksize(mask)
114
+
115
+ # reference size
116
+ label_size = np.sum(reduced)
117
+
118
+ # invert
119
+ reduced = 1 - reduced # background and holes of object
120
+
121
+ # get clusters
122
+ labeled_array, _ = ndimage.label(reduced, structure=s)
123
+ size = np.bincount(labeled_array.ravel())
124
+ biggest_label = np.argmax(size)
125
+
126
+ # get label with all holes filled
127
+ reduced.fill(1)
128
+ reduced[labeled_array==biggest_label] = 0
129
+
130
+ # preserve large holes
131
+ for l, m in enumerate(size[1:]):
132
+ if m > threshold * label_size and l+1 != biggest_label:
133
+ reduced[labeled_array==l+1] = 0
134
+
135
+ # get original size
136
+ mask.fill(0)
137
+ mask[argmin_z:argmax_z, argmin_y:argmax_y, argmin_x:argmax_x] = reduced
138
+
139
+ # write filled label to array
140
+ image_i[label] = 0
141
+ image_i[mask==1] = k
142
+
143
+ return image_i
144
+
145
+ def main_helper(path_to_labels, img_id=None, friend_id=None, fill_holes=True,
146
+ clean_threshold=0.1, fill_threshold=0.9, remote=False, no_compression=False):
147
+
148
+ # django environment
149
+ if img_id is not None:
150
+ django_env = True
151
+ else:
152
+ django_env = False
153
+
154
+ # compression
155
+ if no_compression:
156
+ compression = False
157
+ else:
158
+ compression = True
159
+
160
+ # final filenames
161
+ filename, extension = os.path.splitext(path_to_labels)
162
+ if extension == '.gz':
163
+ extension = '.nii.gz'
164
+ filename = filename[:-4]
165
+ path_to_cleaned = filename + '.cleaned' + extension
166
+ path_to_filled = filename + '.filled' + extension
167
+ path_to_cleaned_filled = filename + '.cleaned.filled' + extension
168
+
169
+ # load data
170
+ final, header = load_data(path_to_labels, 'cleanup')
171
+
172
+ # process data
173
+ final_cleaned = clean(final, clean_threshold)
174
+ if fill_holes:
175
+ final_filled = fill(final, fill_threshold)
176
+ final_cleaned_filled = final_cleaned + (final_filled - final)
177
+
178
+ # unique_file_paths
179
+ if django_env and not remote:
180
+ path_to_cleaned = unique_file_path(path_to_cleaned)
181
+ path_to_filled = unique_file_path(path_to_filled)
182
+ path_to_cleaned_filled = unique_file_path(path_to_cleaned_filled)
183
+
184
+ # save results
185
+ save_data(path_to_cleaned, final_cleaned, header, extension, compression)
186
+ if fill_holes:
187
+ save_data(path_to_filled, final_filled, header, extension, compression)
188
+ save_data(path_to_cleaned_filled, final_cleaned_filled, header, extension, compression)
189
+
190
+ # post processing
191
+ post_processing(path_to_cleaned, path_to_filled, path_to_cleaned_filled, img_id, friend_id, fill_holes, remote)
192
+
193
+ def post_processing(path_to_cleaned, path_to_filled, path_to_cleaned_filled, img_id=None, friend_id=None, fill_holes=False, remote=False):
194
+ if remote:
195
+ with open(biomedisa.BASE_DIR + '/log/config_6', 'w') as configfile:
196
+ print(path_to_cleaned, path_to_filled, path_to_cleaned_filled, file=configfile)
197
+ else:
198
+ import django
199
+ django.setup()
200
+ from biomedisa_app.models import Upload
201
+ from biomedisa.features.create_slices import create_slices
202
+ from redis import Redis
203
+ from rq import Queue
204
+
205
+ # check if reference data still exists
206
+ image = Upload.objects.filter(pk=img_id)
207
+ friend = Upload.objects.filter(pk=friend_id)
208
+ if len(friend)>0:
209
+ friend = friend[0]
210
+
211
+ # save django object
212
+ shortfilename = os.path.basename(path_to_cleaned)
213
+ pic_path = 'images/' + friend.user.username + '/' + shortfilename
214
+ Upload.objects.create(pic=pic_path, user=friend.user, project=friend.project, final=(2 if fill_holes else 6), imageType=3, shortfilename=shortfilename, friend=friend_id)
215
+
216
+ # create slices for sliceviewer
217
+ if len(image)>0:
218
+ q_slices = Queue('slices', connection=Redis())
219
+ job = q_slices.enqueue_call(create_slices, args=(image[0].pic.path, path_to_cleaned,), timeout=-1)
220
+
221
+ # fill holes
222
+ if fill_holes:
223
+ # save django object
224
+ shortfilename = os.path.basename(path_to_cleaned_filled)
225
+ pic_path = 'images/' + friend.user.username + '/' + shortfilename
226
+ Upload.objects.create(pic=pic_path, user=friend.user, project=friend.project, final=8, imageType=3, shortfilename=shortfilename, friend=friend_id)
227
+ shortfilename = os.path.basename(path_to_filled)
228
+ pic_path = 'images/' + friend.user.username + '/' + shortfilename
229
+ Upload.objects.create(pic=pic_path, user=friend.user, project=friend.project, final=7, imageType=3, shortfilename=shortfilename, friend=friend_id)
230
+
231
+ # create slices for sliceviewer
232
+ if len(image)>0:
233
+ q_slices = Queue('slices', connection=Redis())
234
+ job = q_slices.enqueue_call(create_slices, args=(image[0].pic.path, path_to_filled,), timeout=-1)
235
+ job = q_slices.enqueue_call(create_slices, args=(image[0].pic.path, path_to_cleaned_filled,), timeout=-1)
236
+ else:
237
+ silent_remove(path_to_cleaned)
238
+ silent_remove(path_to_filled)
239
+ silent_remove(path_to_cleaned_filled)
240
+
241
+ def init_remove_outlier(image_id, final_id, label_id, fill_holes=True):
242
+ '''
243
+ Runs clean() and fill() within django environment/webbrowser version
244
+
245
+ Parameters
246
+ ---------
247
+ image_id: int
248
+ Django id of image data used for creating slice preview
249
+ final_id: int
250
+ Django id of result data to be processed
251
+ label_id: int
252
+ Django id of label data used for configuration parameters
253
+ fill_holes: bool
254
+ Fill holes and save as an optional result
255
+
256
+ Returns
257
+ -------
258
+ No returns
259
+ Fails silently
260
+ '''
261
+
262
+ import django
263
+ django.setup()
264
+ from biomedisa_app.models import Upload
265
+ from biomedisa_app.config import config
266
+ from biomedisa_app.views import send_data_to_host, qsub_start, qsub_stop
267
+
268
+ # get objects
269
+ try:
270
+ image = Upload.objects.get(pk=image_id)
271
+ final = Upload.objects.get(pk=final_id)
272
+ label = Upload.objects.get(pk=label_id)
273
+ success = True
274
+ except Upload.DoesNotExist:
275
+ success = False
276
+
277
+ # get host information
278
+ host = ''
279
+ host_base = biomedisa.BASE_DIR
280
+ subhost, qsub_pid = None, None
281
+ if 'REMOTE_QUEUE_HOST' in config:
282
+ host = config['REMOTE_QUEUE_HOST']
283
+ if host and 'REMOTE_QUEUE_BASE_DIR' in config:
284
+ host_base = config['REMOTE_QUEUE_BASE_DIR']
285
+
286
+ if success:
287
+
288
+ # remote server
289
+ if host:
290
+
291
+ # command
292
+ cmd = ['python3', host_base+'/biomedisa/features/remove_outlier.py', final.pic.path.replace(biomedisa.BASE_DIR,host_base)]
293
+ cmd += [f'-iid={image.id}', f'-fid={final.friend}', '-r']
294
+
295
+ # command (append only on demand)
296
+ if fill_holes:
297
+ cmd += ['-fh']
298
+ if not label.compression:
299
+ cmd += ['-nc']
300
+ if label.delete_outliers != 0.1:
301
+ cmd += [f'-c={label.delete_outliers}']
302
+ if label.fill_holes != 0.9:
303
+ cmd += [f'-f={label.fill_holes}']
304
+
305
+ # create user directory
306
+ subprocess.Popen(['ssh', host, 'mkdir', '-p', host_base+'/private_storage/images/'+image.user.username]).wait()
307
+
308
+ # send data to host
309
+ success = send_data_to_host(final.pic.path, host+':'+final.pic.path.replace(biomedisa.BASE_DIR,host_base))
310
+
311
+ if success==0:
312
+
313
+ # qsub start
314
+ if 'REMOTE_QUEUE_QSUB' in config and config['REMOTE_QUEUE_QSUB']:
315
+ subhost, qsub_pid = qsub_start(host, host_base, 6)
316
+
317
+ # start removing outliers
318
+ if subhost:
319
+ cmd = ['ssh', '-t', host, 'ssh', subhost] + cmd
320
+ else:
321
+ cmd = ['ssh', host] + cmd
322
+ subprocess.Popen(cmd).wait()
323
+
324
+ # config
325
+ success = subprocess.Popen(['scp', host+':'+host_base+'/log/config_6', biomedisa.BASE_DIR+'/log/config_6']).wait()
326
+
327
+ if success==0:
328
+ with open(biomedisa.BASE_DIR + '/log/config_6', 'r') as configfile:
329
+ cleaned_on_host, filled_on_host, cleaned_filled_on_host = configfile.read().split()
330
+
331
+ # local file names
332
+ path_to_cleaned = unique_file_path(cleaned_on_host.replace(host_base,biomedisa.BASE_DIR))
333
+ path_to_filled = unique_file_path(filled_on_host.replace(host_base,biomedisa.BASE_DIR))
334
+ path_to_cleaned_filled = unique_file_path(cleaned_filled_on_host.replace(host_base,biomedisa.BASE_DIR))
335
+
336
+ # get results
337
+ subprocess.Popen(['scp', host+':'+cleaned_on_host, path_to_cleaned]).wait()
338
+ if fill_holes:
339
+ subprocess.Popen(['scp', host+':'+filled_on_host, path_to_filled]).wait()
340
+ subprocess.Popen(['scp', host+':'+cleaned_filled_on_host, path_to_cleaned_filled]).wait()
341
+
342
+ # post processing
343
+ post_processing(path_to_cleaned, path_to_filled, path_to_cleaned_filled, image_id, final.friend, fill_holes)
344
+
345
+ # remove config file
346
+ subprocess.Popen(['ssh', host, 'rm', host_base + '/log/config_6']).wait()
347
+
348
+ # local server
349
+ else:
350
+ try:
351
+ main_helper(final.pic.path, img_id=image_id, friend_id=final.friend,
352
+ fill_holes=fill_holes, clean_threshold=label.delete_outliers, fill_threshold=label.fill_holes, remote=False,
353
+ no_compression=(False if label.compression else True))
354
+ except Exception as e:
355
+ print(traceback.format_exc())
356
+
357
+ # qsub stop
358
+ if 'REMOTE_QUEUE_QSUB' in config and config['REMOTE_QUEUE_QSUB']:
359
+ qsub_stop(host, host_base, 6, 'cleanup', subhost, qsub_pid)
360
+
361
+ if __name__ == '__main__':
362
+
363
+ # initialize arguments
364
+ parser = argparse.ArgumentParser(description='Biomedisa remove outliers.',
365
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
366
+
367
+ # required arguments
368
+ parser.add_argument('path_to_labels', type=str, metavar='PATH_TO_LABELS',
369
+ help='Location of label data')
370
+
371
+ # optional arguments
372
+ parser.add_argument('-v', '--version', action='version', version=f'{biomedisa.__version__}',
373
+ help='Biomedisa version')
374
+ parser.add_argument('-fh','--fill_holes', action='store_true', default=False,
375
+ help='Fill holes and save as an optional result')
376
+ parser.add_argument('-c', '--clean_threshold', type=float, default=0.1,
377
+ help='Remove outliers, e.g. 0.5 means that objects smaller than 50 percent of the size of the largest object will be removed')
378
+ parser.add_argument('-f', '--fill_threshold', type=float, default=0.9,
379
+ help='Fill holes, e.g. 0.5 means that all holes smaller than 50 percent of the entire label will be filled')
380
+ parser.add_argument('-nc', '--no_compression', action='store_true', default=False,
381
+ help='Disable compression of segmentation results')
382
+ parser.add_argument('-iid','--img_id', type=str, default=None,
383
+ help='Image ID within django environment/browser version')
384
+ parser.add_argument('-fid','--friend_id', type=str, default=None,
385
+ help='Label ID within django environment/browser version')
386
+ parser.add_argument('-r','--remote', action='store_true', default=False,
387
+ help='Process is carried out on a remote server. Must be set up in config.py')
388
+
389
+ kwargs = vars(parser.parse_args())
390
+
391
+ # main function
392
+ try:
393
+ main_helper(**kwargs)
394
+ except Exception as e:
395
+ print(traceback.format_exc())
396
+
@@ -0,0 +1,167 @@
1
+ ##########################################################################
2
+ ## ##
3
+ ## Copyright (c) 2019-2024 Philipp Lösel. All rights reserved. ##
4
+ ## ##
5
+ ## This file is part of the open source project biomedisa. ##
6
+ ## ##
7
+ ## Licensed under the European Union Public Licence (EUPL) ##
8
+ ## v1.2, or - as soon as they will be approved by the ##
9
+ ## European Commission - subsequent versions of the EUPL; ##
10
+ ## ##
11
+ ## You may redistribute it and/or modify it under the terms ##
12
+ ## of the EUPL v1.2. You may not use this work except in ##
13
+ ## compliance with this Licence. ##
14
+ ## ##
15
+ ## You can obtain a copy of the Licence at: ##
16
+ ## ##
17
+ ## https://joinup.ec.europa.eu/page/eupl-text-11-12 ##
18
+ ## ##
19
+ ## Unless required by applicable law or agreed to in ##
20
+ ## writing, software distributed under the Licence is ##
21
+ ## distributed on an "AS IS" basis, WITHOUT WARRANTIES ##
22
+ ## OR CONDITIONS OF ANY KIND, either express or implied. ##
23
+ ## ##
24
+ ## See the Licence for the specific language governing ##
25
+ ## permissions and limitations under the Licence. ##
26
+ ## ##
27
+ ##########################################################################
28
+
29
+ import os
30
+ from biomedisa.features.biomedisa_helper import load_data, save_data
31
+ from biomedisa.interpolation import smart_interpolation
32
+ from tifffile import imread, imwrite, TiffFile
33
+ import numpy as np
34
+ import argparse
35
+
36
+ if __name__ == '__main__':
37
+
38
+ # initialize arguments
39
+ parser = argparse.ArgumentParser(description='Biomedisa interpolation.',
40
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
41
+
42
+ # required arguments
43
+ parser.add_argument('path_to_data', type=str, metavar='PATH_TO_IMAGE',
44
+ help='Location of image data')
45
+ parser.add_argument('path_to_labels', type=str, metavar='PATH_TO_LABELS',
46
+ help='Location of label data')
47
+
48
+ # optional arguments
49
+ parser.add_argument('-allx', '--allaxis', action='store_true', default=False,
50
+ help='If pre-segmentation is not exlusively in xy-plane')
51
+ parser.add_argument('-u', '--uncertainty', action='store_true', default=False,
52
+ help='Return uncertainty of segmentation result')
53
+ parser.add_argument('-s', '--smooth', nargs='?', type=int, const=100, default=0,
54
+ help='Number of smoothing iterations for segmentation result')
55
+ parser.add_argument('-ol', '--overlap', type=int, default=50,
56
+ help='Overlap of sub-blocks')
57
+ parser.add_argument('-sx','--split_x', type=int, default=1,
58
+ help='Number of sub-blocks in x-direction')
59
+ parser.add_argument('-sy','--split_y', type=int, default=1,
60
+ help='Number of sub-blocks in y-direction')
61
+ parser.add_argument('-sz','--split_z', type=int, default=1,
62
+ help='Number of sub-blocks in z-direction')
63
+ args = parser.parse_args()
64
+
65
+ # image size
66
+ if args.path_to_data[-4:] == '.tif':
67
+ tif = TiffFile(args.path_to_data)
68
+ zsh = len(tif.pages)
69
+ ysh, xsh = tif.pages[0].shape
70
+ else:
71
+ print('Warning: This script is optimized for TIFF files. Please consider saving your data in TIFF format.')
72
+ data, _ = load_data(args.path_to_data)
73
+ shape = np.array(data.shape).copy()
74
+ zsh, ysh, xsh = shape
75
+ del data
76
+
77
+ if args.path_to_labels[-4:] != '.tif':
78
+ print('Warning: This script is optimized for TIFF files. Please consider saving your labels in TIFF format.')
79
+
80
+ # split volume
81
+ sub_size_z = np.ceil(zsh / args.split_z)
82
+ sub_size_y = np.ceil(ysh / args.split_y)
83
+ sub_size_x = np.ceil(xsh / args.split_x)
84
+
85
+ # allocate memory
86
+ final = np.zeros((zsh, ysh, xsh), dtype=np.uint8)
87
+ if args.smooth:
88
+ final_smooth = np.zeros_like(final)
89
+ if args.uncertainty:
90
+ final_uncertainty = np.zeros_like(final)
91
+
92
+ # iterate over subvolumes
93
+ for z_i in range(args.split_z):
94
+ for y_i in range(args.split_y):
95
+ for x_i in range(args.split_x):
96
+ subvolume = z_i * args.split_y * args.split_x + y_i * args.split_x + x_i + 1
97
+ print('Subvolume:', subvolume, '/', args.split_z * args.split_y * args.split_x)
98
+
99
+ # determine z subvolume
100
+ blockmin_z = int(z_i * sub_size_z)
101
+ blockmax_z = int((z_i+1) * sub_size_z)
102
+ datamin_z = max(blockmin_z - args.overlap, 0)
103
+ datamax_z = min(blockmax_z + args.overlap, zsh)
104
+
105
+ # determine y subvolume
106
+ blockmin_y = int(y_i * sub_size_y)
107
+ blockmax_y = int((y_i+1) * sub_size_y)
108
+ datamin_y = max(blockmin_y - args.overlap, 0)
109
+ datamax_y = min(blockmax_y + args.overlap, ysh)
110
+
111
+ # determine x subvolume
112
+ blockmin_x = int(x_i * sub_size_x)
113
+ blockmax_x = int((x_i+1) * sub_size_x)
114
+ datamin_x = max(blockmin_x - args.overlap, 0)
115
+ datamax_x = min(blockmax_x + args.overlap, xsh)
116
+
117
+ # extract image subvolume
118
+ if args.path_to_data[-4:] == '.tif':
119
+ data = imread(args.path_to_data, key=range(datamin_z,datamax_z))
120
+ data = data[:,datamin_y:datamax_y,datamin_x:datamax_x].copy()
121
+ else:
122
+ data, _ = load_data(args.path_to_data)
123
+ data = data[datamin_z:datamax_z,datamin_y:datamax_y,datamin_x:datamax_x].copy()
124
+
125
+ # extract label subvolume
126
+ if args.path_to_labels[-4:] == '.tif':
127
+ header, final_image_type = None, '.tif'
128
+ labelData = imread(args.path_to_labels, key=range(datamin_z,datamax_z))
129
+ labelData = labelData[:,datamin_y:datamax_y,datamin_x:datamax_x].copy()
130
+ else:
131
+ labelData, header, final_image_type = load_data(args.path_to_labels, return_extension=True)
132
+ labelData = labelData[datamin_z:datamax_z,datamin_y:datamax_y,datamin_x:datamax_x].copy()
133
+
134
+ # interpolation
135
+ results = smart_interpolation(data, labelData, uncertainty=args.uncertainty, allaxis=args.allaxis, smooth=args.smooth)
136
+
137
+ # append results
138
+ final[blockmin_z:blockmax_z,blockmin_y:blockmax_y,blockmin_x:blockmax_x] \
139
+ = results['regular'][blockmin_z-datamin_z:blockmax_z-datamin_z,blockmin_y-datamin_y:blockmax_y-datamin_y,blockmin_x-datamin_x:blockmax_x-datamin_x]
140
+ if 'smooth' in results and results['smooth'] is not None:
141
+ final_smooth[blockmin_z:blockmax_z,blockmin_y:blockmax_y,blockmin_x:blockmax_x] \
142
+ = results['smooth'][blockmin_z-datamin_z:blockmax_z-datamin_z,blockmin_y-datamin_y:blockmax_y-datamin_y,blockmin_x-datamin_x:blockmax_x-datamin_x]
143
+ if 'uncertainty' in results and results['uncertainty'] is not None:
144
+ final_uncertainty[blockmin_z:blockmax_z,blockmin_y:blockmax_y,blockmin_x:blockmax_x] \
145
+ = results['uncertainty'][blockmin_z-datamin_z:blockmax_z-datamin_z,blockmin_y-datamin_y:blockmax_y-datamin_y,blockmin_x-datamin_x:blockmax_x-datamin_x]
146
+
147
+ # path to regular result
148
+ filename, extension = os.path.splitext(os.path.basename(args.path_to_data))
149
+ if extension == '.gz':
150
+ filename = filename[:-4]
151
+ filename = 'final.' + filename
152
+ path_to_final = args.path_to_data.replace(os.path.basename(args.path_to_data), filename + final_image_type)
153
+
154
+ # path to optional results
155
+ filename, extension = os.path.splitext(path_to_final)
156
+ if extension == '.gz':
157
+ filename = filename[:-4]
158
+ path_to_smooth = filename + '.smooth' + final_image_type
159
+ path_to_uq = filename + '.uncertainty.tif'
160
+
161
+ # save results
162
+ save_data(path_to_final, final, header)
163
+ if args.smooth:
164
+ save_data(path_to_smooth, final_smooth, header)
165
+ if args.uncertainty:
166
+ imwrite(path_to_uq, final_uncertainty)
167
+