nettracer3d 0.6.6__py3-none-any.whl → 0.6.7__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.
nettracer3d/proximity.py CHANGED
@@ -64,13 +64,13 @@ def reslice_3d_array(args):
64
64
 
65
65
 
66
66
 
67
- def _get_node_node_dict(label_array, label, dilate_xy, dilate_z):
67
+ def _get_node_node_dict(label_array, label, dilate_xy, dilate_z, fastdil = False, xy_scale = 1, z_scale = 1, search = 0):
68
68
  """Internal method used for the secondary algorithm to find which nodes interact
69
69
  with which other nodes based on proximity."""
70
70
 
71
71
  # Create a boolean mask where elements with the specified label are True
72
72
  binary_array = label_array == label
73
- binary_array = nettracer.dilate_3D_recursive(binary_array, dilate_xy, dilate_xy, dilate_z) #Dilate the label to see where the dilated label overlaps
73
+ binary_array = nettracer.dilate(binary_array, search, xy_scale, z_scale, fast_dil = fastdil, dilate_xy = dilate_xy, dilate_z = dilate_z) #Dilate the label to see where the dilated label overlaps
74
74
  label_array = label_array * binary_array # Filter the labels by the node in question
75
75
  label_array = label_array.flatten() # Convert 3d array to 1d array
76
76
  label_array = nettracer.remove_zeros(label_array) # Remove zeros
@@ -82,7 +82,7 @@ def _get_node_node_dict(label_array, label, dilate_xy, dilate_z):
82
82
  def process_label(args):
83
83
  """Modified to use pre-computed bounding boxes instead of argwhere"""
84
84
  nodes, label, dilate_xy, dilate_z, array_shape, bounding_boxes = args
85
- print(f"Processing node {label}")
85
+ #print(f"Processing node {label}")
86
86
 
87
87
  # Get the pre-computed bounding box for this label
88
88
  slice_obj = bounding_boxes[label-1] # -1 because label numbers start at 1
@@ -97,10 +97,11 @@ def process_label(args):
97
97
  return label, sub_nodes
98
98
 
99
99
 
100
- def create_node_dictionary(nodes, num_nodes, dilate_xy, dilate_z, targets=None):
101
- """Modified to pre-compute all bounding boxes using find_objects"""
100
+ def create_node_dictionary(nodes, num_nodes, dilate_xy, dilate_z, targets=None, fastdil = False, xy_scale = 1, z_scale = 1, search = 0):
101
+ """pre-compute all bounding boxes using find_objects"""
102
102
  node_dict = {}
103
103
  array_shape = nodes.shape
104
+
104
105
 
105
106
  # Get all bounding boxes at once
106
107
  bounding_boxes = ndimage.find_objects(nodes)
@@ -118,17 +119,17 @@ def create_node_dictionary(nodes, num_nodes, dilate_xy, dilate_z, targets=None):
118
119
 
119
120
  # Process results in parallel
120
121
  for label, sub_nodes in results:
121
- executor.submit(create_dict_entry, node_dict, label, sub_nodes, dilate_xy, dilate_z)
122
+ executor.submit(create_dict_entry, node_dict, label, sub_nodes, dilate_xy, dilate_z, fastdil = fastdil, xy_scale = xy_scale, z_scale = z_scale, search = search)
122
123
 
123
124
  return node_dict
124
125
 
125
- def create_dict_entry(node_dict, label, sub_nodes, dilate_xy, dilate_z):
126
+ def create_dict_entry(node_dict, label, sub_nodes, dilate_xy, dilate_z, fastdil = False, xy_scale = 1, z_scale = 1, search = 0):
126
127
  """Internal method used for the secondary algorithm to pass around args in parallel."""
127
128
 
128
129
  if label is None:
129
130
  pass
130
131
  else:
131
- node_dict[label] = _get_node_node_dict(sub_nodes, label, dilate_xy, dilate_z)
132
+ node_dict[label] = _get_node_node_dict(sub_nodes, label, dilate_xy, dilate_z, fastdil = fastdil, xy_scale = xy_scale, z_scale = z_scale, search = search)
132
133
 
133
134
  def find_shared_value_pairs(input_dict):
