biomedisa 24.8.10__tar.gz → 24.8.11__tar.gz

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 (48) hide show
  1. {biomedisa-24.8.10 → biomedisa-24.8.11}/PKG-INFO +1 -1
  2. {biomedisa-24.8.10 → biomedisa-24.8.11}/pyproject.toml +1 -1
  3. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/deeplearning.py +8 -1
  4. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/DataGenerator.py +122 -2
  5. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/biomedisa_helper.py +28 -9
  6. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/keras_helper.py +8 -9
  7. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/remove_outlier.py +3 -3
  8. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/split_volume.py +12 -11
  9. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/interpolation.py +3 -8
  10. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/mesh.py +2 -2
  11. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa.egg-info/PKG-INFO +1 -1
  12. {biomedisa-24.8.10 → biomedisa-24.8.11}/LICENSE +0 -0
  13. {biomedisa-24.8.10 → biomedisa-24.8.11}/README.md +0 -0
  14. {biomedisa-24.8.10 → biomedisa-24.8.11}/setup.cfg +0 -0
  15. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/__init__.py +0 -0
  16. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/__main__.py +0 -0
  17. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/DataGeneratorCrop.py +0 -0
  18. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/PredictDataGenerator.py +0 -0
  19. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/PredictDataGeneratorCrop.py +0 -0
  20. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/__init__.py +0 -0
  21. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/active_contour.py +0 -0
  22. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/amira_to_np/__init__.py +0 -0
  23. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/amira_to_np/amira_data_stream.py +0 -0
  24. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/amira_to_np/amira_grammar.py +0 -0
  25. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/amira_to_np/amira_header.py +0 -0
  26. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/amira_to_np/amira_helper.py +0 -0
  27. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/assd.py +0 -0
  28. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/create_slices.py +0 -0
  29. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/crop_helper.py +0 -0
  30. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/curvop_numba.py +0 -0
  31. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/django_env.py +0 -0
  32. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/nc_reader.py +0 -0
  33. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/pid.py +0 -0
  34. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/process_image.py +0 -0
  35. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/pycuda_test.py +0 -0
  36. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/random_walk/__init__.py +0 -0
  37. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/random_walk/gpu_kernels.py +0 -0
  38. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/random_walk/pycuda_large.py +0 -0
  39. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/random_walk/pycuda_large_allx.py +0 -0
  40. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/random_walk/pycuda_small.py +0 -0
  41. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/random_walk/pycuda_small_allx.py +0 -0
  42. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/random_walk/pyopencl_large.py +0 -0
  43. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/random_walk/pyopencl_small.py +0 -0
  44. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/random_walk/rw_large.py +0 -0
  45. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa/features/random_walk/rw_small.py +0 -0
  46. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa.egg-info/SOURCES.txt +0 -0
  47. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa.egg-info/dependency_links.txt +0 -0
  48. {biomedisa-24.8.10 → biomedisa-24.8.11}/src/biomedisa.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: biomedisa
3
- Version: 24.8.10
3
+ Version: 24.8.11
4
4
  Summary: Segmentation of 3D volumetric image data
5
5
  Author: Philipp Lösel
6
6
  Author-email: philipp.loesel@anu.edu.au
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "biomedisa"
7
- version = "24.8.10"
7
+ version = "24.8.11"
8
8
  authors = [
9
9
  { name="Philipp Lösel"}, {email="philipp.loesel@anu.edu.au" },
10
10
  ]
@@ -67,7 +67,7 @@ def deep_learning(img_data, label_data=None, val_img_data=None, val_label_data=N
67
67
  balance=False, crop_data=False, flip_x=False, flip_y=False, flip_z=False,
68
68
  swapaxes=False, train_dice=False, val_dice=True, compression=True, ignore='none', only='all',
69
69
  network_filters='32-64-128-256-512', resnet=False, debug_cropping=False,
70
- save_cropped=False, epochs=100, normalization=True, rotate=0.0, validation_split=0.0,
70
+ save_cropped=False, epochs=100, normalization=True, rotate=0.0, rotate3d=0.0, validation_split=0.0,
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,
@@ -436,6 +436,8 @@ if __name__ == '__main__':
436
436
  help='Disable normalization of 3D image volumes')
