biomedisa 24.8.6__py3-none-any.whl → 24.8.8__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.
biomedisa/deeplearning.py CHANGED
@@ -71,7 +71,7 @@ def deep_learning(img_data, label_data=None, val_img_data=None, val_label_data=N
71
71
  learning_rate=0.01, stride_size=32, validation_stride_size=32, validation_freq=1,
72
72
  batch_size=None, x_scale=256, y_scale=256, z_scale=256, scaling=True, early_stopping=0,
73
73
  pretrained_model=None, fine_tune=False, workers=1, cropping_epochs=50,
74
- x_range=None, y_range=None, z_range=None, header=None, extension='.tif',
74
+ x_range=None, y_range=None, z_range=None, header=None, extension=None,
75
75
  img_header=None, img_extension='.tif', average_dice=False, django_env=False,
76
76
  path=None, success=True, return_probs=False, patch_normalization=False,
77
77
  z_patch=64, y_patch=64, x_patch=64, path_to_logfile=None, img_id=None, label_id=None,
@@ -228,9 +228,11 @@ def deep_learning(img_data, label_data=None, val_img_data=None, val_label_data=N
228
228
  bm.scaling = bool(meta['scaling'][()])
229
229
 
230
230
  # check if amira header is available in the network
231
- if bm.header is None and meta.get('header') is not None:
231
+ if bm.extension is None and bm.header is None and meta.get('header') is not None:
232
232
  bm.header = [np.array(meta.get('header'))]
233
233
  bm.extension = '.am'
234
+ if bm.extension is None:
235
+ bm.extension = '.tif'
234
236
 
235
237
  # crop data
236
238
  crop_data = True if 'cropping_weights' in hf else False
@@ -301,6 +303,12 @@ def deep_learning(img_data, label_data=None, val_img_data=None, val_label_data=N
301
303
  results, bm = predict_segmentation(bm, region_of_interest,
302
304
  channels, normalization_parameters)
303
305
 
306
+ from mpi4py import MPI
307
+ comm = MPI.COMM_WORLD
308
+ rank = comm.Get_rank()
309
+ if rank>0:
310
+ return 0
311
+
304
312
  # results
305
313
  if cropped_volume is not None:
306
314
  results['cropped_volume'] = cropped_volume
@@ -361,7 +369,7 @@ if __name__ == '__main__':
361
369
  parser.add_argument('path_to_images', type=str, metavar='PATH_TO_IMAGES',
362
370
  help='Location of image data (tarball, directory, or file)')
363
371
  parser.add_argument('path', type=str, metavar='PATH',
364
- help='Location of label data during training (tarball, directory, or file) or model for prediction (h5)')
372
+ help='Location of label data for training (tarball, directory, or file) or model for prediction (.h5)')
365
373
 
366
374
  # optional arguments
367
375
  g.add_argument('-p','--predict', action='store_true', default=False,
@@ -488,8 +496,10 @@ if __name__ == '__main__':
488
496
  help='Location of mask')
489
497
  parser.add_argument('-rf','--refinement', action='store_true', default=False,
490
498
  help='Refine segmentation on full size data')
491
- parser.add_argument('-ext','--extension', type=str, default='.tif',
492
- help='Save data for example as NRRD file using --extension=".nrrd"')
499
+ parser.add_argument('-ext','--extension', type=str, default=None,
500
+ help='Save data in formats like NRRD or TIFF using --extension=".nrrd"')
501
+ parser.add_argument('-ptm','--path_to_model', type=str, metavar='PATH', default=None,
502
+ help='Specify the model location for training')
493
503
  bm = parser.parse_args()
494
504
  bm.success = True
495
505
 
@@ -505,7 +515,8 @@ if __name__ == '__main__':
505
515
  bm.path_to_model = bm.path
506
516
  if bm.train:
507
517
  bm.path_to_labels = bm.path
508
- bm.path_to_model = bm.path_to_images + '.h5'
518
+ if bm.path_to_model is None:
519
+ bm.path_to_model = bm.path_to_images + '.h5'
509
520
 
510
521
  # django environment
511
522
  if bm.img_id is not None:
@@ -424,8 +424,6 @@ def load_training_data(bm, img_list, label_list, channels, img_in=None, label_in
424
424
 
425
425
  # if header is not single data stream Amira Mesh falling back to Multi-TIFF
426
426
  if extension != '.am':
427
- if extension != '.tif':
428
- print(f'Warning! Please use --header_file="path_to_training_label{extension}" for prediction to save your result as "{extension}"')
429
427
  extension, header = '.tif', None
430
428
  elif len(header) > 1:
431
429
  print('Warning! Multiple data streams are not supported. Falling back to TIFF.')
@@ -798,6 +796,35 @@ class Metrics(Callback):
798
796
  if self.early_stopping > 0 and max(self.history['val_dice']) not in self.history['val_dice'][-self.early_stopping:]:
799
797
  self.model.stop_training = True
800
798
 
799
+ class HistoryCallback(Callback):
800
+ def __init__(self, bm):
801
+ self.path_to_model = bm.path_to_model
802
+ self.train_dice = bm.train_dice
803
+ self.val_img_data = bm.val_img_data
804
+
805
+ def on_train_begin(self, logs={}):
806
+ self.history = {}
807
+ self.history['loss'] = []
808
+ self.history['accuracy'] = []
809
+ if self.train_dice:
810
+ self.history['dice'] = []
811
+ if self.val_img_data is not None:
812
+ self.history['val_loss'] = []
813
+ self.history['val_accuracy'] = []
814
+
815
+ def on_epoch_end(self, epoch, logs={}):
816
+ # append history
817
+ self.history['loss'].append(logs['loss'])
818
+ self.history['accuracy'].append(logs['accuracy'])
819
+ if self.train_dice:
820
+ self.history['dice'].append(logs['dice'])
821
+ if self.val_img_data is not None:
822
+ self.history['val_loss'].append(logs['val_loss'])
823
+ self.history['val_accuracy'].append(logs['val_accuracy'])
824
+
825
+ # plot history in figure and save as numpy array
826
+ save_history(self.history, self.path_to_model)
827
+
801
828
  def softmax(x):
802
829
  # Avoiding numerical instability by subtracting the maximum value
803
830
  exp_values = np.exp(x - np.max(x, axis=-1, keepdims=True))
@@ -1020,11 +1047,11 @@ def train_segmentation(bm):
1020
1047
  monitor='val_accuracy',
1021
1048
  mode='max',
1022
1049
  save_best_only=True)
1023
- callbacks = [model_checkpoint_callback, meta_data]
1050
+ callbacks = [model_checkpoint_callback, HistoryCallback(bm), meta_data]
1024
1051
  if bm.early_stopping > 0:
1025
1052
  callbacks.insert(0, EarlyStopping(monitor='val_accuracy', mode='max', patience=bm.early_stopping))
1026
1053
  else:
1027
- callbacks = [ModelCheckpoint(filepath=str(bm.path_to_model)), meta_data]
1054
+ callbacks = [ModelCheckpoint(filepath=str(bm.path_to_model)), HistoryCallback(bm), meta_data]
1028
1055
 
1029
1056
  # monitor dice score on training data
1030
1057
  if bm.train_dice:
@@ -1035,15 +1062,11 @@ def train_segmentation(bm):
1035
1062
  callbacks.insert(-1, CustomCallback(bm.img_id, bm.epochs))
1036
1063
 
1037
1064
  # train model
1038
- history = model.fit(training_generator,
1039
- epochs=bm.epochs,
1040
- validation_data=validation_generator,
1041
- callbacks=callbacks,
1042
- workers=bm.workers)
1043
-
1044
- # save monitoring figure on train end
1045
- if bm.val_img_data is None or not bm.val_dice:
1046
- save_history(history.history, bm.path_to_model)
1065
+ model.fit(training_generator,
1066
+ epochs=bm.epochs,
1067
+ validation_data=validation_generator,
1068
+ callbacks=callbacks,
1069
+ workers=bm.workers)
1047
1070
 
1048
1071
  def load_prediction_data(bm, channels, normalize, normalization_parameters,
1049
1072
  region_of_interest, img, img_header, load_blockwise=False, z=None):
@@ -1151,6 +1174,21 @@ def gradient(volData):
1151
1174
 
1152
1175
  def predict_segmentation(bm, region_of_interest, channels, normalization_parameters):
1153
1176
 
1177
+ from mpi4py import MPI
1178
+ comm = MPI.COMM_WORLD
1179
+ rank = comm.Get_rank()
1180
+ ngpus = comm.Get_size()
1181
+
1182
+ # Set the visible GPU by ID
1183
+ gpus = tf.config.experimental.list_physical_devices('GPU')
1184
+ if gpus:
1185
+ try:
1186
+ # Restrict TensorFlow to only use the specified GPU
1187
+ tf.config.experimental.set_visible_devices(gpus[rank], 'GPU')
1188
+ tf.config.experimental.set_memory_growth(gpus[rank], True)
1189
+ except RuntimeError as e:
1190
+ print(e)
1191
+
1154
1192
  # initialize results
1155
1193
  results = {}
1156
1194
 
@@ -1177,6 +1215,7 @@ def predict_segmentation(bm, region_of_interest, channels, normalization_paramet
1177
1215
  load_blockwise = False
1178
1216
  if not bm.scaling and not bm.normalize and bm.path_to_image and not np.any(region_of_interest) and \
1179
1217
  os.path.splitext(bm.path_to_image)[1] in ['.tif', '.tiff'] and not bm.acwe:
1218
+ # get image shape
1180
1219
  tif = TiffFile(bm.path_to_image)
1181
1220
  zsh = len(tif.pages)
1182
1221
  ysh, xsh = tif.pages[0].shape
@@ -1292,17 +1331,23 @@ def predict_segmentation(bm, region_of_interest, channels, normalization_paramet
1292
1331
  # stream data batchwise to GPU to reduce memory usage
1293
1332
  X = np.empty((bm.batch_size, bm.z_patch, bm.y_patch, bm.x_patch, channels), dtype=np.float32)
1294
1333
 
1295
- # allocate final array
1296
- if bm.return_probs:
1334
+ # allocate final probabilities array
1335
+ if rank==0 and bm.return_probs:
1297
1336
  final = np.zeros((zsh, ysh, xsh, nb_labels), dtype=np.float32)
1298
1337
 
1299
- # allocate result array
1300
- label = np.zeros((zsh, ysh, xsh), dtype=np.uint8)
1338
+ # allocate final result array
1339
+ if rank==0:
1340
+ label = np.zeros((zsh, ysh, xsh), dtype=np.uint8)
1301
1341
 
1302
1342
  # predict segmentation block by block
1303
1343
  z_indices = range(0, zsh-bm.z_patch+1, bm.stride_size)
1304
1344
  for j, z in enumerate(z_indices):
1305
-
1345
+ # handle len(z_indices) % ngpus != 0
1346
+ if len(z_indices)-1-j < ngpus:
1347
+ nprocs = len(z_indices)-j
1348
+ else:
1349
+ nprocs = ngpus
1350
+ if j % ngpus == rank:
1306
1351
  # load blockwise from TIFF
1307
1352
  if load_blockwise:
1308
1353
  img, _, _, _, _, _, _ = load_prediction_data(bm,
@@ -1336,8 +1381,11 @@ def predict_segmentation(bm, region_of_interest, channels, normalization_paramet
1336
1381
  # number of patches
1337
1382
  nb_patches = len(list_IDs_block)
1338
1383
 
1339
- # allocate tmp probabilities array
1340
- probs = np.zeros((bm.z_patch, ysh, xsh, nb_labels), dtype=np.float32)
1384
+ # allocate block array
1385
+ if bm.separation:
1386
+ block_label = np.zeros((bm.z_patch, ysh, xsh), dtype=np.uint8)
1387
+ else:
1388
+ block_probs = np.zeros((bm.z_patch, ysh, xsh, nb_labels), dtype=np.float32)
1341
1389
 
1342
1390
  # get one batch of image patches
1343
1391
  for step in range(nb_patches//bm.batch_size):
@@ -1369,157 +1417,186 @@ def predict_segmentation(bm, region_of_interest, channels, normalization_paramet
1369
1417
  if step*bm.batch_size+i < max_i_block:
1370
1418
  if bm.separation:
1371
1419
  patch = np.argmax(Y[i], axis=-1).astype(np.uint8)
1372
- label[z:z+bm.z_patch,l:l+bm.y_patch,m:m+bm.x_patch] += gradient(patch)
1420
+ block_label[:,l:l+bm.y_patch,m:m+bm.x_patch] += gradient(patch)
1373
1421
  else:
1374
- probs[:,l:l+bm.y_patch,m:m+bm.x_patch] += Y[i]
1375
-
1376
- if not bm.separation:
1377
- # overlap in z direction
1378
- if bm.stride_size < bm.z_patch:
1379
- if j>0:
1380
- probs[:bm.stride_size] += overlap
1381
- overlap = probs[bm.stride_size:].copy()
1382
-
1383
- # calculate result
1384
- if z==z_indices[-1]:
1385
- label[z:z+bm.z_patch] = np.argmax(probs, axis=-1).astype(np.uint8)
1386
- if bm.return_probs:
1387
- final[z:z+bm.z_patch] = probs
1422
+ block_probs[:,l:l+bm.y_patch,m:m+bm.x_patch] += Y[i]
1423
+
1424
+ # communicate results
1425
+ if bm.separation:
1426
+ if rank==0:
1427
+ label[z:z+bm.z_patch] += block_label
1428
+ for source in range(1, nprocs):
1429
+ receivedata = np.empty_like(block_label)
1430
+ for i in range(bm.z_patch):
1431
+ comm.Recv([receivedata[i], MPI.BYTE], source=source, tag=i)
1432
+ block_start = z_indices[j+source]
1433
+ label[block_start:block_start+bm.z_patch] += receivedata
1388
1434
  else:
1389
- block_zsh = min(bm.stride_size, bm.z_patch)
1390
- label[z:z+block_zsh] = np.argmax(probs[:block_zsh], axis=-1).astype(np.uint8)
1391
- if bm.return_probs:
1392
- final[z:z+block_zsh] = probs[:block_zsh]
1393
-
1394
- # refine mask data with result
1395
- if bm.refinement:
1396
- # loop over boundary patches
1397
- for i, ID in enumerate(list_IDs):
1398
- if i < max_i:
1399
- k = ID // (ysh*xsh)
1400
- rest = ID % (ysh*xsh)
1401
- l = rest // xsh
1402
- m = rest % xsh
1403
- mask[k:k+bm.z_patch, l:l+bm.y_patch, m:m+bm.x_patch] = label[k:k+bm.z_patch, l:l+bm.y_patch, m:m+bm.x_patch]
1404
- label = mask
1405
-
1406
- # remove appendix
1407
- if bm.return_probs:
1408
- final = final[:-z_rest,:-y_rest,:-x_rest]
1409
- label = label[:-z_rest,:-y_rest,:-x_rest]
1410
- zsh, ysh, xsh = label.shape
1411
-
1412
- # return probabilities
1413
- if bm.return_probs:
1414
- counter = np.zeros((zsh, ysh, xsh, nb_labels), dtype=np.float32)
1415
- nb = 0
1416
- for k in range(0, zsh-bm.z_patch+1, bm.stride_size):
1417
- for l in range(0, ysh-bm.y_patch+1, bm.stride_size):
1418
- for m in range(0, xsh-bm.x_patch+1, bm.stride_size):
1419
- counter[k:k+bm.z_patch, l:l+bm.y_patch, m:m+bm.x_patch] += 1
1420
- nb += 1
1421
- counter[counter==0] = 1
1422
- probabilities = final / counter
1435
+ for i in range(bm.z_patch):
1436
+ comm.Send([block_label[i].copy(), MPI.BYTE], dest=0, tag=i)
1437
+ else:
1438
+ if rank==0:
1439
+ for source in range(nprocs):
1440
+ if source>0:
1441
+ probs = np.empty_like(block_probs)
1442
+ for i in range(bm.z_patch):
1443
+ comm.Recv([probs[i], MPI.FLOAT], source=source, tag=i)
1444
+ else:
1445
+ probs = block_probs
1446
+
1447
+ # overlap in z direction
1448
+ if bm.stride_size < bm.z_patch:
1449
+ if j+source>0:
1450
+ probs[:bm.stride_size] += overlap
1451
+ overlap = probs[bm.stride_size:].copy()
1452
+
1453
+ # calculate result
1454
+ block_z = z_indices[j+source]
1455
+ if j+source==len(z_indices)-1:
1456
+ label[block_z:block_z+bm.z_patch] = np.argmax(probs, axis=-1).astype(np.uint8)
1457
+ if bm.return_probs:
1458
+ final[block_z:block_z+bm.z_patch] = probs
1459
+ else:
1460
+ block_zsh = min(bm.stride_size, bm.z_patch)
1461
+ label[block_z:block_z+block_zsh] = np.argmax(probs[:block_zsh], axis=-1).astype(np.uint8)
1462
+ if bm.return_probs:
1463
+ final[block_z:block_z+block_zsh] = probs[:block_zsh]
1464
+ else:
1465
+ for i in range(bm.z_patch):
1466
+ comm.Send([block_probs[i].copy(), MPI.FLOAT], dest=0, tag=i)
1467
+ if rank==0:
1468
+
1469
+ # refine mask data with result
1470
+ if bm.refinement:
1471
+ # loop over boundary patches
1472
+ for i, ID in enumerate(list_IDs):
1473
+ if i < max_i:
1474
+ k = ID // (ysh*xsh)
1475
+ rest = ID % (ysh*xsh)
1476
+ l = rest // xsh
1477
+ m = rest % xsh
1478
+ mask[k:k+bm.z_patch, l:l+bm.y_patch, m:m+bm.x_patch] = label[k:k+bm.z_patch, l:l+bm.y_patch, m:m+bm.x_patch]
1479
+ label = mask
1480
+
1481
+ # remove appendix
1482
+ if bm.return_probs:
1483
+ final = final[:-z_rest,:-y_rest,:-x_rest]
1484
+ label = label[:-z_rest,:-y_rest,:-x_rest]
1485
+ zsh, ysh, xsh = label.shape
1486
+
1487
+ # return probabilities
1488
+ if bm.return_probs:
1489
+ counter = np.zeros((zsh, ysh, xsh, nb_labels), dtype=np.float32)
1490
+ nb = 0
1491
+ for k in range(0, zsh-bm.z_patch+1, bm.stride_size):
1492
+ for l in range(0, ysh-bm.y_patch+1, bm.stride_size):
1493
+ for m in range(0, xsh-bm.x_patch+1, bm.stride_size):
1494
+ counter[k:k+bm.z_patch, l:l+bm.y_patch, m:m+bm.x_patch] += 1
1495
+ nb += 1
1496
+ counter[counter==0] = 1
1497
+ probabilities = final / counter
1498
+ if bm.scaling:
1499
+ probabilities = img_resize(probabilities, z_shape, y_shape, x_shape)
1500
+ if np.any(region_of_interest):
1501
+ min_z,max_z,min_y,max_y,min_x,max_x,original_zsh,original_ysh,original_xsh = region_of_interest[:]
1502
+ tmp = np.zeros((original_zsh, original_ysh, original_xsh, nb_labels), dtype=np.float32)
1503
+ tmp[min_z:max_z,min_y:max_y,min_x:max_x] = probabilities
1504
+ probabilities = np.copy(tmp, order='C')
1505
+ results['probs'] = probabilities
1506
+
1507
+ # rescale final to input size
1423
1508
  if bm.scaling:
1424
- probabilities = img_resize(probabilities, z_shape, y_shape, x_shape)
1509
+ label = img_resize(label, z_shape, y_shape, x_shape, labels=True)
1510
+
1511
+ # revert automatic cropping
1425
1512
  if np.any(region_of_interest):
1426
1513
  min_z,max_z,min_y,max_y,min_x,max_x,original_zsh,original_ysh,original_xsh = region_of_interest[:]
1427
- tmp = np.zeros((original_zsh, original_ysh, original_xsh, nb_labels), dtype=np.float32)
1428
- tmp[min_z:max_z,min_y:max_y,min_x:max_x] = probabilities
1429
- probabilities = np.copy(tmp, order='C')
1430
- results['probs'] = probabilities
1431
-
1432
- # rescale final to input size
1433
- if bm.scaling:
1434
- label = img_resize(label, z_shape, y_shape, x_shape, labels=True)
1514
+ tmp = np.zeros((original_zsh, original_ysh, original_xsh), dtype=np.uint8)
1515
+ tmp[min_z:max_z,min_y:max_y,min_x:max_x] = label
1516
+ label = np.copy(tmp, order='C')
1517
+
1518
+ # get result
1519
+ if not bm.separation:
1520
+ label = get_labels(label, bm.allLabels)
1521
+ results['regular'] = label
1522
+
1523
+ # load header from file
1524
+ if bm.header_file and os.path.exists(bm.header_file):
1525
+ _, bm.header = load_data(bm.header_file)
1526
+ # update file extension
1527
+ if bm.header is not None and bm.path_to_image:
1528
+ bm.extension = os.path.splitext(bm.header_file)[1]
1529
+ if bm.extension == '.gz':
1530
+ bm.extension = '.nii.gz'
1531
+ bm.path_to_final = os.path.splitext(bm.path_to_final)[0] + bm.extension
1532
+ if bm.django_env and not bm.remote and not bm.tarfile:
1533
+ bm.path_to_final = unique_file_path(bm.path_to_final)
1534
+
1535
+ # handle amira header
1536
+ if bm.header is not None:
1537
+ if bm.extension == '.am':
1538
+ bm.header = set_image_dimensions(bm.header[0], label)
1539
+ if bm.img_header is not None:
1540
+ try:
1541
+ bm.header = set_physical_size(bm.header, bm.img_header[0])
1542
+ except:
1543
+ pass
1544
+ bm.header = [bm.header]
1545
+ else:
1546
+ # build new header
1547
+ if bm.img_header is None:
1548
+ zsh, ysh, xsh = label.shape
1549
+ bm.img_header = sitk.Image(xsh, ysh, zsh, bm.header.GetPixelID())
1550
+ # copy metadata
1551
+ for key in bm.header.GetMetaDataKeys():
1552
+ if not (re.match(r'Segment\d+_Extent$', key) or key=='Segmentation_ConversionParameters'):
1553
+ bm.img_header.SetMetaData(key, bm.header.GetMetaData(key))
1554
+ bm.header = bm.img_header
1555
+ results['header'] = bm.header
1556
+
1557
+ # save result
1558
+ if bm.path_to_image:
1559
+ save_data(bm.path_to_final, label, header=bm.header, compress=bm.compression)
1435
1560
 
1436
- # revert automatic cropping
1437
- if np.any(region_of_interest):
1438
- min_z,max_z,min_y,max_y,min_x,max_x,original_zsh,original_ysh,original_xsh = region_of_interest[:]
1439
- tmp = np.zeros((original_zsh, original_ysh, original_xsh), dtype=np.uint8)
1440
- tmp[min_z:max_z,min_y:max_y,min_x:max_x] = label
1441
- label = np.copy(tmp, order='C')
1442
-
1443
- # get result
1444
- if not bm.separation:
1445
- label = get_labels(label, bm.allLabels)
1446
- results['regular'] = label
1447
-
1448
- # load header from file
1449
- if bm.header_file and os.path.exists(bm.header_file):
1450
- _, bm.header = load_data(bm.header_file)
1451
- # update file extension
1452
- if bm.header is not None and bm.path_to_image:
1453
- bm.extension = os.path.splitext(bm.header_file)[1]
1561
+ # paths to optional results
1562
+ filename, bm.extension = os.path.splitext(bm.path_to_final)
1454
1563
  if bm.extension == '.gz':
1455
1564
  bm.extension = '.nii.gz'
1456
- bm.path_to_final = os.path.splitext(bm.path_to_final)[0] + bm.extension
1457
- if bm.django_env and not bm.remote and not bm.tarfile:
1458
- bm.path_to_final = unique_file_path(bm.path_to_final)
1459
-
1460
- # handle amira header
1461
- if bm.header is not None:
1462
- if bm.extension == '.am':
1463
- bm.header = set_image_dimensions(bm.header[0], label)
1464
- if bm.img_header is not None:
1465
- try:
1466
- bm.header = set_physical_size(bm.header, bm.img_header[0])
1467
- except:
1468
- pass
1469
- bm.header = [bm.header]
1470
- else:
1471
- # build new header
1472
- if bm.img_header is None:
1473
- zsh, ysh, xsh = label.shape
1474
- bm.img_header = sitk.Image(xsh, ysh, zsh, bm.header.GetPixelID())
1475
- # copy metadata
1476
- for key in bm.header.GetMetaDataKeys():
1477
- if not (re.match(r'Segment\d+_Extent$', key) or key=='Segmentation_ConversionParameters'):
1478
- bm.img_header.SetMetaData(key, bm.header.GetMetaData(key))
1479
- bm.header = bm.img_header
1480
- results['header'] = bm.header
1481
-
1482
- # save result
1483
- if bm.path_to_image:
1484
- save_data(bm.path_to_final, label, header=bm.header, compress=bm.compression)
1485
-
1486
- # paths to optional results
1487
- filename, bm.extension = os.path.splitext(bm.path_to_final)
1488
- if bm.extension == '.gz':
1489
- bm.extension = '.nii.gz'
1490
- filename = filename[:-4]
1491
- path_to_cleaned = filename + '.cleaned' + bm.extension
1492
- path_to_filled = filename + '.filled' + bm.extension
1493
- path_to_cleaned_filled = filename + '.cleaned.filled' + bm.extension
1494
- path_to_refined = filename + '.refined' + bm.extension
1495
- path_to_acwe = filename + '.acwe' + bm.extension
1496
-
1497
- # remove outliers
1498
- if bm.clean:
1499
- cleaned_result = clean(label, bm.clean)
1500
- results['cleaned'] = cleaned_result
1501
- if bm.path_to_image:
1502
- save_data(path_to_cleaned, cleaned_result, header=bm.header, compress=bm.compression)
1503
- if bm.fill:
1504
- filled_result = clean(label, bm.fill)
1505
- results['filled'] = filled_result
1506
- if bm.path_to_image:
1507
- save_data(path_to_filled, filled_result, header=bm.header, compress=bm.compression)
1508
- if bm.clean and bm.fill:
1509
- cleaned_filled_result = cleaned_result + (filled_result - label)
1510
- results['cleaned_filled'] = cleaned_filled_result
1511
- if bm.path_to_image:
1512
- save_data(path_to_cleaned_filled, cleaned_filled_result, header=bm.header, compress=bm.compression)
1513
-
1514
- # post-processing with active contour
1515
- if bm.acwe:
1516
- acwe_result = activeContour(bm.img_data, label, bm.acwe_alpha, bm.acwe_smooth, bm.acwe_steps)
1517
- refined_result = activeContour(bm.img_data, label, simple=True)
1518
- results['acwe'] = acwe_result
1519
- results['refined'] = refined_result
1520
- if bm.path_to_image:
1521
- save_data(path_to_acwe, acwe_result, header=bm.header, compress=bm.compression)
1522
- save_data(path_to_refined, refined_result, header=bm.header, compress=bm.compression)
1523
-
1524
- return results, bm
1565
+ filename = filename[:-4]
1566
+ path_to_cleaned = filename + '.cleaned' + bm.extension
1567
+ path_to_filled = filename + '.filled' + bm.extension
1568
+ path_to_cleaned_filled = filename + '.cleaned.filled' + bm.extension
1569
+ path_to_refined = filename + '.refined' + bm.extension
1570
+ path_to_acwe = filename + '.acwe' + bm.extension
1571
+
1572
+ # remove outliers
1573
+ if bm.clean:
1574
+ cleaned_result = clean(label, bm.clean)
1575
+ results['cleaned'] = cleaned_result
1576
+ if bm.path_to_image:
1577
+ save_data(path_to_cleaned, cleaned_result, header=bm.header, compress=bm.compression)
1578
+ if bm.fill:
1579
+ filled_result = clean(label, bm.fill)
1580
+ results['filled'] = filled_result
1581
+ if bm.path_to_image:
1582
+ save_data(path_to_filled, filled_result, header=bm.header, compress=bm.compression)
1583
+ if bm.clean and bm.fill:
1584
+ cleaned_filled_result = cleaned_result + (filled_result - label)
1585
+ results['cleaned_filled'] = cleaned_filled_result
1586
+ if bm.path_to_image:
1587
+ save_data(path_to_cleaned_filled, cleaned_filled_result, header=bm.header, compress=bm.compression)
1588
+
1589
+ # post-processing with active contour
1590
+ if bm.acwe:
1591
+ acwe_result = activeContour(bm.img_data, label, bm.acwe_alpha, bm.acwe_smooth, bm.acwe_steps)
1592
+ refined_result = activeContour(bm.img_data, label, simple=True)
1593
+ results['acwe'] = acwe_result
1594
+ results['refined'] = refined_result
1595
+ if bm.path_to_image:
1596
+ save_data(path_to_acwe, acwe_result, header=bm.header, compress=bm.compression)
1597
+ save_data(path_to_refined, refined_result, header=bm.header, compress=bm.compression)
1598
+
1599
+ return results, bm
1600
+ else:
1601
+ return None, None
1525
1602
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: biomedisa
3
- Version: 24.8.6
3
+ Version: 24.8.8
4
4
  Summary: Segmentation of 3D volumetric image data
5
5
  Author: Philipp Lösel
6
6
  Author-email: philipp.loesel@anu.edu.au
@@ -10,7 +10,7 @@ Project-URL: GitHub, https://github.com/biomedisa/biomedisa
10
10
  Classifier: Programming Language :: Python :: 3
11
11
  Classifier: License :: OSI Approved :: European Union Public Licence 1.2 (EUPL 1.2)
12
12
  Classifier: Operating System :: OS Independent
13
- Requires-Python: >=3.8
13
+ Requires-Python: >=3.10
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
16
 
@@ -19,6 +19,7 @@ License-File: LICENSE
19
19
  - [Overview](#overview)
20
20
  - [Hardware Requirements](#hardware-requirements)
21
21
  - [Installation (command-line based)](#installation-command-line-based)
22
+ - [Installation (3D Slicer extension)](#installation-3d-slicer-extension)
22
23
  - [Installation (browser based)](#installation-browser-based)
23
24
  - [Download Data](#download-data)
24
25
  - [Revisions](#revisions)
@@ -33,14 +34,15 @@ License-File: LICENSE
33
34
  - [License](#license)
34
35
 
35
36
  ## Overview
36
- Biomedisa (https://biomedisa.info) is a free and easy-to-use open-source application for segmenting large 3D volumetric images such as CT and MRI scans, developed at [The Australian National University CTLab](https://ctlab.anu.edu.au/). Biomedisa's smart interpolation of sparsely pre-segmented slices enables accurate semi-automated segmentation by considering the complete underlying image data. Additionally, Biomedisa enables deep learning for fully automated segmentation across similar samples and structures. It is compatible with segmentation tools like Amira/Avizo, ImageJ/Fiji and 3D Slicer. If you are using Biomedisa or the data for your research please cite: Lösel, P.D. et al. [Introducing Biomedisa as an open-source online platform for biomedical image segmentation.](https://www.nature.com/articles/s41467-020-19303-w) *Nat. Commun.* **11**, 5577 (2020).
37
+ Biomedisa (https://biomedisa.info) is a free and easy-to-use open-source application for segmenting large 3D volumetric images such as CT and MRI scans, developed at [The Australian National University CTLab](https://ctlab.anu.edu.au/). Biomedisa's smart interpolation of sparsely pre-segmented slices enables accurate semi-automated segmentation by considering the complete underlying image data. Additionally, Biomedisa enables deep learning for fully automated segmentation across similar samples and structures. It is compatible with segmentation tools like Amira/Avizo, ImageJ/Fiji, and 3D Slicer. If you are using Biomedisa or the data for your research please cite: Lösel, P.D. et al. [Introducing Biomedisa as an open-source online platform for biomedical image segmentation.](https://www.nature.com/articles/s41467-020-19303-w) *Nat. Commun.* **11**, 5577 (2020).
37
38
 
38
39
  ## Hardware Requirements
39
- + One or more NVIDIA GPUs with compute capability 3.0 or higher.
40
+ + One or more NVIDIA GPUs.
40
41
 
41
42
  ## Installation (command-line based)
42
- + [Ubuntu 22.04 + Smart Interpolation](https://github.com/biomedisa/biomedisa/blob/master/README/ubuntu2204_interpolation_cli.md)
43
- + [Ubuntu 22.04 + Smart Interpolation + Deep Learning](https://github.com/biomedisa/biomedisa/blob/master/README/ubuntu2204_cuda11.8_gpu_cli.md)
43
+ + [Ubuntu 22/24 + Smart Interpolation](https://github.com/biomedisa/biomedisa/blob/master/README/ubuntu_interpolation_cli.md)
44
+ + [Ubuntu 22/24 + Deep Learning](https://github.com/biomedisa/biomedisa/blob/master/README/ubuntu_deeplearning_cli.md)
45
+ + [Ubuntu 22/24 + Smart Interpolation + Deep Learning](https://github.com/biomedisa/biomedisa/blob/master/README/ubuntu_cli.md)
44
46
  + [Windows 10/11 + Smart Interpolation + Deep Learning](https://github.com/biomedisa/biomedisa/blob/master/README/windows10_cuda_gpu_cli.md)
45
47
  + [Windows (WSL) + Smart Interpolation + Deep Learning](https://github.com/biomedisa/biomedisa/blob/master/README/windows_wsl.md)
46
48
 
@@ -165,7 +167,7 @@ save_data('final.Head5.am', results['regular'], results['header'])
165
167
 
166
168
  #### Command-line based (prediction)
167
169
  ```
168
- python -m biomedisa.deeplearning C:\Users\%USERNAME%\Downloads\testing_axial_crop_pat13.nii.gz C:\Users\%USERNAME%\Downloads\heart.h5 -p
170
+ python -m biomedisa.deeplearning C:\Users\%USERNAME%\Downloads\testing_axial_crop_pat13.nii.gz C:\Users\%USERNAME%\Downloads\heart.h5
169
171
  ```
170
172
 
171
173
  ## Mesh Generator
@@ -1,6 +1,6 @@
1
1
  biomedisa/__init__.py,sha256=hw4mzEjGFXm-vxus2DBfKFW0nKoG0ibL5SH6ShfchrY,1526
2
2
  biomedisa/__main__.py,sha256=a1--8vhtztWEloHVtbM43FZLCfrFo4BELgdsgtWE8ls,536
3
- biomedisa/deeplearning.py,sha256=UD4IeaxITLLqzoaQ1Ul5HI_bN8wINouOGxf14yZ7SWQ,28008
3
+ biomedisa/deeplearning.py,sha256=chN5uLHvmIl6gdqNYKSyq-3CNZt5n2o6drFtkeNChpg,28474
4
4
  biomedisa/interpolation.py,sha256=i10aqwEl-wsVU_nQ-zyubhAs27NSKF4ial7LyhaBLv0,17273
5
5
  biomedisa/mesh.py,sha256=8-iuVsrfW5JovaMrAez7qSxv1LCU3eiqOdik0s0DV1w,16062
6
6
  biomedisa/features/DataGenerator.py,sha256=m7vsKkLhRsVF1BE3Y8YGVx-xx0DWjbBw_inIdZBq6pQ,13111
@@ -15,7 +15,7 @@ biomedisa/features/create_slices.py,sha256=uSDH1OcEYc5BFPZHSy3UpS4P2DuoVnxOZ-l7w
15
15
  biomedisa/features/crop_helper.py,sha256=wNVbb1c6qNmJFbDJ2jrjjvqJw-EMLkJt1HLjEolMwAA,24089
16
16
  biomedisa/features/curvop_numba.py,sha256=AjKQJcUBoURTB8pq1HmugQYpBwBELthhcEu51_r_xPI,7049
17
17
  biomedisa/features/django_env.py,sha256=LNrZ6rBHZ5I0FaWa5xN8K-ASPgq0r5dGDEUI56HzJxE,8615
18
- biomedisa/features/keras_helper.py,sha256=twNuZtgfE5Bcw790ZLv4Rw8xFgXaQQb4ciV9qGdMt9w,65209
18
+ biomedisa/features/keras_helper.py,sha256=r9Knb5GlJCU3nQ601wBJF_9pOpdTL20KUO-x0xRP6WM,68853
19
19
  biomedisa/features/nc_reader.py,sha256=RoRMwu3ELSNfoV3qZtaT2OWACnXb2EhNFu_DAF1T93o,7406
20
20
  biomedisa/features/pid.py,sha256=Jmn1VIp0fBlgBrqZ-yUIQVVb5-NAxNBdibXALVr2PPI,2545
21
21
  biomedisa/features/process_image.py,sha256=VtS3fGDvglqJiiJLPK1toe76J58j914NJ8XQKg3CRwo,11091
@@ -37,8 +37,8 @@ biomedisa/features/random_walk/pyopencl_large.py,sha256=q79AxG3p3qFjxfiAZfUK9I5B
37
37
  biomedisa/features/random_walk/pyopencl_small.py,sha256=opNlS-qzOa9qWafBNJdvf6r1aRAFf7_JXf6ISDnkdXE,17068
38
38
  biomedisa/features/random_walk/rw_large.py,sha256=ZnITvk00Y11ZZlGuBRaJO1EwU0wYBdEwdpj9vvXCqF4,19805
39
39
  biomedisa/features/random_walk/rw_small.py,sha256=RPzZe24YrEwYelJukDjvqaoD_SyhgdriEi7uV3kZGXI,14881
40
- biomedisa-24.8.6.dist-info/LICENSE,sha256=sehayP6UhydNnmstfL4yFR3genMRdpuUh6uZVWJN1H0,14152
41
- biomedisa-24.8.6.dist-info/METADATA,sha256=OKGPd1oxdzvG17a0ITHB7j4e51NjHpIel2tK7rYkU74,10575
42
- biomedisa-24.8.6.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
43
- biomedisa-24.8.6.dist-info/top_level.txt,sha256=opsf1Eb4vCguPSxev4HHSeiUKCccT_C_RcUCdAYbHWQ,10
44
- biomedisa-24.8.6.dist-info/RECORD,,
40
+ biomedisa-24.8.8.dist-info/LICENSE,sha256=sehayP6UhydNnmstfL4yFR3genMRdpuUh6uZVWJN1H0,14152
41
+ biomedisa-24.8.8.dist-info/METADATA,sha256=kOfWrd_HbkEy_Ppoa-AXJkxDhG-K-v8EGIFGnMsY6LU,10708
42
+ biomedisa-24.8.8.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
43
+ biomedisa-24.8.8.dist-info/top_level.txt,sha256=opsf1Eb4vCguPSxev4HHSeiUKCccT_C_RcUCdAYbHWQ,10
44
+ biomedisa-24.8.8.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5