134
135
  """Internal method used for the secondary algorithm to look through discrete
nettracer3d/segmenter.py CHANGED
@@ -1,18 +1,5 @@
1
1
  from sklearn.ensemble import RandomForestClassifier
2
2
  import numpy as np
3
- try:
4
- import torch
5
- except:
6
- pass
7
- try:
8
- import cupy as cp
9
- import cupyx.scipy.ndimage as cpx
10
- except:
11
- pass
12
- try:
13
- from cuml.ensemble import RandomForestClassifier as cuRandomForestClassifier
14
- except:
15
- pass
16
3
  import concurrent.futures
17
4
  from concurrent.futures import ThreadPoolExecutor
18
5
  import threading
@@ -218,13 +205,20 @@ class InteractiveSegmenter:
218
205
 
219
206
  # Gaussian and DoG using scipy
220
207
  #print("Obtaining gaussians")
221
- for sigma in [0.5, 1.0, 2.0, 4.0]:
208
+ for sigma in self.alphas:
222
209
  smooth = ndimage.gaussian_filter(image_3d, sigma)
223
210
  features.append(smooth)
211
+
212
+ # Difference of Gaussians
213
+ for (s1, s2) in self.dogs:
214
+ g1 = ndimage.gaussian_filter(image_3d, s1)
215
+ g2 = ndimage.gaussian_filter(image_3d, s2)
216
+ dog = g1 - g2
217
+ features.append(dog)
224
218
 
225
219
  #print("Computing local statistics")
226
220
  # Local statistics using scipy's convolve
227
- window_size = 5
221
+ window_size = self.windows
228
222
  kernel = np.ones((window_size, window_size, window_size)) / (window_size**3)
229
223
 
230
224
  # Local mean
@@ -299,7 +293,7 @@ class InteractiveSegmenter:
299
293
  for (s1, s2) in self.dogs:
300
294
 
301
295
  future = executor.submit(compute_dog_local, image_3d, s1, s2)
302
- futures.append('dog', s1, future)
296
+ futures.append(('dog', s1, future))
303
297
 
304
298
  # Local statistics computation
305
299
  def compute_local_mean():
@@ -960,13 +954,13 @@ class InteractiveSegmenter:
960
954
 
961
955
  # Gaussian smoothing at different scales
962
956
  #print("Obtaining gaussians")
963
- for sigma in [0.5, 1.0, 2.0, 4.0]:
957
+ for sigma in self.alphas:
964
958
  smooth = ndimage.gaussian_filter(image_3d, sigma)
965
959
  features.append(smooth)
966
960
 
967
961
  #print("Obtaining dif of gaussians")
968
962
  # Difference of Gaussians
969
- for (s1, s2) in [(1, 2), (2, 4)]:
963
+ for (s1, s2) in self.dogs:
970
964
  g1 = ndimage.gaussian_filter(image_3d, s1)
971
965
  g2 = ndimage.gaussian_filter(image_3d, s2)
972
966
  dog = g1 - g2
@@ -2,6 +2,7 @@ import tifffile
2
2
  import numpy as np
3
3
  from scipy.ndimage import binary_dilation, distance_transform_edt
4
4
  from scipy.ndimage import gaussian_filter
5
+ from scipy import ndimage
5
6
  from concurrent.futures import ThreadPoolExecutor, as_completed
6
7
  import cv2
7
8
  import os
@@ -145,45 +146,99 @@ def dilate_3D(tiff_array, dilated_x, dilated_y, dilated_z):
145
146
  return final_result
146
147
 
147
148
 
148
- def dilate_3D_old(tiff_array, dilated_x, dilated_y, dilated_z):
149
- """Dilate an array in 3D. Consider replacing with scipy dilation method.
150
- Arguments are an array, and the desired pixel dilation amounts in X, Y, Z."""
149
+ def dilate_3D_old(tiff_array, dilated_x=3, dilated_y=3, dilated_z=3):
150
+ """
151
+ Dilate a 3D array using scipy.ndimage.binary_dilation with a 3x3x3 cubic kernel.
152
+
153
+ Arguments:
154
+ tiff_array -- Input 3D binary array
155
+ dilated_x -- Fixed at 3 for X dimension
156
+ dilated_y -- Fixed at 3 for Y dimension
157
+ dilated_z -- Fixed at 3 for Z dimension
158
+
159
+ Returns:
160
+ Dilated 3D array
161
+ """
162
+ import numpy as np
163
+ from scipy import ndimage
164
+
165
+ # Handle special case for 2D arrays
166
+ if tiff_array.shape[0] == 1:
167
+ # Call 2D dilation function if needed
168
+ return dilate_2D(tiff_array, 1) # For a 3x3 kernel, radius is 1
169
+
170
+ # Create a simple 3x3x3 cubic kernel (all ones)
171
+ kernel = np.ones((3, 3, 3), dtype=bool)
172
+
173
+ # Perform binary dilation
174
+ dilated_array = ndimage.binary_dilation(tiff_array.astype(bool), structure=kernel)
175
+
176
+ return dilated_array.astype(np.uint8)
151
177
 
152
- # Create empty arrays to store the dilated results for the XY and XZ planes
153
- dilated_xy = np.zeros_like(tiff_array, dtype=np.uint8)
154
- dilated_xz = np.zeros_like(tiff_array, dtype=np.uint8)
178
+ def dilate_3D_dt(array, search_distance, xy_scaling=1.0, z_scaling=1.0, GPU = False):
179
+ """
180
+ Dilate a 3D array using distance transform method. Dt dilation produces perfect results but only works in euclidean geometry and lags in big arrays.
181
+
182
+ Parameters:
183
+ array -- Input 3D binary array
184
+ search_distance -- Distance within which to dilate
185
+ xy_scaling -- Scaling factor for x and y dimensions (default: 1.0)
186
+ z_scaling -- Scaling factor for z dimension (default: 1.0)
187
+
188
+ Returns:
189
+ Dilated 3D array
190
+ """
191
+ if array.shape[0] == 1:
192
+
193
+ return nettracer.dilate_2D(array, search_distance, scaling = xy_scaling)
194
+
195
+ # Determine which dimension needs resampling
196
+ if (z_scaling > xy_scaling):
197
+ # Z dimension needs to be stretched
198
+ zoom_factor = [z_scaling/xy_scaling, 1, 1] # Scale factor for [z, y, x]
199
+ rev_factor = [xy_scaling/z_scaling, 1, 1]
200
+ cardinal = xy_scaling
201
+ elif (xy_scaling > z_scaling):
202
+ # XY dimensions need to be stretched
203
+ zoom_factor = [1, xy_scaling/z_scaling, xy_scaling/z_scaling] # Scale factor for [z, y, x]
204
+ rev_factor = [1, z_scaling/xy_scaling, z_scaling/xy_scaling] # Scale factor for [z, y, x]
205
+ cardinal = z_scaling
206
+ else:
207
+ # Already uniform scaling, no need to resample
208
+ zoom_factor = None
209
+ rev_factor = None
210
+ cardinal = xy_scaling
155
211
 
156
- # Perform 2D dilation in the XY plane
157
- for z in range(tiff_array.shape[0]):
158
- kernel_x = int(dilated_x)
159
- kernel_y = int(dilated_y)
160
- kernel = np.ones((kernel_y, kernel_x), dtype=np.uint8)
161
212
 
213
+ # Resample the mask if needed
214
+ if zoom_factor:
215
+ array = ndimage.zoom(array, zoom_factor, order=0) # Use order=0 for binary masks
162
216
 
163
- # Convert the slice to the appropriate data type
164
- tiff_slice = tiff_array[z].astype(np.uint8)
165
-
166
- dilated_slice = cv2.dilate(tiff_slice, kernel, iterations=1)
167
- dilated_xy[z] = dilated_slice
217
+ # Invert the array (find background)
218
+ inv = array < 1
219
+
220
+ if GPU:
221
+ try:
222
+ print("Attempting on GPU...")
223
+ inv, indices = compute_distance_transform_GPU(inv, return_dists = True)
224
+ except:
225
+ print("Failed, attempting on CPU...")
226
+ #Who would have seen this coming?:
227
+ inv, indices = compute_distance_transform(inv, return_dists = True)
228
+ else:
229
+ inv, indices = compute_distance_transform(inv, return_dists = True)
168
230
 
169
- # Perform 2D dilation in the XZ plane
170
- for y in range(tiff_array.shape[1]):
171
- kernel_x = int(dilated_x)
172
- kernel_z = int(dilated_z)
173
- kernel = np.ones((kernel_z, kernel_x), dtype=np.uint8)
174
231
 
232
+ inv = inv * cardinal
233
+
234
+ # Threshold the distance transform to get dilated result
235
+ inv = inv <= search_distance
175
236
 
176
- # Convert the slice to the appropriate data type
177
- tiff_slice = tiff_array[:, y, :].astype(np.uint8)
178
237
 
179
- dilated_slice = cv2.dilate(tiff_slice, kernel, iterations=1)
180
- dilated_xz[:, y, :] = dilated_slice
238
+ return inv.astype(np.uint8), indices, array, rev_factor
181
239
 
182
- # Overlay the results (you can use logical OR operation or another method)
183
- final_result = dilated_xy | dilated_xz
184
240
 
185
241
 
186
- return final_result
187
242
 
188
243
  def binarize(image):
189
244
  """Convert an array from numerical values to boolean mask"""
@@ -209,71 +264,73 @@ def process_chunk(start_idx, end_idx, nodes, ring_mask, nearest_label_indices):
209
264
 
210
265
  return dilated_nodes_with_labels_chunk
211
266
 
212
- def smart_dilate(nodes, dilate_xy, dilate_z, directory = None, GPU = True, fast_dil = False, predownsample = None):
267
+ def smart_dilate(nodes, dilate_xy, dilate_z, directory = None, GPU = True, fast_dil = True, predownsample = None, use_dt_dil_amount = None, xy_scale = 1, z_scale = 1):
213
268
 
214
269
  original_shape = nodes.shape
215
270
 
216
- # Step 1: Binarize the labeled array
217
- binary_nodes = binarize(nodes)
218
271
 
219
- # Step 2: Dilate the binarized array
220
- if not fast_dil:
272
+ #Dilate the binarized array
273
+ if fast_dil:
274
+ # Step : Binarize the labeled array
275
+ binary_nodes = binarize(nodes)
221
276
  dilated_binary_nodes = dilate_3D(binary_nodes, dilate_xy, dilate_xy, dilate_z)
222
277
  else:
223
- dilated_binary_nodes = dilate_3D_old(binary_nodes, dilate_xy, dilate_xy, dilate_z)
224
-
278
+ dilated_binary_nodes, nearest_label_indices, nodes, rev_factor = dilate_3D_dt(nodes, use_dt_dil_amount, GPU = GPU, xy_scaling = xy_scale, z_scaling = z_scale)
279
+ binary_nodes = binarize(nodes)
225
280
 
226
281
  # Step 3: Isolate the ring (binary dilated mask minus original binary mask)
227
282
  ring_mask = dilated_binary_nodes & invert_array(binary_nodes)
228
283
 
284
+ del binary_nodes
285
+
229
286
  print("Preforming distance transform for smart search... this step may take some time if computed on CPU...")
230
287
 
231
- try:
288
+ if fast_dil:
232
289
 
233
- if GPU == True and cp.cuda.runtime.getDeviceCount() > 0:
234
- print("GPU detected. Using CuPy for distance transform.")
290
+ try:
235
291
 
236
- try:
292
+ if GPU == True and cp.cuda.runtime.getDeviceCount() > 0:
293
+ print("GPU detected. Using CuPy for distance transform.")
237
294
 
238
- if predownsample is None:
295
+ try:
239
296
 
240
- # Step 4: Find the nearest label for each voxel in the ring
241
- nearest_label_indices = compute_distance_transform_GPU(invert_array(nodes))
297
+ if predownsample is None:
242
298
 
243
- else:
244
- gotoexcept = 1/0
299
+ # Step 4: Find the nearest label for each voxel in the ring
300
+ nearest_label_indices = compute_distance_transform_GPU(invert_array(nodes))
245
301
 
246
- except (cp.cuda.memory.OutOfMemoryError, ZeroDivisionError) as e:
247
- if predownsample is None:
248
- down_factor = catch_memory(e) #Obtain downsample amount based on memory missing
249
- else:
250
- down_factor = (predownsample)**3
302
+ else:
303
+ gotoexcept = 1/0
251
304
 
252
- while True:
253
- downsample_needed = down_factor**(1./3.)
254
- small_nodes = nettracer.downsample(nodes, downsample_needed) #Apply downsample
255
- try:
256
- nearest_label_indices = compute_distance_transform_GPU(invert_array(small_nodes)) #Retry dt on downsample
257
- print(f"Using {down_factor} downsample ({downsample_needed} in each dim - Largest possible with this GPU unless user specified downsample)")
258
- break
259
- except cp.cuda.memory.OutOfMemoryError:
260
- down_factor += 1
261
- binary_nodes = binarize(small_nodes) #Recompute variables for downsample
262
- dilated_mask = dilated_binary_nodes #Need this for later to stamp out the correct output
263
- if not fast_dil:
305
+ except (cp.cuda.memory.OutOfMemoryError, ZeroDivisionError) as e:
306
+ if predownsample is None:
307
+ down_factor = catch_memory(e) #Obtain downsample amount based on memory missing
308
+ else:
309
+ down_factor = (predownsample)**3
310
+
311
+ while True:
312
+ downsample_needed = down_factor**(1./3.)
313
+ small_nodes = nettracer.downsample(nodes, downsample_needed) #Apply downsample
314
+ try:
315
+ nearest_label_indices = compute_distance_transform_GPU(invert_array(small_nodes)) #Retry dt on downsample
316
+ print(f"Using {down_factor} downsample ({downsample_needed} in each dim - Largest possible with this GPU unless user specified downsample)")
317
+ break
318
+ except cp.cuda.memory.OutOfMemoryError:
319
+ down_factor += 1
320
+ binary_nodes = binarize(small_nodes) #Recompute variables for downsample
321
+ dilated_mask = dilated_binary_nodes #Need this for later to stamp out the correct output
264
322
  dilated_binary_nodes = dilate_3D(binary_nodes, 2 + round_to_odd(dilate_xy/downsample_needed), 2 + round_to_odd(dilate_xy/downsample_needed), 2 + round_to_odd(dilate_z/downsample_needed)) #Mod dilation to recompute variables for downsample while also over dilatiing
265
- else:
266
- dilated_binary_nodes = dilate_3D_old(binary_nodes, 2 + round_to_odd(dilate_xy/downsample_needed), 2 + round_to_odd(dilate_xy/downsample_needed), 2 + round_to_odd(dilate_z/downsample_needed))
267
- ring_mask = dilated_binary_nodes & invert_array(binary_nodes)
268
- nodes = small_nodes
269
- del small_nodes
270
- else:
271
- goto_except = 1/0
272
- except Exception as e:
273
- print("GPU dt failed or did not detect GPU (cupy must be installed with a CUDA toolkit setup...). Computing CPU distance transform instead.")
274
- if GPU:
275
- print(f"Error message: {str(e)}")
276
- nearest_label_indices = compute_distance_transform(invert_array(nodes))
323
+
324
+ ring_mask = dilated_binary_nodes & invert_array(binary_nodes)
325
+ nodes = small_nodes
326
+ del small_nodes
327
+ else:
328
+ goto_except = 1/0
329
+ except Exception as e:
330
+ print("GPU dt failed or did not detect GPU (cupy must be installed with a CUDA toolkit setup...). Computing CPU distance transform instead.")
331
+ if GPU:
332
+ print(f"Error message: {str(e)}")
333
+ nearest_label_indices = compute_distance_transform(invert_array(nodes))
277
334
 
278
335
 
279
336
  # Step 5: Process in parallel chunks using ThreadPoolExecutor
@@ -284,12 +341,19 @@ def smart_dilate(nodes, dilate_xy, dilate_z, directory = None, GPU = True, fast_
284
341
  args_list = [(i * chunk_size, (i + 1) * chunk_size if i != num_cores - 1 else nodes.shape[0], nodes, ring_mask, nearest_label_indices) for i in range(num_cores)]
285
342
  results = list(executor.map(lambda args: process_chunk(*args), args_list))
286
343
 
344
+ del ring_mask
345
+ del nodes
346
+ del nearest_label_indices
347
+
287
348
  # Combine results from chunks
288
349
  dilated_nodes_with_labels = np.concatenate(results, axis=0)
289
350
 
290
- if nodes.shape[1] < original_shape[1]: #If downsample was used, upsample output
351
+
352
+ if (dilated_nodes_with_labels.shape[1] < original_shape[1]) and fast_dil: #If downsample was used, upsample output
291
353
  dilated_nodes_with_labels = nettracer.upsample_with_padding(dilated_nodes_with_labels, downsample_needed, original_shape)
292
354
  dilated_nodes_with_labels = dilated_nodes_with_labels * dilated_mask
355
+ elif (dilated_nodes_with_labels.shape[1] != original_shape[1]) and not fast_dil:
356
+ dilated_nodes_with_labels = ndimage.zoom(dilated_nodes_with_labels, rev_factor, order=0)
293
357
 
294
358
  if directory is not None:
295
359
  try:
@@ -364,7 +428,7 @@ def smart_label(binary_array, label_array, directory = None, GPU = True, predown
364
428
  binary_core = binarize(small_array)
365
429
  label_array = small_array
366
430
  binary_array = nettracer.downsample(binary_array, downsample_needed)
367
- binary_array = nettracer.dilate_3D(binary_array, 3, 3, 3)
431
+ binary_array = nettracer.dilate_3D_old(binary_array)
368
432
  ring_mask = binary_array & invert_array(binary_core)
369
433
 
370
434
  else:
@@ -408,7 +472,7 @@ def smart_label(binary_array, label_array, directory = None, GPU = True, predown
408
472
 
409
473
  return dilated_nodes_with_labels
410
474
 
411
- def compute_distance_transform_GPU(nodes):
475
+ def compute_distance_transform_GPU(nodes, return_dists = False):
412
476
  is_pseudo_3d = nodes.shape[0] == 1
413
477
  if is_pseudo_3d:
414
478
  nodes = np.squeeze(nodes) # Convert to 2D for processing
@@ -417,7 +481,7 @@ def compute_distance_transform_GPU(nodes):
417
481
  nodes_cp = cp.asarray(nodes)
418
482
 
419
483
  # Compute the distance transform on the GPU
420
- _, nearest_label_indices = cpx.distance_transform_edt(nodes_cp, return_indices=True)
484
+ dists, nearest_label_indices = cpx.distance_transform_edt(nodes_cp, return_indices=True)
421
485
 
422
486
  # Convert results back to numpy arrays
423
487
  nearest_label_indices_np = cp.asnumpy(nearest_label_indices)
@@ -430,18 +494,22 @@ def compute_distance_transform_GPU(nodes):
430
494
  # indices_4d[0] stays 0 for all Z coordinates
431
495
  nearest_label_indices_np = indices_4d
432
496
 
433
-
497
+ if not return_dists:
434
498
 
499
+ return nearest_label_indices_np
500
+
501
+ else:
502
+ dists = cp.asnumpy(dists)
435
503
 
436
- return nearest_label_indices_np
504
+ return dists, nearest_label_indices_np
437
505
 
438
506
 
439
- def compute_distance_transform(nodes):
507
+ def compute_distance_transform(nodes, return_dists = False):
440
508
  is_pseudo_3d = nodes.shape[0] == 1
441
509
  if is_pseudo_3d:
442
510
  nodes = np.squeeze(nodes) # Convert to 2D for processing
443
511
 
444
- distance, nearest_label_indices = distance_transform_edt(nodes, return_indices=True)
512
+ dists, nearest_label_indices = distance_transform_edt(nodes, return_indices=True)
445
513
 
446
514
  if is_pseudo_3d:
447
515
  # For 2D input, we get (2, H, W) but need (3, 1, H, W)
@@ -451,7 +519,13 @@ def compute_distance_transform(nodes):
451
519
  # indices_4d[0] stays 0 for all Z coordinates
452
520
  nearest_label_indices = indices_4d
453
521
 
454
- return nearest_label_indices
522
+ if not return_dists:
523
+
524
+ return nearest_label_indices
525
+
526
+ else:
527
+
528
+ return dists, nearest_label_indices
455
529
 
456
530
 
457
531
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nettracer3d
3
- Version: 0.6.6
3
+ Version: 0.6.7
4
4
  Summary: Scripts for intializing and analyzing networks from segmentations of three dimensional images.
5
5
  Author-email: Liam McLaughlin <mclaughlinliam99@gmail.com>
6
6
  Project-URL: User_Tutorial, https://www.youtube.com/watch?v=cRatn5VTWDY
@@ -46,8 +46,12 @@ NetTracer3D is free to use/fork for academic/nonprofit use so long as citation i
46
46
 
47
47
  NetTracer3D was developed by Liam McLaughlin while working under Dr. Sanjay Jain at Washington University School of Medicine.
48
48
 
49
- -- Version 0.6.6 updates --
49
+ -- Version 0.6.7 updates --
50
50
 
51
- 1. Updated flexibility of the fill holes method for user with varying use cases.
51
+ 1. Updated all methods to use dilation to allow the user to select between perfect distance transform based dilation (which can be slower but allows for perfect searching - and is designed to account for scaling differences), or the current pseudo-3d kernel method.
52
52
 
53
- 2. Greatly improved memory efficiency of segmenter. Now works comfortably with 3.5 GB array on my machine for example (my machine has 64 GB RAM and this occupied around 20% of it I would say). Removed the non-memory efficient option (now always prioritizes mem - the former wasn't even that much faster anyway), removed GPU option (would need an entire cupy-centric build, does not make sense to be sharing a script with the CPU version).
53
+ 1.5. The dt dilator accounts for scaling by stretching (upsampling) images to equivalent scales before dilating with the distance transform. It will not attempt to downsample. This admittedly will ask for greater memory and some more processing. To give the user the option to use the dt dilator without dealing with this, I added two new options to the resize method. You can now have it upsample your image until its equivalently scaled, or, if you don't need the fidelity, downsample your image until it's equivalently scaled. When the scaling is equivalent, the dt dilator will always just use the regular distance transform without attempting to resize the array.
54
+
55
+ 2. Fixed radius finding method to also account for scaling correctly. Previous method scaled wrong. New method predictably accounts for differing scaling in xy vs z dims as well.
56
+
57
+ 3. Bug fixes.
@@ -0,0 +1,20 @@
1
+ nettracer3d/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ nettracer3d/community_extractor.py,sha256=5v9SCCLX3P1RX0fjPVKH5NHMFkMolZ5BTe0bR_a67xg,24479
3
+ nettracer3d/modularity.py,sha256=V1f3s_vGd8EuVz27mzq6ycIGr0BWIpH7c7NU4QjgAHU,30247
4
+ nettracer3d/morphology.py,sha256=P7hH9qpDBs0JtMSd95NmrvqoyD8BVq3AjAYv-MWoS_Y,19498
5
+ nettracer3d/nettracer.py,sha256=HDU7z9UOpc2rK1tp-gV7vum27NBNVe8CmfZEeJ7lDBc,209469
6
+ nettracer3d/nettracer_gui.py,sha256=ba_Kx84iu6qfdYKLjhwrS7cXvQQL0_YxrxM9PdIp6kk,401549
7
+ nettracer3d/network_analysis.py,sha256=q1q7lxtA3lebxitfC_jfiT9cnpYXJw4q0Oy2_-Aj8qE,48068
8
+ nettracer3d/network_draw.py,sha256=F7fw6Pcf4qWOhdKwLmhwqWdschbDlHzwCVolQC9imeU,14117
9
+ nettracer3d/node_draw.py,sha256=k3sCTfUCJs3aH1C1q1gTNxDz9EAQbBd1hsUIJajxRx8,9823
10
+ nettracer3d/proximity.py,sha256=mHgU24GZy5GGrR6RETB7QACfOURxgiyUze2dxMfs_3o,10917
11
+ nettracer3d/run.py,sha256=xYeaAc8FCx8MuzTGyL3NR3mK7WZzffAYAH23bNRZYO4,127
12
+ nettracer3d/segmenter.py,sha256=NcNeLSfg3ox-CfnUajT1E2iDqDkv5H6zSJOK_L5N4YI,85020
13
+ nettracer3d/simple_network.py,sha256=fP1gkDdtQcHruEZpUdasKdZeVacoLOxKhR3bY0L1CAQ,15426
14
+ nettracer3d/smart_dilate.py,sha256=ISZR6v52zf-MwhGx-JTfTOP8uo7pNGt-GJj7ydeuMAo,25587
15
+ nettracer3d-0.6.7.dist-info/licenses/LICENSE,sha256=gM207DhJjWrxLuEWXl0Qz5ISbtWDmADfjHp3yC2XISs,888
16
+ nettracer3d-0.6.7.dist-info/METADATA,sha256=jAjlCQhz-wFDiHbqF-nbVpEKu95n77H8CZNLP2cRnGI,4172
17
+ nettracer3d-0.6.7.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
18
+ nettracer3d-0.6.7.dist-info/entry_points.txt,sha256=Nx1rr_0QhJXDBHAQg2vcqCzLMKBzSHfwy3xwGkueVyc,53
19
+ nettracer3d-0.6.7.dist-info/top_level.txt,sha256=zsYy9rZwirfCEOubolhee4TyzqBAL5gSUeFMzhFTX8c,12
20
+ nettracer3d-0.6.7.dist-info/RECORD,,
@@ -1,20 +0,0 @@
1
- nettracer3d/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- nettracer3d/community_extractor.py,sha256=Zq8ZM595CTzeR6zLEZ4I6KvhkNfCPUReWvAKxTlaVfk,33495
3
- nettracer3d/modularity.py,sha256=V1f3s_vGd8EuVz27mzq6ycIGr0BWIpH7c7NU4QjgAHU,30247
4
- nettracer3d/morphology.py,sha256=yncUj04Noj_mcdJze4qMfYw-21AbebwiIcu1bDWGgCM,17778
5
- nettracer3d/nettracer.py,sha256=iq2EybaXzC9pdkNMmLQ_EqfFqHWMK-jxYqpb8Su61xQ,210230
6
- nettracer3d/nettracer_gui.py,sha256=o2DiNbEDrf5CK_CdIZNjArmx-eKbwHk25rzBwVeRE5A,394393
7
- nettracer3d/network_analysis.py,sha256=q1q7lxtA3lebxitfC_jfiT9cnpYXJw4q0Oy2_-Aj8qE,48068
8
- nettracer3d/network_draw.py,sha256=F7fw6Pcf4qWOhdKwLmhwqWdschbDlHzwCVolQC9imeU,14117
9
- nettracer3d/node_draw.py,sha256=k3sCTfUCJs3aH1C1q1gTNxDz9EAQbBd1hsUIJajxRx8,9823
10
- nettracer3d/proximity.py,sha256=FnIiI_AzfXd22HwCIFIyQRZxKYJ8YscIDdPnIv-wsO4,10560
11
- nettracer3d/run.py,sha256=xYeaAc8FCx8MuzTGyL3NR3mK7WZzffAYAH23bNRZYO4,127
12
- nettracer3d/segmenter.py,sha256=MC4-Bkz1JKcbkISwJaoCwhNmys9E2iXp1gmCn049JjU,85023
13
- nettracer3d/simple_network.py,sha256=fP1gkDdtQcHruEZpUdasKdZeVacoLOxKhR3bY0L1CAQ,15426
14
- nettracer3d/smart_dilate.py,sha256=vnBj2soDGVBioKaNQi-bcyAtg0nuWcNGmlrzUNFFYQE,23191
15
- nettracer3d-0.6.6.dist-info/licenses/LICENSE,sha256=gM207DhJjWrxLuEWXl0Qz5ISbtWDmADfjHp3yC2XISs,888
16
- nettracer3d-0.6.6.dist-info/METADATA,sha256=gro7B_GK6lL1oL-nd64pO69ynXwbZKBvShNBTKJVYu0,3559
17
- nettracer3d-0.6.6.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
18
- nettracer3d-0.6.6.dist-info/entry_points.txt,sha256=Nx1rr_0QhJXDBHAQg2vcqCzLMKBzSHfwy3xwGkueVyc,53
19
- nettracer3d-0.6.6.dist-info/top_level.txt,sha256=zsYy9rZwirfCEOubolhee4TyzqBAL5gSUeFMzhFTX8c,12
20
- nettracer3d-0.6.6.dist-info/RECORD,,