437
437
  parser.add_argument('-r','--rotate', type=float, default=0.0,
438
438
  help='Randomly rotate during training')
439
+ parser.add_argument('--rotate3d', action='store_true', default=False,
440
+ help='Randomly rotate through three dimensions during training. Uniformly distributed over the sphere.')
439
441
  parser.add_argument('-vs','--validation_split', type=float, default=0.0,
440
442
  help='Percentage of data used for training')
441
443
  parser.add_argument('-lr','--learning_rate', type=float, default=0.01,
@@ -507,6 +509,11 @@ if __name__ == '__main__':
507
509
  bm = parser.parse_args()
508
510
  bm.success = True
509
511
 
512
+ if bm.rotate3d and not bm.scaling:
513
+ raise RuntimeError("You cannot do true 3d rotation without rescaling the data yet.")
514
+ # To fix this, have the loading function pass in a list of where the images end,
515
+ # and use that to figure out the z-centres in biomedisa.features.DataGenerator.rotate_*_3d
516
+
510
517
  # prediction or training
511
518
  if not any([bm.train, bm.predict]):
512
519
  bm.predict = False
@@ -32,6 +32,25 @@ import numba
32
32
  import random
33
33
  import scipy
34
34
 
35
+ def get_random_rotation_matrix(batch_size):
36
+ angle_xy = np.random.uniform(0, 2. * np.pi, batch_size)
37
+ Householder_1 = np.random.uniform(0, 2. * np.pi, batch_size)
38
+ Householder_2 = np.random.uniform(0, 1., batch_size)
39
+ # Matrix for xy rotation
40
+ RR = np.zeros([batch_size, 3, 3])
41
+ RR[:, 0, 0] = np.cos(angle_xy[:])
42
+ RR[:, 0, 1] = np.sin(angle_xy[:])
43
+ RR[:, 1, 0] = np.cos(angle_xy[:])
44
+ RR[:, 1, 1] = -np.sin(angle_xy[:])
45
+ RR[:, 2, 2] = 1.
46
+ # Householder matrix
47
+ vv = np.zeros([batch_size, 3, 1])
48
+ vv[:, 0, 0] = np.cos(Householder_1[:]) * np.sqrt(Householder_2[:])
49
+ vv[:, 1, 0] = np.sin(Householder_1[:]) * np.sqrt(Householder_2[:])
50
+ vv[:, 2, 0] = np.sqrt(1. - Householder_2[:])
51
+ HH = np.eye(3)[np.newaxis, :, :] - 2. * np.matmul(vv, vv.transpose(0, 2, 1))
52
+ return -np.matmul(HH, RR)
53
+
35
54
  @numba.jit(nopython=True)#parallel=True
36
55
  def rotate_img_patch(src,trg,k,l,m,cos_a,sin_a,z_patch,y_patch,x_patch,imageHeight,imageWidth):
37
56
  for y in range(l,l+y_patch):
@@ -61,6 +80,57 @@ def rotate_img_patch(src,trg,k,l,m,cos_a,sin_a,z_patch,y_patch,x_patch,imageHeig
61
80
  trg[z-k,y-l,x-m] = val
62
81
  return trg
63
82
 
83
+
84
+ @numba.jit(nopython=True)#parallel=True
85
+ def rotate_img_patch_3d(src,trg,k,l,m,rm_xx,rm_xy,rm_xz,rm_yx,rm_yy,rm_yz,rm_zx,rm_zy,rm_zz,z_patch,y_patch,x_patch,imageVertStride,imageDepth,imageHeight,imageWidth):
86
+ #return rotate_label_patch_3d(src,trg,k,l,m,rm_xx,rm_xy,rm_xz,rm_yx,rm_yy,rm_yz,rm_zx,rm_zy,rm_zz,z_patch,y_patch,x_patch,imageVertStride,imageDepth,imageHeight,imageWidth)
87
+ for z in range(k,k+z_patch):
88
+ zCentreRotation = imageVertStride * (z // imageVertStride) + imageVertStride/2
89
+ zA = z - zCentreRotation
90
+ for y in range(l,l+y_patch):
91
+ yA = y - imageHeight/2
92
+ for x in range(m,m+x_patch):
93
+ xA = x - imageWidth/2
94
+ xR = xA * rm_xx + yA * rm_xy + zA * rm_xz
95
+ yR = xA * rm_yx + yA * rm_yy + zA * rm_yz
96
+ zR = xA * rm_zx + yA * rm_zy + zA * rm_zz
97
+ src_x = xR + imageWidth/2
98
+ src_y = yR + imageHeight/2
99
+ src_z = zR + zCentreRotation
100
+ # bilinear interpolation
101
+ src_x0 = float(int(src_x))
102
+ src_x1 = src_x0 + 1
103
+ src_y0 = float(int(src_y))
104
+ src_y1 = src_y0 + 1
105
+ src_z0 = float(int(src_z))
106
+ src_z1 = src_z0 + 1
107
+ sx = src_x - src_x0
108
+ sy = src_y - src_y0
109
+ sz = src_z - src_z0
110
+ idx_src_x0 = int(min(max(0,src_x0),imageWidth-1))
111
+ idx_src_x1 = int(min(max(0,src_x1),imageWidth-1))
112
+ idx_src_y0 = int(min(max(0,src_y0),imageHeight-1))
113
+ idx_src_y1 = int(min(max(0,src_y1),imageHeight-1))
114
+ idx_src_z0 = int(min(max(0,src_z0),imageDepth-1))
115
+ idx_src_z1 = int(min(max(0,src_z1),imageDepth-1))
116
+
117
+ val = (1-sy) * (1-sx) * (1-sz) * float(src[idx_src_z0,idx_src_y0,idx_src_x0])
118
+ val += (sy) * (1-sx) * (1-sz) * float(src[idx_src_z0,idx_src_y1,idx_src_x0])
119
+ val += (1-sy) * (sx) * (1-sz) * float(src[idx_src_z0,idx_src_y0,idx_src_x1])
120
+ val += (sy) * (sx) * (1-sz) * float(src[idx_src_z0,idx_src_y1,idx_src_x1])
121
+ val += (1-sy) * (1-sx) * (sz) * float(src[idx_src_z1,idx_src_y0,idx_src_x0])
122
+ val += (sy) * (1-sx) * (sz) * float(src[idx_src_z1,idx_src_y1,idx_src_x0])
123
+ val += (1-sy) * (sx) * (sz) * float(src[idx_src_z1,idx_src_y0,idx_src_x1])
124
+ val += (sy) * (sx) * (sz) * float(src[idx_src_z1,idx_src_y1,idx_src_x1])
125
+ trg[z-k,y-l,x-m] = val
126
+ return trg
127
+
128
+ # This exists so I could test it. It's not called because sometimes numba is funny about nested
129
+ # nopython functions.
130
+ @numba.jit(nopython=True)#parallel=True
131
+ def centre_of_z_rotation(z, imageVertStride):
132
+ return imageVertStride * (z // imageVertStride) + imageVertStride/2
133
+
64
134
  @numba.jit(nopython=True)#parallel=True
65
135
  def rotate_label_patch(src,trg,k,l,m,cos_a,sin_a,z_patch,y_patch,x_patch,imageHeight,imageWidth):
66
136
  for y in range(l,l+y_patch):
@@ -80,6 +150,31 @@ def rotate_label_patch(src,trg,k,l,m,cos_a,sin_a,z_patch,y_patch,x_patch,imageHe
80
150
  trg[z-k,y-l,x-m] = src[z,idx_src_y,idx_src_x]
81
151
  return trg
82
152
 
153
+ @numba.jit(nopython=True)#parallel=True
154
+ def rotate_label_patch_3d(src,trg,k,l,m,rm_xx,rm_xy,rm_xz,rm_yx,rm_yy,rm_yz,rm_zx,rm_zy,rm_zz,z_patch,y_patch,x_patch,imageVertStride,imageDepth,imageHeight,imageWidth):
155
+ for z in range(k,k+z_patch):
156
+ zCentreRotation = imageVertStride * (z // imageVertStride) + imageVertStride/2
157
+ zA = z - zCentreRotation
158
+ for y in range(l,l+y_patch):
159
+ yA = y - imageHeight/2
160
+ for x in range(m,m+x_patch):
161
+ xA = x - imageWidth/2
162
+ xR = xA * rm_xx + yA * rm_xy + zA * rm_xz
163
+ yR = xA * rm_yx + yA * rm_yy + zA * rm_yz
164
+ zR = xA * rm_zx + yA * rm_zy + zA * rm_zz
165
+ src_x = xR + imageWidth/2
166
+ src_y = yR + imageHeight/2
167
+ src_z = zR + zCentreRotation
168
+ # nearest neighbour
169
+ src_x = round(src_x)
170
+ src_y = round(src_y)
171
+ src_z = round(src_z)
172
+ idx_src_x = int(min(max(0,src_x),imageWidth-1))
173
+ idx_src_y = int(min(max(0,src_y),imageHeight-1))
174
+ idx_src_z = int(min(max(0,src_z),imageDepth-1))
175
+ trg[z-k,y-l,x-m] = src[idx_src_z,idx_src_y,idx_src_x]
176
+ return trg
177
+
83
178
  def random_rotation_3d(image, max_angle=180):
84
179
  """ Randomly rotate an image by a random angle (-max_angle, max_angle).
85
180
 
@@ -107,7 +202,7 @@ def random_rotation_3d(image, max_angle=180):
107
202
  class DataGenerator(tf.keras.utils.Sequence):
108
203
  'Generates data for Keras'
109
204
  def __init__(self, img, label, list_IDs_fg, list_IDs_bg, shuffle, train, classification, batch_size=32, dim=(32,32,32),
110
- dim_img=(32,32,32), n_classes=10, n_channels=1, augment=(False,False,False,False,0), patch_normalization=False, separation=False):
205
+ dim_img=(32,32,32), n_classes=10, n_channels=1, augment=(False,False,False,False,0,False), patch_normalization=False, separation=False):
111
206
  'Initialization'
112
207
  self.dim = dim
113
208
  self.dim_img = dim_img
@@ -189,7 +284,7 @@ class DataGenerator(tf.keras.utils.Sequence):
189
284
  y = np.empty((self.batch_size, *self.dim, 1), dtype=np.int32)
190
285
 
191
286
  # get augmentation parameter
192
- flip_x, flip_y, flip_z, swapaxes, rotate = self.augment
287
+ flip_x, flip_y, flip_z, swapaxes, rotate, rotate3d = self.augment
193
288
  n_aug = np.sum([flip_z, flip_y, flip_x])
194
289
  flips = np.where([flip_z, flip_y, flip_x])[0]
195
290
 
@@ -198,6 +293,8 @@ class DataGenerator(tf.keras.utils.Sequence):
198
293
  angle = np.random.uniform(-1,1,self.batch_size) * 3.1416/180*rotate
199
294
  cos_angle = np.cos(angle)
200
295
  sin_angle = np.sin(angle)
296
+ if rotate3d:
297
+ rot_mtx = get_random_rotation_matrix(self.batch_size)
201
298
 
202
299
  # Generate data
203
300
  for i, ID in enumerate(list_IDs_temp):
@@ -268,6 +365,29 @@ class DataGenerator(tf.keras.utils.Sequence):
268
365
  tmp_y = rotate_label_patch(self.label,tmp_y,k,l,m,cos_a,sin_a,
269
366
  self.dim[0],self.dim[1],self.dim[2],
270
367
  self.dim_img[1],self.dim_img[2])
368
+
369
+ # rotate through a random 3d angle, uniformly distributed on a sphere.
370
+ if rotate3d:
371
+ tmp_X = np.empty((*self.dim, self.n_channels), dtype=np.float32)
372
+ tmp_y = np.empty(self.dim, dtype=np.int32)
373
+ rm_xx = rot_mtx[i, 0, 0]
374
+ rm_xy = rot_mtx[i, 0, 1]
375
+ rm_xz = rot_mtx[i, 0, 2]
376
+ rm_yx = rot_mtx[i, 1, 0]
377
+ rm_yy = rot_mtx[i, 1, 1]
378
+ rm_yz = rot_mtx[i, 1, 2]
379
+ rm_zx = rot_mtx[i, 2, 0]
380
+ rm_zy = rot_mtx[i, 2, 1]
381
+ rm_zz = rot_mtx[i, 2, 2]
382
+ for c in range(self.n_channels):
383
+ tmp_X[:,:,:,c] = rotate_img_patch_3d(self.img[:,:,:,c],tmp_X[:,:,:,c],k,l,m,
384
+ rm_xx,rm_xy,rm_xz,rm_yx,rm_yy,rm_yz,rm_zx,rm_zy,rm_zz,
385
+ self.dim[0],self.dim[1],self.dim[2],
386
+ 256, self.dim_img[0],self.dim_img[1],self.dim_img[2])
387
+ tmp_y = rotate_label_patch_3d(self.label,tmp_y,k,l,m,
388
+ rm_xx,rm_xy,rm_xz,rm_yx,rm_yy,rm_yz,rm_zx,rm_zy,rm_zz,
389
+ self.dim[0],self.dim[1],self.dim[2],
390
+ 256, self.dim_img[0],self.dim_img[1],self.dim_img[2])
271
391
 
272
392
  # flip patch along axes
273
393
  v = np.random.randint(n_aug+1)
@@ -1,6 +1,6 @@
1
1
  ##########################################################################
2
2
  ## ##
3
- ## Copyright (c) 2019-2024 Philipp Lösel. All rights reserved. ##
3
+ ## Copyright (c) 2019-2025 Philipp Lösel. All rights reserved. ##
4
4
  ## ##
5
5
  ## This file is part of the open source project biomedisa. ##
6
6
  ## ##
@@ -52,6 +52,26 @@ def silent_remove(filename):
52
52
  except OSError:
53
53
  pass
54
54
 
55
+ # determine all values and their count from an array
56
+ def unique(arr, return_counts=False):
57
+ try:
58
+ arr = arr.ravel()
59
+ counts = np.zeros(np.amax(arr)+1, dtype=int)
60
+ @numba.jit(nopython=True)
61
+ def __unique__(arr, size, counts):
62
+ for k in range(size):
63
+ counts[arr[k]] += 1
64
+ return counts
65
+ counts = __unique__(arr, arr.size, counts)
66
+ labels = np.where(counts)[0]
67
+ if return_counts:
68
+ return labels, counts[labels]
69
+ else:
70
+ return labels
71
+ except Exception as e:
72
+ print(f"Error: {e}")
73
+ return None
74
+
55
75
  # create a unique filename
56
76
  def unique_file_path(path, dir_path=biomedisa.BASE_DIR+'/private_storage/'):
57
77
 
@@ -105,7 +125,7 @@ def unique_file_path(path, dir_path=biomedisa.BASE_DIR+'/private_storage/'):
105
125
  def Dice_score(ground_truth, result, average_dice=False):
106
126
  if average_dice:
107
127
  dice = 0
108
- allLabels = np.unique(ground_truth)
128
+ allLabels = unique(ground_truth)
109
129
  for l in allLabels[1:]:
110
130
  dice += 2 * np.logical_and(ground_truth==l, result==l).sum() / float((ground_truth==l).sum() + (result==l).sum())
111
131
  dice /= float(len(allLabels)-1)
@@ -120,7 +140,7 @@ def ASSD(ground_truth, result):
120
140
  number_of_elements = 0
121
141
  distances = 0
122
142
  hausdorff = 0
123
- for label in np.unique(ground_truth)[1:]:
143
+ for label in unique(ground_truth)[1:]:
124
144
  d, n, h = ASSD_one_label(ground_truth, result, label)
125
145
  number_of_elements += n
126
146
  distances += d
@@ -157,7 +177,7 @@ def img_resize(a, z_shape, y_shape, x_shape, interpolation=None, labels=False):
157
177
 
158
178
  if labels:
159
179
  data = np.zeros((z_shape, y_shape, x_shape), dtype=a.dtype)
160
- for k in np.unique(a):
180
+ for k in unique(a):
161
181
  if k!=0:
162
182
  tmp = np.zeros(a.shape, dtype=np.uint8)
163
183
  tmp[a==k] = 1
@@ -193,7 +213,7 @@ def set_labels_to_zero(label, labels_to_compute, labels_to_remove):
193
213
  # compute only specific labels (set rest to zero)
194
214
  labels_to_compute = labels_to_compute.split(',')
195
215
  if not any([x in ['all', 'All', 'ALL'] for x in labels_to_compute]):
196
- allLabels = np.unique(label)
216
+ allLabels = unique(label)
197
217
  labels_to_del = [k for k in allLabels if str(k) not in labels_to_compute and k > 0]
198
218
  for k in labels_to_del:
199
219
  label[label == k] = 0
@@ -430,7 +450,7 @@ def pre_processing(bm):
430
450
  bm.labelData = bm.labelData.astype(np.int32)
431
451
 
432
452
  # get labels
433
- bm.allLabels = np.unique(bm.labelData)
453
+ bm.allLabels = unique(bm.labelData)
434
454
  index = np.argwhere(bm.allLabels<0)
435
455
  bm.allLabels = np.delete(bm.allLabels, index)
436
456
 
@@ -553,7 +573,7 @@ def color_to_gray(labelData):
553
573
  return labelData
554
574
 
555
575
  def delbackground(labels):
556
- allLabels, labelcounts = np.unique(labels, return_counts=True)
576
+ allLabels, labelcounts = unique(labels, return_counts=True)
557
577
  index = np.argmax(labelcounts)
558
578
  labels[labels==allLabels[index]] = 0
559
579
  return labels
@@ -844,9 +864,8 @@ def _split_indices(indices, ngpus):
844
864
  return parts
845
865
 
846
866
  def get_labels(pre_final, labels):
847
- numos = np.unique(pre_final)
848
867
  final = np.zeros_like(pre_final)
849
- for k in numos[1:]:
868
+ for k in unique(pre_final)[1:]:
850
869
  final[pre_final == k] = labels[k]
851
870
  return final
852
871
 
@@ -1,6 +1,6 @@
1
1
  ##########################################################################
2
2
  ## ##
3
- ## Copyright (c) 2019-2024 Philipp Lösel. All rights reserved. ##
3
+ ## Copyright (c) 2019-2025 Philipp Lösel. All rights reserved. ##
4
4
  ## ##
5
5
  ## This file is part of the open source project biomedisa. ##
6
6
  ## ##
@@ -41,7 +41,7 @@ from tensorflow.keras.utils import to_categorical
41
41
  from tensorflow.keras.callbacks import Callback, ModelCheckpoint, EarlyStopping
42
42
  from biomedisa.features.DataGenerator import DataGenerator
43
43
  from biomedisa.features.PredictDataGenerator import PredictDataGenerator
44
- from biomedisa.features.biomedisa_helper import (
44
+ from biomedisa.features.biomedisa_helper import (unique,
45
45
  img_resize, load_data, save_data, set_labels_to_zero, id_generator, unique_file_path)
46
46
  from biomedisa.features.remove_outlier import clean, fill
47
47
  from biomedisa.features.active_contour import activeContour
@@ -319,9 +319,8 @@ def make_unet(input_shape, nb_labels, filters='32-64-128-256-512', resnet=False)
319
319
  return model
320
320
 
321
321
  def get_labels(arr, allLabels):
322
- np_unique = np.unique(arr)
323
322
  final = np.zeros_like(arr)
324
- for k in np_unique:
323
+ for k in unique(arr):
325
324
  final[arr == k] = allLabels[k]
326
325
  return final
327
326
 
@@ -412,7 +411,7 @@ def load_training_data(bm, img_list, label_list, channels, img_in=None, label_in
412
411
  argmin_z,argmax_z,argmin_y,argmax_y,argmin_x,argmax_x = predict_blocksize(label, x_puffer, y_puffer, z_puffer)
413
412
  label = label[argmin_z:argmax_z,argmin_y:argmax_y,argmin_x:argmax_x].copy()
414
413
  if bm.scaling:
415
- label_values, counts = np.unique(label, return_counts=True)
414
+ label_values, counts = unique(label, return_counts=True)
416
415
  print(f'{os.path.basename(label_names[0])}:', 'Labels:', label_values[1:], 'Sizes:', counts[1:])
417
416
  label = img_resize(label, bm.z_scale, bm.y_scale, bm.x_scale, labels=True)
418
417
 
@@ -514,7 +513,7 @@ def load_training_data(bm, img_list, label_list, channels, img_in=None, label_in
514
513
  argmin_z,argmax_z,argmin_y,argmax_y,argmin_x,argmax_x = predict_blocksize(a, x_puffer, y_puffer, z_puffer)
515
514
  a = np.copy(a[argmin_z:argmax_z,argmin_y:argmax_y,argmin_x:argmax_x], order='C')
516
515
  if bm.scaling:
517
- label_values, counts = np.unique(a, return_counts=True)
516
+ label_values, counts = unique(a, return_counts=True)
518
517
  print(f'{os.path.basename(label_names[k])}:', 'Labels:', label_values[1:], 'Sizes:', counts[1:])
519
518
  a = img_resize(a, bm.z_scale, bm.y_scale, bm.x_scale, labels=True)
520
519
  label = np.append(label, a, axis=0)
@@ -587,7 +586,7 @@ def load_training_data(bm, img_list, label_list, channels, img_in=None, label_in
587
586
  else:
588
587
  # get labels
589
588
  if allLabels is None:
590
- allLabels = np.unique(label)
589
+ allLabels = unique(label)
591
590
  index = np.argwhere(allLabels<0)
592
591
  allLabels = np.delete(allLabels, index)
593
592
 
@@ -987,7 +986,7 @@ def train_segmentation(bm):
987
986
  'dim_img': (zsh, ysh, xsh),
988
987
  'n_classes': nb_labels,
989
988
  'n_channels': bm.channels,
990
- 'augment': (bm.flip_x, bm.flip_y, bm.flip_z, bm.swapaxes, bm.rotate),
989
+ 'augment': (bm.flip_x, bm.flip_y, bm.flip_z, bm.swapaxes, bm.rotate, bm.rotate3d),
991
990
  'patch_normalization': bm.patch_normalization,
992
991
  'separation': bm.separation}
993
992
 
@@ -999,7 +998,7 @@ def train_segmentation(bm):
999
998
  val_metrics = Metrics(bm, bm.val_img_data, bm.val_label_data, list_IDs_val_fg, (zsh_val, ysh_val, xsh_val), nb_labels, False)
1000
999
  else:
1001
1000
  params['dim_img'] = (zsh_val, ysh_val, xsh_val)
1002
- params['augment'] = (False, False, False, False, 0)
1001
+ params['augment'] = (False, False, False, False, 0, False)
1003
1002
  validation_generator = DataGenerator(bm.val_img_data, bm.val_label_data, list_IDs_val_fg, list_IDs_val_bg, True, False, False, **params)
1004
1003
 
1005
1004
  # monitor dice score on training data
@@ -30,7 +30,7 @@
30
30
  import os
31
31
  import biomedisa
32
32
  from biomedisa.features.biomedisa_helper import (load_data, save_data,
33
- unique_file_path, silent_remove)
33
+ unique_file_path, silent_remove, unique)
34
34
  import numpy as np
35
35
  from scipy import ndimage
36
36
  import argparse
@@ -60,7 +60,7 @@ def reduce_blocksize(data):
60
60
 
61
61
  def clean(image, threshold=0.1):
62
62
  image_i = np.copy(image, order='C')
63
- allLabels = np.unique(image_i)
63
+ allLabels = unique(image_i)
64
64
  mask = np.empty_like(image_i)
65
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
66
  for k in allLabels[1:]:
@@ -99,7 +99,7 @@ def clean(image, threshold=0.1):
99
99
 
100
100
  def fill(image, threshold=0.9):
101
101
  image_i = np.copy(image, order='C')
102
- allLabels = np.unique(image_i)
102
+ allLabels = unique(image_i)
103
103
  mask = np.empty_like(image_i)
104
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
105
  for k in allLabels[1:]:
@@ -132,17 +132,18 @@ if __name__ == '__main__':
132
132
  labelData = labelData[datamin_z:datamax_z,datamin_y:datamax_y,datamin_x:datamax_x].copy()
133
133
 
134
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]
135
+ if np.any(labelData):
136
+ results = smart_interpolation(data, labelData, uncertainty=args.uncertainty, allaxis=args.allaxis, smooth=args.smooth)
137
+
138
+ # append results
139
+ final[blockmin_z:blockmax_z,blockmin_y:blockmax_y,blockmin_x:blockmax_x] \
140
+ = 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]
141
+ if 'smooth' in results and results['smooth'] is not None:
142
+ final_smooth[blockmin_z:blockmax_z,blockmin_y:blockmax_y,blockmin_x:blockmax_x] \
143
+ = 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]
144
+ if 'uncertainty' in results and results['uncertainty'] is not None:
145
+ final_uncertainty[blockmin_z:blockmax_z,blockmin_y:blockmax_y,blockmin_x:blockmax_x] \
146
+ = 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
 
147
148
  # path to regular result
148
149
  filename, extension = os.path.splitext(os.path.basename(args.path_to_data))
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/python3
2
2
  ##########################################################################
3
3
  ## ##
4
- ## Copyright (c) 2019-2024 Philipp Lösel. All rights reserved. ##
4
+ ## Copyright (c) 2019-2025 Philipp Lösel. All rights reserved. ##
5
5
  ## ##
6
6
  ## This file is part of the open source project biomedisa. ##
7
7
  ## ##
@@ -165,13 +165,8 @@ def smart_interpolation(data, labelData, nbrw=10, sorw=4000, acwe=False, acwe_al
165
165
  bm.imageSize = int(bm.data.nbytes * 10e-7)
166
166
 
167
167
  # add boundaries
168
- zsh, ysh, xsh = bm.data.shape
169
- tmp = np.zeros((1+zsh+1, 1+ysh+1, 1+xsh+1), dtype=bm.labelData.dtype)
170
- tmp[1:-1, 1:-1, 1:-1] = bm.labelData
171
- bm.labelData = tmp.copy(order='C')
172
- tmp = np.zeros((1+zsh+1, 1+ysh+1, 1+xsh+1), dtype=bm.data.dtype)
173
- tmp[1:-1, 1:-1, 1:-1] = bm.data
174
- bm.data = tmp.copy(order='C')
168
+ bm.data = np.pad(bm.data, pad_width=1, mode='constant', constant_values=0)
169
+ bm.labelData = np.pad(bm.labelData, pad_width=1, mode='constant', constant_values=0)
175
170
  bm.zsh, bm.ysh, bm.xsh = bm.data.shape
176
171
 
177
172
  # check if labeled slices are adjacent
@@ -30,7 +30,7 @@
30
30
  import os
31
31
  import numpy as np
32
32
  import biomedisa
33
- from biomedisa.features.biomedisa_helper import load_data, unique_file_path
33
+ from biomedisa.features.biomedisa_helper import load_data, unique_file_path, unique
34
34
  from biomedisa.features.django_env import create_pid_object
35
35
  from vtk.util.numpy_support import vtk_to_numpy, numpy_to_vtk
36
36
  from stl import mesh
@@ -107,7 +107,7 @@ def save_mesh(path_to_result, labels, x_res=1, y_res=1, z_res=1,
107
107
 
108
108
  # get labels
109
109
  zsh, ysh, xsh = labels.shape
110
- allLabels = np.unique(labels)
110
+ allLabels = unique(labels)
111
111
  b = np.empty_like(labels)
112
112
  arr = np.empty((0,3,3))
113
113
  nTotalCells = [0]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: biomedisa
3
- Version: 24.8.10
3
+ Version: 24.8.11
4
4
  Summary: Segmentation of 3D volumetric image data
5
5
  Author: Philipp Lösel
6
6
  Author-email: philipp.loesel@anu.edu.au
File without changes
File without changes
File without changes