nettracer3d 0.6.7__tar.gz → 0.6.8__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.
Potentially problematic release.
This version of nettracer3d might be problematic. Click here for more details.
- {nettracer3d-0.6.7/src/nettracer3d.egg-info → nettracer3d-0.6.8}/PKG-INFO +4 -8
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/README.md +3 -7
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/pyproject.toml +1 -1
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d/nettracer_gui.py +202 -9
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d/proximity.py +1 -1
- {nettracer3d-0.6.7 → nettracer3d-0.6.8/src/nettracer3d.egg-info}/PKG-INFO +4 -8
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/LICENSE +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/setup.cfg +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d/__init__.py +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d/community_extractor.py +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d/modularity.py +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d/morphology.py +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d/nettracer.py +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d/network_analysis.py +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d/network_draw.py +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d/node_draw.py +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d/run.py +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d/segmenter.py +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d/simple_network.py +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d/smart_dilate.py +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d.egg-info/SOURCES.txt +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d.egg-info/dependency_links.txt +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d.egg-info/entry_points.txt +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d.egg-info/requires.txt +0 -0
- {nettracer3d-0.6.7 → nettracer3d-0.6.8}/src/nettracer3d.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nettracer3d
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.8
|
|
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,12 +46,8 @@ 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.
|
|
49
|
+
-- Version 0.6.8 updates --
|
|
50
50
|
|
|
51
|
-
1.
|
|
51
|
+
1. Added new fill-can and 3D-brush functionalities to the brush mode (press f in brush mode to toggle the fill can. Press d while in brush mode to use the 3D painting tools. Standard Mouse wheel scrolling in the 3D painter will change how many frames you paint on - ie. 5 lets you paint 2 above and 2 below).
|
|
52
52
|
|
|
53
|
-
1.5.
|
|
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.
|
|
53
|
+
1.5. Added single-use ctrl-z functionality to the fill can only because of how easily it can mess up. (Leaving the fill can mode will garbage collect the backup image though).
|
|
@@ -8,12 +8,8 @@ NetTracer3D is free to use/fork for academic/nonprofit use so long as citation i
|
|
|
8
8
|
|
|
9
9
|
NetTracer3D was developed by Liam McLaughlin while working under Dr. Sanjay Jain at Washington University School of Medicine.
|
|
10
10
|
|
|
11
|
-
-- Version 0.6.
|
|
11
|
+
-- Version 0.6.8 updates --
|
|
12
12
|
|
|
13
|
-
1.
|
|
13
|
+
1. Added new fill-can and 3D-brush functionalities to the brush mode (press f in brush mode to toggle the fill can. Press d while in brush mode to use the 3D painting tools. Standard Mouse wheel scrolling in the 3D painter will change how many frames you paint on - ie. 5 lets you paint 2 above and 2 below).
|
|
14
14
|
|
|
15
|
-
1.5.
|
|
16
|
-
|
|
17
|
-
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.
|
|
18
|
-
|
|
19
|
-
3. Bug fixes.
|
|
15
|
+
1.5. Added single-use ctrl-z functionality to the fill can only because of how easily it can mess up. (Leaving the fill can mode will garbage collect the backup image though).
|
|
@@ -18,7 +18,7 @@ from nettracer3d import smart_dilate as sdl
|
|
|
18
18
|
from matplotlib.colors import LinearSegmentedColormap
|
|
19
19
|
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
|
20
20
|
import pandas as pd
|
|
21
|
-
from PyQt6.QtGui import (QFont, QCursor, QColor, QPixmap, QPainter, QPen)
|
|
21
|
+
from PyQt6.QtGui import (QFont, QCursor, QColor, QPixmap, QFontMetrics, QPainter, QPen)
|
|
22
22
|
import tifffile
|
|
23
23
|
import copy
|
|
24
24
|
import multiprocessing as mp
|
|
@@ -118,6 +118,9 @@ class ImageViewerWindow(QMainWindow):
|
|
|
118
118
|
|
|
119
119
|
#For ML segmenting mode
|
|
120
120
|
self.brush_mode = False
|
|
121
|
+
self.can = False
|
|
122
|
+
self.threed = False
|
|
123
|
+
self.threedthresh = 5
|
|
121
124
|
self.painting = False
|
|
122
125
|
self.foreground = True
|
|
123
126
|
self.machine_window = None
|
|
@@ -1712,6 +1715,9 @@ class ImageViewerWindow(QMainWindow):
|
|
|
1712
1715
|
self.pen_button.setChecked(False)
|
|
1713
1716
|
self.pan_mode = False
|
|
1714
1717
|
self.brush_mode = False
|
|
1718
|
+
self.can = False
|
|
1719
|
+
self.threed = False
|
|
1720
|
+
self.last_change = None
|
|
1715
1721
|
if self.machine_window is not None:
|
|
1716
1722
|
self.machine_window.silence_button()
|
|
1717
1723
|
self.canvas.setCursor(Qt.CursorShape.CrossCursor)
|
|
@@ -1729,6 +1735,9 @@ class ImageViewerWindow(QMainWindow):
|
|
|
1729
1735
|
self.zoom_button.setChecked(False)
|
|
1730
1736
|
self.pen_button.setChecked(False)
|
|
1731
1737
|
self.zoom_mode = False
|
|
1738
|
+
self.can = False
|
|
1739
|
+
self.threed = False
|
|
1740
|
+
self.last_change = None
|
|
1732
1741
|
self.brush_mode = False
|
|
1733
1742
|
if self.machine_window is not None:
|
|
1734
1743
|
self.machine_window.silence_button()
|
|
@@ -1749,14 +1758,69 @@ class ImageViewerWindow(QMainWindow):
|
|
|
1749
1758
|
self.zoom_mode = False
|
|
1750
1759
|
self.update_brush_cursor()
|
|
1751
1760
|
else:
|
|
1761
|
+
self.last_change = None
|
|
1762
|
+
self.can = False
|
|
1763
|
+
self.threed = False
|
|
1752
1764
|
self.canvas.setCursor(Qt.CursorShape.ArrowCursor)
|
|
1753
1765
|
|
|
1766
|
+
def toggle_can(self):
|
|
1767
|
+
|
|
1768
|
+
if not self.can:
|
|
1769
|
+
self.can = True
|
|
1770
|
+
self.update_brush_cursor()
|
|
1771
|
+
else:
|
|
1772
|
+
self.can = False
|
|
1773
|
+
self.last_change = None
|
|
1774
|
+
self.update_brush_cursor()
|
|
1775
|
+
|
|
1776
|
+
def toggle_threed(self):
|
|
1777
|
+
|
|
1778
|
+
if not self.threed:
|
|
1779
|
+
self.threed = True
|
|
1780
|
+
self.threedthresh = 5
|
|
1781
|
+
self.update_brush_cursor()
|
|
1782
|
+
else:
|
|
1783
|
+
self.threed = False
|
|
1784
|
+
self.update_brush_cursor()
|
|
1785
|
+
|
|
1754
1786
|
|
|
1755
1787
|
def on_mpl_scroll(self, event):
|
|
1756
1788
|
"""Handle matplotlib canvas scroll events"""
|
|
1757
1789
|
#Wheel events
|
|
1758
1790
|
if self.brush_mode and event.inaxes == self.ax:
|
|
1791
|
+
|
|
1792
|
+
# Get modifiers
|
|
1793
|
+
modifiers = event.guiEvent.modifiers()
|
|
1794
|
+
ctrl_pressed = bool(modifiers & Qt.ControlModifier)
|
|
1795
|
+
shift_pressed = bool(modifiers & Qt.ShiftModifier)
|
|
1796
|
+
alt_pressed = bool(modifiers & Qt.AltModifier)
|
|
1797
|
+
|
|
1798
|
+
# Check if threed is enabled and ONLY if no specific modifiers are pressed
|
|
1799
|
+
if self.threed and not ctrl_pressed and not shift_pressed and not alt_pressed:
|
|
1800
|
+
import math
|
|
1801
|
+
step = 1 if event.button == 'up' else -1
|
|
1802
|
+
self.threedthresh += step
|
|
1803
|
+
|
|
1804
|
+
# Round to appropriate odd integer based on scroll direction
|
|
1805
|
+
if event.button == 'up':
|
|
1806
|
+
# Round up to nearest odd
|
|
1807
|
+
self.threedthresh = math.ceil(self.threedthresh)
|
|
1808
|
+
if self.threedthresh % 2 == 0:
|
|
1809
|
+
self.threedthresh += 1
|
|
1810
|
+
else: # event.button == 'down'
|
|
1811
|
+
# Round down to nearest odd, but not below 1
|
|
1812
|
+
self.threedthresh = math.floor(self.threedthresh)
|
|
1813
|
+
if self.threedthresh % 2 == 0:
|
|
1814
|
+
self.threedthresh -= 1
|
|
1815
|
+
# Ensure not below minimum value of 1
|
|
1816
|
+
self.threedthresh = max(1, self.threedthresh)
|
|
1817
|
+
|
|
1818
|
+
# Update the brush cursor to show the new threshold
|
|
1819
|
+
self.update_brush_cursor()
|
|
1820
|
+
return
|
|
1821
|
+
|
|
1759
1822
|
# Check if Ctrl is pressed
|
|
1823
|
+
|
|
1760
1824
|
if event.guiEvent.modifiers() & Qt.ShiftModifier:
|
|
1761
1825
|
pass
|
|
1762
1826
|
|
|
@@ -1793,6 +1857,15 @@ class ImageViewerWindow(QMainWindow):
|
|
|
1793
1857
|
self.update_display(preserve_zoom=(current_xlim, current_ylim))
|
|
1794
1858
|
|
|
1795
1859
|
def keyPressEvent(self, event):
|
|
1860
|
+
|
|
1861
|
+
if event.key() == Qt.Key_Z and event.modifiers() & Qt.ControlModifier:
|
|
1862
|
+
try:
|
|
1863
|
+
self.load_channel(self.last_change[1], self.last_change[0], True)
|
|
1864
|
+
except:
|
|
1865
|
+
pass
|
|
1866
|
+
|
|
1867
|
+
return # Return to prevent triggering the regular Z key action below
|
|
1868
|
+
|
|
1796
1869
|
if event.key() == Qt.Key_Z:
|
|
1797
1870
|
self.zoom_button.click()
|
|
1798
1871
|
if self.machine_window is not None:
|
|
@@ -1800,28 +1873,65 @@ class ImageViewerWindow(QMainWindow):
|
|
|
1800
1873
|
self.machine_window.switch_foreground()
|
|
1801
1874
|
if event.key() == Qt.Key_X:
|
|
1802
1875
|
self.high_button.click()
|
|
1876
|
+
if self.brush_mode and self.machine_window is None:
|
|
1877
|
+
if event.key() == Qt.Key_F:
|
|
1878
|
+
self.toggle_can()
|
|
1879
|
+
elif event.key() == Qt.Key_D:
|
|
1880
|
+
self.toggle_threed()
|
|
1803
1881
|
|
|
1804
1882
|
|
|
1805
1883
|
def update_brush_cursor(self):
|
|
1806
1884
|
"""Update the cursor to show brush size"""
|
|
1807
1885
|
if not self.brush_mode:
|
|
1808
1886
|
return
|
|
1809
|
-
|
|
1810
|
-
#
|
|
1811
|
-
|
|
1812
|
-
|
|
1887
|
+
|
|
1888
|
+
# Get font metrics first to determine text size
|
|
1889
|
+
font = QFont()
|
|
1890
|
+
font.setPointSize(14)
|
|
1891
|
+
font_metrics = QFontMetrics(font)
|
|
1892
|
+
thresh_text = str(self.threedthresh)
|
|
1893
|
+
text_rect = font_metrics.boundingRect(thresh_text)
|
|
1894
|
+
|
|
1895
|
+
# Create a pixmap for the cursor - ensure it's large enough for text
|
|
1896
|
+
brush_size = self.brush_size * 2 + 2 # Add padding for border
|
|
1897
|
+
extra_width = max(0, text_rect.width() + 4 - brush_size) # Extra width for text if needed
|
|
1898
|
+
extra_height = max(0, text_rect.height() + 4 - brush_size) # Extra height for text if needed
|
|
1899
|
+
|
|
1900
|
+
# Make sure pixmap is large enough for both brush and text
|
|
1901
|
+
total_width = brush_size + extra_width
|
|
1902
|
+
total_height = brush_size + extra_height
|
|
1903
|
+
pixmap = QPixmap(total_width, total_height)
|
|
1813
1904
|
pixmap.fill(Qt.transparent)
|
|
1814
1905
|
|
|
1815
1906
|
# Create painter for the pixmap
|
|
1816
1907
|
painter = QPainter(pixmap)
|
|
1817
1908
|
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
|
|
1818
1909
|
|
|
1910
|
+
# Calculate center offset for brush ellipse to accommodate text
|
|
1911
|
+
x_offset = extra_width // 2
|
|
1912
|
+
y_offset = extra_height // 2
|
|
1913
|
+
|
|
1819
1914
|
# Draw circle
|
|
1820
|
-
|
|
1915
|
+
if not self.threed:
|
|
1916
|
+
pen = QPen(Qt.white)
|
|
1917
|
+
else:
|
|
1918
|
+
pen = QPen(Qt.red)
|
|
1821
1919
|
pen.setWidth(1)
|
|
1822
1920
|
painter.setPen(pen)
|
|
1823
1921
|
painter.setBrush(Qt.transparent)
|
|
1824
|
-
|
|
1922
|
+
if not self.can:
|
|
1923
|
+
painter.drawEllipse(1 + x_offset, 1 + y_offset, brush_size-2, brush_size-2)
|
|
1924
|
+
|
|
1925
|
+
# Draw threshold number when threed is True and can is False
|
|
1926
|
+
if self.threed:
|
|
1927
|
+
# Set text properties
|
|
1928
|
+
painter.setFont(font)
|
|
1929
|
+
painter.setPen(QPen(Qt.white)) # White text for visibility
|
|
1930
|
+
|
|
1931
|
+
# Draw the text
|
|
1932
|
+
painter.drawText(2, font_metrics.ascent() + 2, thresh_text)
|
|
1933
|
+
else:
|
|
1934
|
+
painter.drawRect(1 + x_offset, 1 + y_offset, 8, 8)
|
|
1825
1935
|
|
|
1826
1936
|
# Create cursor from pixmap
|
|
1827
1937
|
cursor = QCursor(pixmap)
|
|
@@ -1929,13 +2039,20 @@ class ImageViewerWindow(QMainWindow):
|
|
|
1929
2039
|
|
|
1930
2040
|
if event.button == 1 or event.button == 3:
|
|
1931
2041
|
|
|
2042
|
+
x, y = int(event.xdata), int(event.ydata)
|
|
2043
|
+
|
|
2044
|
+
|
|
2045
|
+
if event.button == 1 and self.can:
|
|
2046
|
+
self.handle_can(x, y)
|
|
2047
|
+
return
|
|
2048
|
+
|
|
2049
|
+
|
|
1932
2050
|
if event.button == 3:
|
|
1933
2051
|
self.erase = True
|
|
1934
2052
|
else:
|
|
1935
2053
|
self.erase = False
|
|
1936
2054
|
|
|
1937
2055
|
self.painting = True
|
|
1938
|
-
x, y = int(event.xdata), int(event.ydata)
|
|
1939
2056
|
self.last_paint_pos = (x, y)
|
|
1940
2057
|
|
|
1941
2058
|
if self.pen_button.isChecked():
|
|
@@ -1995,7 +2112,77 @@ class ImageViewerWindow(QMainWindow):
|
|
|
1995
2112
|
for x in range(max(0, center_x - radius), min(width, center_x + radius + 1)):
|
|
1996
2113
|
# Check if point is within circular brush area
|
|
1997
2114
|
if (x - center_x) ** 2 + (y - center_y) ** 2 <= radius ** 2:
|
|
1998
|
-
|
|
2115
|
+
|
|
2116
|
+
if self.threed and self.threedthresh > 1:
|
|
2117
|
+
amount = (self.threedthresh - 1) / 2
|
|
2118
|
+
low = max(0, self.current_slice - amount)
|
|
2119
|
+
high = min(self.channel_data[channel].shape[0] - 1, self.current_slice + amount)
|
|
2120
|
+
|
|
2121
|
+
for i in range(int(low), int(high + 1)):
|
|
2122
|
+
self.channel_data[channel][i][y, x] = val
|
|
2123
|
+
else:
|
|
2124
|
+
self.channel_data[channel][self.current_slice][y, x] = val
|
|
2125
|
+
|
|
2126
|
+
def handle_can(self, x, y):
|
|
2127
|
+
|
|
2128
|
+
|
|
2129
|
+
if self.threed:
|
|
2130
|
+
ref = copy.deepcopy(self.channel_data[self.active_channel])
|
|
2131
|
+
the_slice = self.channel_data[self.active_channel]
|
|
2132
|
+
|
|
2133
|
+
# First invert the boolean array
|
|
2134
|
+
inv = n3d.invert_boolean(the_slice)
|
|
2135
|
+
|
|
2136
|
+
# Label the connected components in the inverted array
|
|
2137
|
+
labeled_array, num_features = n3d.label_objects(inv)
|
|
2138
|
+
|
|
2139
|
+
# Get the target label at the clicked point
|
|
2140
|
+
target_label = labeled_array[self.current_slice][y][x]
|
|
2141
|
+
|
|
2142
|
+
# Only fill if we clicked on a valid region (target_label > 0)
|
|
2143
|
+
if target_label > 0:
|
|
2144
|
+
# Create a mask of the connected component we clicked on
|
|
2145
|
+
fill_mask = (labeled_array == target_label) * 255
|
|
2146
|
+
|
|
2147
|
+
self.last_change = [ref, self.active_channel]
|
|
2148
|
+
|
|
2149
|
+
# Add this mask to the original slice
|
|
2150
|
+
the_slice = the_slice | fill_mask # Use logical OR to add the filled region
|
|
2151
|
+
|
|
2152
|
+
# Update the channel data
|
|
2153
|
+
self.load_channel(self.active_channel, the_slice, True)
|
|
2154
|
+
else:
|
|
2155
|
+
|
|
2156
|
+
ref = copy.deepcopy(self.channel_data[self.active_channel])
|
|
2157
|
+
|
|
2158
|
+
the_slice = self.channel_data[self.active_channel][self.current_slice]
|
|
2159
|
+
|
|
2160
|
+
# First invert the boolean array
|
|
2161
|
+
inv = n3d.invert_boolean(the_slice)
|
|
2162
|
+
|
|
2163
|
+
# Label the connected components in the inverted array
|
|
2164
|
+
labeled_array, num_features = n3d.label_objects(inv)
|
|
2165
|
+
|
|
2166
|
+
# Get the target label at the clicked point
|
|
2167
|
+
target_label = labeled_array[y][x]
|
|
2168
|
+
|
|
2169
|
+
# Only fill if we clicked on a valid region (target_label > 0)
|
|
2170
|
+
if target_label > 0:
|
|
2171
|
+
# Create a mask of the connected component we clicked on
|
|
2172
|
+
fill_mask = (labeled_array == target_label) * 255
|
|
2173
|
+
|
|
2174
|
+
self.last_change = [ref, self.active_channel]
|
|
2175
|
+
|
|
2176
|
+
# Add this mask to the original slice
|
|
2177
|
+
the_slice = the_slice | fill_mask # Use logical OR to add the filled region
|
|
2178
|
+
|
|
2179
|
+
# Update the channel data
|
|
2180
|
+
self.channel_data[self.active_channel][self.current_slice] = the_slice
|
|
2181
|
+
self.load_channel(self.active_channel, self.channel_data[self.active_channel], True)
|
|
2182
|
+
|
|
2183
|
+
|
|
2184
|
+
|
|
2185
|
+
|
|
1999
2186
|
|
|
2000
2187
|
def on_mouse_move(self, event):
|
|
2001
2188
|
"""Handle mouse movement events."""
|
|
@@ -2082,6 +2269,7 @@ class ImageViewerWindow(QMainWindow):
|
|
|
2082
2269
|
points = self.get_line_points(last_x, last_y, x, y)
|
|
2083
2270
|
|
|
2084
2271
|
# Paint at each point along the line
|
|
2272
|
+
|
|
2085
2273
|
for px, py in points:
|
|
2086
2274
|
if 0 <= px < width and 0 <= py < height:
|
|
2087
2275
|
self.paint_at_position(px, py, self.erase, channel)
|
|
@@ -6776,6 +6964,9 @@ class MachineWindow(QMainWindow):
|
|
|
6776
6964
|
|
|
6777
6965
|
if self.parent().pen_button.isChecked(): #Disable the pen mode if the user is in it because the segmenter pen forks it
|
|
6778
6966
|
self.parent().pen_button.click()
|
|
6967
|
+
self.parent().threed = False
|
|
6968
|
+
self.parent().can = False
|
|
6969
|
+
self.parent().last_change = None
|
|
6779
6970
|
|
|
6780
6971
|
self.parent().pen_button.setEnabled(False)
|
|
6781
6972
|
|
|
@@ -7002,6 +7193,8 @@ class MachineWindow(QMainWindow):
|
|
|
7002
7193
|
self.parent().zoom_mode = False
|
|
7003
7194
|
self.parent().update_brush_cursor()
|
|
7004
7195
|
else:
|
|
7196
|
+
self.threed = False
|
|
7197
|
+
self.can = False
|
|
7005
7198
|
self.parent().zoom_button.click()
|
|
7006
7199
|
|
|
7007
7200
|
def silence_button(self):
|
|
@@ -82,7 +82,7 @@ def _get_node_node_dict(label_array, label, dilate_xy, dilate_z, fastdil = False
|
|
|
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
|
-
|
|
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nettracer3d
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.8
|
|
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,12 +46,8 @@ 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.
|
|
49
|
+
-- Version 0.6.8 updates --
|
|
50
50
|
|
|
51
|
-
1.
|
|
51
|
+
1. Added new fill-can and 3D-brush functionalities to the brush mode (press f in brush mode to toggle the fill can. Press d while in brush mode to use the 3D painting tools. Standard Mouse wheel scrolling in the 3D painter will change how many frames you paint on - ie. 5 lets you paint 2 above and 2 below).
|
|
52
52
|
|
|
53
|
-
1.5.
|
|
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.
|
|
53
|
+
1.5. Added single-use ctrl-z functionality to the fill can only because of how easily it can mess up. (Leaving the fill can mode will garbage collect the backup image though).
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|