nettracer3d 0.5.2__py3-none-any.whl → 0.5.4__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/community_extractor.py +42 -0
- nettracer3d/morphology.py +63 -109
- nettracer3d/nettracer.py +70 -49
- nettracer3d/nettracer_gui.py +378 -81
- nettracer3d/proximity.py +45 -47
- nettracer3d/segmenter.py +1 -1
- {nettracer3d-0.5.2.dist-info → nettracer3d-0.5.4.dist-info}/METADATA +10 -1
- nettracer3d-0.5.4.dist-info/RECORD +21 -0
- nettracer3d-0.5.2.dist-info/RECORD +0 -21
- {nettracer3d-0.5.2.dist-info → nettracer3d-0.5.4.dist-info}/LICENSE +0 -0
- {nettracer3d-0.5.2.dist-info → nettracer3d-0.5.4.dist-info}/WHEEL +0 -0
- {nettracer3d-0.5.2.dist-info → nettracer3d-0.5.4.dist-info}/entry_points.txt +0 -0
- {nettracer3d-0.5.2.dist-info → nettracer3d-0.5.4.dist-info}/top_level.txt +0 -0
nettracer3d/proximity.py
CHANGED
|
@@ -3,6 +3,7 @@ from . import nettracer
|
|
|
3
3
|
import multiprocessing as mp
|
|
4
4
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
5
5
|
from scipy.spatial import KDTree
|
|
6
|
+
from scipy import ndimage
|
|
6
7
|
import concurrent.futures
|
|
7
8
|
import multiprocessing as mp
|
|
8
9
|
import pandas as pd
|
|
@@ -11,41 +12,35 @@ from typing import Dict, Union, Tuple, List, Optional
|
|
|
11
12
|
|
|
12
13
|
# Related to morphological border searching:
|
|
13
14
|
|
|
14
|
-
def get_reslice_indices(
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
indices, dilate_xy, dilate_z, array_shape = args
|
|
18
|
-
try:
|
|
19
|
-
max_indices = np.amax(indices, axis = 0) #Get the max/min of each index.
|
|
20
|
-
except ValueError: #Return Nones if this error is encountered
|
|
15
|
+
def get_reslice_indices(slice_obj, dilate_xy, dilate_z, array_shape):
|
|
16
|
+
"""Convert slice object to padded indices accounting for dilation and boundaries"""
|
|
17
|
+
if slice_obj is None:
|
|
21
18
|
return None, None, None
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
z_min,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
19
|
+
|
|
20
|
+
z_slice, y_slice, x_slice = slice_obj
|
|
21
|
+
|
|
22
|
+
# Extract min/max from slices
|
|
23
|
+
z_min, z_max = z_slice.start, z_slice.stop - 1
|
|
24
|
+
y_min, y_max = y_slice.start, y_slice.stop - 1
|
|
25
|
+
x_min, x_max = x_slice.start, x_slice.stop - 1
|
|
26
|
+
|
|
27
|
+
# Add dilation padding
|
|
28
|
+
y_max = y_max + ((dilate_xy-1)/2) + 1
|
|
29
|
+
y_min = y_min - ((dilate_xy-1)/2) - 1
|
|
30
|
+
x_max = x_max + ((dilate_xy-1)/2) + 1
|
|
31
31
|
x_min = x_min - ((dilate_xy-1)/2) - 1
|
|
32
32
|
z_max = z_max + ((dilate_z-1)/2) + 1
|
|
33
33
|
z_min = z_min - ((dilate_z-1)/2) - 1
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
x_min = 0
|
|
45
|
-
if z_min < 0:
|
|
46
|
-
z_min = 0
|
|
47
|
-
|
|
48
|
-
y_vals = [y_min, y_max] #Return the subarray dimensions as lists
|
|
35
|
+
# Boundary checks
|
|
36
|
+
y_max = min(y_max, array_shape[1] - 1)
|
|
37
|
+
x_max = min(x_max, array_shape[2] - 1)
|
|
38
|
+
z_max = min(z_max, array_shape[0] - 1)
|
|
39
|
+
y_min = max(y_min, 0)
|
|
40
|
+
x_min = max(x_min, 0)
|
|
41
|
+
z_min = max(z_min, 0)
|
|
42
|
+
|
|
43
|
+
y_vals = [y_min, y_max]
|
|
49
44
|
x_vals = [x_min, x_max]
|
|
50
45
|
z_vals = [z_min, z_max]
|
|
51
46
|
|
|
@@ -85,40 +80,43 @@ def _get_node_node_dict(label_array, label, dilate_xy, dilate_z):
|
|
|
85
80
|
return label_array
|
|
86
81
|
|
|
87
82
|
def process_label(args):
|
|
88
|
-
"""
|
|
89
|
-
nodes, label, dilate_xy, dilate_z, array_shape = args
|
|
83
|
+
"""Modified to use pre-computed bounding boxes instead of argwhere"""
|
|
84
|
+
nodes, label, dilate_xy, dilate_z, array_shape, bounding_boxes = args
|
|
90
85
|
print(f"Processing node {label}")
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
|
|
87
|
+
# Get the pre-computed bounding box for this label
|
|
88
|
+
slice_obj = bounding_boxes[label-1] # -1 because label numbers start at 1
|
|
89
|
+
if slice_obj is None:
|
|
93
90
|
return None, None
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
|
|
92
|
+
z_vals, y_vals, x_vals = get_reslice_indices(slice_obj, dilate_xy, dilate_z, array_shape)
|
|
93
|
+
if z_vals is None:
|
|
96
94
|
return None, None
|
|
95
|
+
|
|
97
96
|
sub_nodes = reslice_3d_array((nodes, z_vals, y_vals, x_vals))
|
|
98
97
|
return label, sub_nodes
|
|
99
98
|
|
|
100
99
|
|
|
101
|
-
def create_node_dictionary(nodes, num_nodes, dilate_xy, dilate_z, targets
|
|
102
|
-
"""
|
|
103
|
-
# Initialize the dictionary to be returned
|
|
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"""
|
|
104
102
|
node_dict = {}
|
|
105
|
-
|
|
106
103
|
array_shape = nodes.shape
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
|
|
105
|
+
# Get all bounding boxes at once
|
|
106
|
+
bounding_boxes = ndimage.find_objects(nodes)
|
|
107
|
+
|
|
109
108
|
# Use ThreadPoolExecutor for parallel execution
|
|
110
109
|
with ThreadPoolExecutor(max_workers=mp.cpu_count()) as executor:
|
|
111
|
-
#
|
|
112
|
-
|
|
113
|
-
|
|
110
|
+
# Create args list with bounding_boxes included
|
|
111
|
+
args_list = [(nodes, i, dilate_xy, dilate_z, array_shape, bounding_boxes)
|
|
112
|
+
for i in range(1, num_nodes + 1)]
|
|
114
113
|
|
|
115
114
|
if targets is not None:
|
|
116
115
|
args_list = [tup for tup in args_list if tup[1] in targets]
|
|
117
116
|
|
|
118
117
|
results = executor.map(process_label, args_list)
|
|
119
118
|
|
|
120
|
-
|
|
121
|
-
# Second parallel section to create dictionary entries
|
|
119
|
+
# Process results in parallel
|
|
122
120
|
for label, sub_nodes in results:
|
|
123
121
|
executor.submit(create_dict_entry, node_dict, label, sub_nodes, dilate_xy, dilate_z)
|
|
124
122
|
|
nettracer3d/segmenter.py
CHANGED
|
@@ -401,7 +401,7 @@ class InteractiveSegmenter:
|
|
|
401
401
|
|
|
402
402
|
return foreground, background
|
|
403
403
|
|
|
404
|
-
def segment_volume(self, chunk_size=
|
|
404
|
+
def segment_volume(self, chunk_size=None, gpu=False):
|
|
405
405
|
"""Segment volume using parallel processing of chunks with vectorized chunk creation"""
|
|
406
406
|
#Change the above chunk size to None to have it auto-compute largest chunks (not sure which is faster, 64 seems reasonable in test cases)
|
|
407
407
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: nettracer3d
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.4
|
|
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
|
|
@@ -26,6 +26,7 @@ Requires-Dist: tifffile==2023.7.18
|
|
|
26
26
|
Requires-Dist: qtrangeslider==0.1.5
|
|
27
27
|
Requires-Dist: PyQt6==6.8.0
|
|
28
28
|
Requires-Dist: scikit-learn==1.6.1
|
|
29
|
+
Requires-Dist: nibabel==5.2.0
|
|
29
30
|
Provides-Extra: cuda11
|
|
30
31
|
Requires-Dist: cupy-cuda11x; extra == "cuda11"
|
|
31
32
|
Provides-Extra: cuda12
|
|
@@ -42,3 +43,11 @@ for a video tutorial on using the GUI.
|
|
|
42
43
|
NetTracer3D is free to use/fork for academic/nonprofit use so long as citation is provided, and is available for commercial use at a fee (see license file for information).
|
|
43
44
|
|
|
44
45
|
NetTracer3D was developed by Liam McLaughlin while working under Dr. Sanjay Jain at Washington University School of Medicine.
|
|
46
|
+
|
|
47
|
+
-- Version 0.5.4 updates --
|
|
48
|
+
|
|
49
|
+
1. Added new function to GUI in image -> overlays -> color nodes/edges. Generates a rgb array corresponding to the nodes/edge labels where each node/edge (depending which array is selected) is randomly assigned a unique rgb color in an overlay channel. This can be used, for example, to color code labeled branches for easy identification of which branch is which.
|
|
50
|
+
|
|
51
|
+
2. Improved highlight overlay general functionality (for selecting nodes/edges). Previously selecting a node/edge had the program attempting to create an equal sized array as an overlay, find all objects corresponding to the selected ones, fill those into the new highlight overlay, then overlay that image. This was understandably quite slow in big arrays where the system was wasting a lot of time searching the entire array every time something was selected. New version retains this functionality for arrays below 125 million voxels, since search time is rather manageable at that size. For larger arrays, it instead draws the highlight for the selected objects only into the current slice, rendering a new slice whenever the user scrolls in the stack (although the entire highlight overlay is still initialized as a placeholder). Functions that require the use of the entire highlight overlay (such as masking) are correspondingly updated to draw the entirety of the highlight overlay before executing (when the system has up until that point been drawing slices one at a time). This will likely be the retained behavior moving forward, although to eliminate this behavior, one can open nettracer_gui.py and set self.mini_thresh to some comically large value. The new highlight overlay seems to work effectively the same but faster in my testing although it is possible a bug slipped through, which I will fix if informed about (or if I find it myself).
|
|
52
|
+
|
|
53
|
+
3. For the machine learning segmenter, changed the system to attempt to segment the image by chunking the array into the largest possible chunks that can be divided across all CPU cores. Previously the system split the array into 64^3 voxel sized chunks and passed those to the CPU cores until everything was processed. I am not sure which version is more efficient/faster so this is somewhat of a test. In theory the new behavior could be faster because it asking Python to interpret less stuff.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
nettracer3d/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
nettracer3d/community_extractor.py,sha256=Zq8ZM595CTzeR6zLEZ4I6KvhkNfCPUReWvAKxTlaVfk,33495
|
|
3
|
+
nettracer3d/hub_getter.py,sha256=KiNtxdajLkwB1ftslvrh1FE1Ch9ZCFEmHSEEotwR-To,8298
|
|
4
|
+
nettracer3d/modularity.py,sha256=V1f3s_vGd8EuVz27mzq6ycIGr0BWIpH7c7NU4QjgAHU,30247
|
|
5
|
+
nettracer3d/morphology.py,sha256=yQ0GuieMVXOQpaohZlPnkEXEuCUjf8Fg352axyK8nbM,10755
|
|
6
|
+
nettracer3d/nettracer.py,sha256=OE95IH1TfAZvT-htv1LEhw1EpnnEpkA83R5EcGMQDQg,209828
|
|
7
|
+
nettracer3d/nettracer_gui.py,sha256=fOKzicFOX9z-MEf_aD1SV8P4BuLKOdi6K1pxH-tiqrk,357091
|
|
8
|
+
nettracer3d/network_analysis.py,sha256=MJBBjslA1k_R8ymid77U-qGSgzxFVfzGVQhE0IdhnbE,48046
|
|
9
|
+
nettracer3d/network_draw.py,sha256=F7fw6Pcf4qWOhdKwLmhwqWdschbDlHzwCVolQC9imeU,14117
|
|
10
|
+
nettracer3d/node_draw.py,sha256=k3sCTfUCJs3aH1C1q1gTNxDz9EAQbBd1hsUIJajxRx8,9823
|
|
11
|
+
nettracer3d/proximity.py,sha256=FnIiI_AzfXd22HwCIFIyQRZxKYJ8YscIDdPnIv-wsO4,10560
|
|
12
|
+
nettracer3d/run.py,sha256=xYeaAc8FCx8MuzTGyL3NR3mK7WZzffAYAH23bNRZYO4,127
|
|
13
|
+
nettracer3d/segmenter.py,sha256=5Dqo_q-m28cYq4ROBhc4lyWjJnYK7ETTiRXyU_QdVXU,29688
|
|
14
|
+
nettracer3d/simple_network.py,sha256=fP1gkDdtQcHruEZpUdasKdZeVacoLOxKhR3bY0L1CAQ,15426
|
|
15
|
+
nettracer3d/smart_dilate.py,sha256=Kekm6YIVlJniMvJMG6_AwwNmCqK2l4Qtvg9VzzqPKMw,24600
|
|
16
|
+
nettracer3d-0.5.4.dist-info/LICENSE,sha256=gM207DhJjWrxLuEWXl0Qz5ISbtWDmADfjHp3yC2XISs,888
|
|
17
|
+
nettracer3d-0.5.4.dist-info/METADATA,sha256=dn0Reda7mqMn5rBXKcn53Ky_K6eXNNTyi6YlICSwwg8,5305
|
|
18
|
+
nettracer3d-0.5.4.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
19
|
+
nettracer3d-0.5.4.dist-info/entry_points.txt,sha256=Nx1rr_0QhJXDBHAQg2vcqCzLMKBzSHfwy3xwGkueVyc,53
|
|
20
|
+
nettracer3d-0.5.4.dist-info/top_level.txt,sha256=zsYy9rZwirfCEOubolhee4TyzqBAL5gSUeFMzhFTX8c,12
|
|
21
|
+
nettracer3d-0.5.4.dist-info/RECORD,,
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
nettracer3d/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
nettracer3d/community_extractor.py,sha256=8bRDJOfZhOFLtpkJVaDQrQ4O8wUywyr-EfVvW5fxyPs,31700
|
|
3
|
-
nettracer3d/hub_getter.py,sha256=KiNtxdajLkwB1ftslvrh1FE1Ch9ZCFEmHSEEotwR-To,8298
|
|
4
|
-
nettracer3d/modularity.py,sha256=V1f3s_vGd8EuVz27mzq6ycIGr0BWIpH7c7NU4QjgAHU,30247
|
|
5
|
-
nettracer3d/morphology.py,sha256=CsRWB0DY-vBBlKdF9IQwgfYYZswuE7n1Iu_Osxgmxnw,13042
|
|
6
|
-
nettracer3d/nettracer.py,sha256=hDccGy6RybSJFvY6dsN1l5eM3wKZW93CizlTvgEeyNs,209690
|
|
7
|
-
nettracer3d/nettracer_gui.py,sha256=dQUhNeeVQCkuXrvtdUmqSs184Gr8Y-neoWPWcXhGaAo,340385
|
|
8
|
-
nettracer3d/network_analysis.py,sha256=MJBBjslA1k_R8ymid77U-qGSgzxFVfzGVQhE0IdhnbE,48046
|
|
9
|
-
nettracer3d/network_draw.py,sha256=F7fw6Pcf4qWOhdKwLmhwqWdschbDlHzwCVolQC9imeU,14117
|
|
10
|
-
nettracer3d/node_draw.py,sha256=k3sCTfUCJs3aH1C1q1gTNxDz9EAQbBd1hsUIJajxRx8,9823
|
|
11
|
-
nettracer3d/proximity.py,sha256=B1pmFegx5Wb0JKI5rvpILv2VRU09f6M2iljAQAqBja0,11059
|
|
12
|
-
nettracer3d/run.py,sha256=xYeaAc8FCx8MuzTGyL3NR3mK7WZzffAYAH23bNRZYO4,127
|
|
13
|
-
nettracer3d/segmenter.py,sha256=Rr5MUUWgGHYzzTy4hzbO3zzJhNIKsyjV1Qxg99Pb8QY,29686
|
|
14
|
-
nettracer3d/simple_network.py,sha256=fP1gkDdtQcHruEZpUdasKdZeVacoLOxKhR3bY0L1CAQ,15426
|
|
15
|
-
nettracer3d/smart_dilate.py,sha256=Kekm6YIVlJniMvJMG6_AwwNmCqK2l4Qtvg9VzzqPKMw,24600
|
|
16
|
-
nettracer3d-0.5.2.dist-info/LICENSE,sha256=gM207DhJjWrxLuEWXl0Qz5ISbtWDmADfjHp3yC2XISs,888
|
|
17
|
-
nettracer3d-0.5.2.dist-info/METADATA,sha256=M7khbzBNHwsNJ2KqmNKwnP1rvk1v37E6BI7dD9mQU58,2912
|
|
18
|
-
nettracer3d-0.5.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
19
|
-
nettracer3d-0.5.2.dist-info/entry_points.txt,sha256=Nx1rr_0QhJXDBHAQg2vcqCzLMKBzSHfwy3xwGkueVyc,53
|
|
20
|
-
nettracer3d-0.5.2.dist-info/top_level.txt,sha256=zsYy9rZwirfCEOubolhee4TyzqBAL5gSUeFMzhFTX8c,12
|
|
21
|
-
nettracer3d-0.5.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|