nettracer3d 0.9.6__py3-none-any.whl → 0.9.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.

Potentially problematic release.


This version of nettracer3d might be problematic. Click here for more details.

@@ -109,7 +109,7 @@ class ImageViewerWindow(QMainWindow):
109
109
  self.color_dictionary['LIGHT_RED'], # Lighter red
110
110
  self.color_dictionary['LIGHT_GREEN'], # Lighter green
111
111
  self.color_dictionary['WHITE'], # White
112
- self.color_dictionary['WHITE'] # White
112
+ self.color_dictionary['CYAN'] # Now cyan
113
113
  ]
114
114
 
115
115
 
@@ -2494,6 +2494,12 @@ class ImageViewerWindow(QMainWindow):
2494
2494
 
2495
2495
  self.update_display(preserve_zoom=(current_xlim, current_ylim))
2496
2496
 
2497
+ if self.pan_mode:
2498
+ self.create_pan_background()
2499
+ current_xlim = self.ax.get_xlim()
2500
+ current_ylim = self.ax.get_ylim()
2501
+ self.update_display_pan_mode(current_xlim, current_ylim)
2502
+
2497
2503
 
2498
2504
  def toggle_zoom_mode(self):
2499
2505
  """Toggle zoom mode on/off."""
@@ -2501,7 +2507,9 @@ class ImageViewerWindow(QMainWindow):
2501
2507
 
2502
2508
  if self.zoom_mode:
2503
2509
  if self.pan_mode:
2504
- self.pan_button.click()
2510
+ self.update_display(preserve_zoom=(self.ax.get_xlim(), self.ax.get_ylim()))
2511
+ self.pan_mode = False
2512
+ self.pan_button.setChecked(False)
2505
2513
 
2506
2514
  self.pen_button.setChecked(False)
2507
2515
  self.brush_mode = False
@@ -2522,11 +2530,6 @@ class ImageViewerWindow(QMainWindow):
2522
2530
  current_xlim = self.ax.get_xlim()
2523
2531
  current_ylim = self.ax.get_ylim()
2524
2532
  self.update_display(preserve_zoom=(current_xlim, current_ylim))
2525
- if self.pan_mode:
2526
- current_xlim = self.ax.get_xlim()
2527
- current_ylim = self.ax.get_ylim()
2528
- self.update_display(preserve_zoom=(current_xlim, current_ylim))
2529
- self.pan_mode = False
2530
2533
 
2531
2534
  else:
2532
2535
  if self.machine_window is None:
@@ -2605,7 +2608,9 @@ class ImageViewerWindow(QMainWindow):
2605
2608
  if self.brush_mode:
2606
2609
 
2607
2610
  if self.pan_mode:
2608
- self.pan_button.click()
2611
+ self.update_display(preserve_zoom=(self.ax.get_xlim(), self.ax.get_ylim()))
2612
+ self.pan_mode = False
2613
+ self.pan_button.setChecked(False)
2609
2614
 
2610
2615
  self.pm = painting.PaintManager(parent = self)
2611
2616
 
@@ -3594,8 +3599,8 @@ class ImageViewerWindow(QMainWindow):
3594
3599
  # Multi-color highlight for machine window
3595
3600
  mask_1 = (highlight_data == 1)
3596
3601
  mask_2 = (highlight_data == 2)
3597
- rgba[mask_1] = [1, 1, 0, 0.5] # Yellow for 1
3598
- rgba[mask_2] = [0, 0.7, 1, 0.5] # Blue for 2
3602
+ rgba[mask_1] = [1, 1, 0, 0.3] # Yellow for 1
3603
+ rgba[mask_2] = [0, 0.7, 1, 0.3] # Blue for 2
3599
3604
 
3600
3605
  return rgba
3601
3606
 
@@ -6088,17 +6093,6 @@ class ImageViewerWindow(QMainWindow):
6088
6093
  pass
6089
6094
  self.static_background = None
6090
6095
 
6091
- # Your existing machine_window logic
6092
- if self.machine_window is None:
6093
- try:
6094
- self.channel_data[4][self.current_slice, :, :] = n3d.overlay_arrays_simple(
6095
- self.channel_data[self.temp_chan][self.current_slice, :, :],
6096
- self.channel_data[4][self.current_slice, :, :])
6097
- self.load_channel(self.temp_chan, self.channel_data[4], data=True, end_paint=True)
6098
- self.channel_data[4] = None
6099
- self.channel_visible[4] = False
6100
- except:
6101
- pass
6102
6096
 
6103
6097
  # Get dimensions
6104
6098
  active_channels = [i for i in range(4) if self.channel_data[i] is not None]
@@ -10991,6 +10985,8 @@ class MachineWindow(QMainWindow):
10991
10985
  def toggle_brush_mode(self):
10992
10986
  """Toggle brush mode on/off"""
10993
10987
  self.parent().brush_mode = self.brush_button.isChecked()
10988
+ if self.parent().pan_mode:
10989
+ self.parent().update_display(preserve_zoom=(self.parent().ax.get_xlim(), self.parent().ax.get_ylim()))
10994
10990
 
10995
10991
  if self.parent().brush_mode:
10996
10992
 
nettracer3d/segmenter.py CHANGED
@@ -192,10 +192,10 @@ class InteractiveSegmenter:
192
192
  if image_2d is None:
193
193
  image_2d = self.image_3d[z, :, :]
194
194
 
195
- if image_2d.ndim == 3 and image_2d.shape[-1] == 3:
195
+ if image_2d.ndim == 3 and (image_2d.shape[-1] == 3 or image_2d.shape[-1] == 4):
196
196
  # RGB case - process each channel
197
197
  features_per_channel = []
198
- for channel in range(3):
198
+ for channel in range(image_2d.shape[-1]):
199
199
  channel_features = self.compute_deep_feature_maps_cpu_2d(image_2d = image_2d[..., channel])
200
200
  features_per_channel.append(channel_features)
201
201
 
@@ -308,10 +308,10 @@ class InteractiveSegmenter:
308
308
  if image_2d is None:
309
309
  image_2d = self.image_3d[z, :, :]
310
310
 
311
- if image_2d.ndim == 3 and image_2d.shape[-1] == 3:
311
+ if image_2d.ndim == 3 and (image_2d.shape[-1] == 3 or image_2d.shape[-1] == 4):
312
312
  # RGB case - process each channel
313
313
  features_per_channel = []
314
- for channel in range(3):
314
+ for channel in range(image_2d.shape[-1]):
315
315
  channel_features = self.compute_feature_maps_cpu_2d(image_2d = image_2d[..., channel])
316
316
  features_per_channel.append(channel_features)
317
317
 
@@ -361,10 +361,10 @@ class InteractiveSegmenter:
361
361
  if image_3d is None:
362
362
  image_3d = self.image_3d
363
363
 
364
- if image_3d.ndim == 4 and image_3d.shape[-1] == 3:
364
+ if image_3d.ndim == 4 and (image_3d.shape[-1] == 3 or image_3d.shape[-1] == 4):
365
365
  # RGB case - process each channel
366
366
  features_per_channel = []
367
- for channel in range(3):
367
+ for channel in range(image_3d.shape[-1]):
368
368
  channel_features = self.compute_deep_feature_maps_cpu(image_3d[..., channel])
369
369
  features_per_channel.append(channel_features)
370
370
 
@@ -483,127 +483,15 @@ class InteractiveSegmenter:
483
483
 
484
484
  return features
485
485
 
486
- def compute_deep_feature_maps_cpu_smaller(self, image_3d=None): #smaller
487
- """Optimized version using determinant instead of full eigenvalue computation. Currently not in use anywhere"""
488
- if image_3d is None:
489
- image_3d = self.image_3d
490
-
491
- # Calculate total number of features (using determinant instead of 3 eigenvalues)
492
- num_basic_features = 1 + len(self.sigmas) + len(self.dogs)
493
- num_gradient_features = len(self.sigmas)
494
- num_laplacian_features = len(self.sigmas)
495
- num_hessian_features = len(self.sigmas) * 3 # determinant + trace + frobenius norm
496
-
497
- total_features = num_basic_features + num_gradient_features + num_laplacian_features + num_hessian_features
498
-
499
- # Pre-allocate result array
500
- features = np.empty(image_3d.shape + (total_features,), dtype=image_3d.dtype)
501
- features[..., 0] = image_3d
502
-
503
- feature_idx = 1
504
-
505
- # Cache for Gaussian filters
506
- gaussian_cache = {}
507
- all_sigmas = set(self.sigmas)
508
- for s1, s2 in self.dogs:
509
- all_sigmas.add(s1)
510
- all_sigmas.add(s2)
511
-
512
- # Pre-compute all Gaussian filters
513
- for sigma in all_sigmas:
514
- gaussian_cache[sigma] = ndimage.gaussian_filter(image_3d, sigma)
515
-
516
- # Gaussian smoothing
517
- for sigma in self.sigmas:
518
- features[..., feature_idx] = gaussian_cache[sigma]
519
- feature_idx += 1
520
-
521
- # Difference of Gaussians
522
- for s1, s2 in self.dogs:
523
- features[..., feature_idx] = gaussian_cache[s1] - gaussian_cache[s2]
524
- feature_idx += 1
525
-
526
- # Gaussian gradient magnitudes
527
- for sigma in self.sigmas:
528
- gaussian_img = gaussian_cache[sigma]
529
- gx = ndimage.sobel(gaussian_img, axis=2, mode='reflect')
530
- gy = ndimage.sobel(gaussian_img, axis=1, mode='reflect')
531
- gz = ndimage.sobel(gaussian_img, axis=0, mode='reflect')
532
- features[..., feature_idx] = np.sqrt(gx**2 + gy**2 + gz**2)
533
- feature_idx += 1
534
-
535
- # Laplacian of Gaussian
536
- for sigma in self.sigmas:
537
- gaussian_img = gaussian_cache[sigma]
538
- features[..., feature_idx] = ndimage.laplace(gaussian_img, mode='reflect')
539
- feature_idx += 1
540
-
541
- # Hessian-based features (much faster than full eigenvalue computation)
542
- for sigma in self.sigmas:
543
- gaussian_img = gaussian_cache[sigma]
544
-
545
- # Compute second derivatives
546
- hxx = ndimage.gaussian_filter(gaussian_img, sigma=0, order=[0, 0, 2], mode='reflect')
547
- hyy = ndimage.gaussian_filter(gaussian_img, sigma=0, order=[0, 2, 0], mode='reflect')
548
- hzz = ndimage.gaussian_filter(gaussian_img, sigma=0, order=[2, 0, 0], mode='reflect')
549
- hxy = ndimage.gaussian_filter(gaussian_img, sigma=0, order=[0, 1, 1], mode='reflect')
550
- hxz = ndimage.gaussian_filter(gaussian_img, sigma=0, order=[1, 0, 1], mode='reflect')
551
- hyz = ndimage.gaussian_filter(gaussian_img, sigma=0, order=[1, 1, 0], mode='reflect')
552
-
553
- # Hessian determinant (captures overall curvature)
554
- determinant = (hxx * (hyy * hzz - hyz**2) -
555
- hxy * (hxy * hzz - hxz * hyz) +
556
- hxz * (hxy * hyz - hyy * hxz))
557
- features[..., feature_idx] = determinant
558
- feature_idx += 1
559
-
560
- # Hessian trace (sum of eigenvalues)
561
- trace = hxx + hyy + hzz
562
- features[..., feature_idx] = trace
563
- feature_idx += 1
564
-
565
- # Frobenius norm (overall curvature magnitude)
566
- frobenius_norm = np.sqrt(hxx**2 + hyy**2 + hzz**2 + 2*(hxy**2 + hxz**2 + hyz**2))
567
- features[..., feature_idx] = frobenius_norm
568
- feature_idx += 1
569
-
570
- """
571
- # Normalize features: zero-mean, unit variance per feature band
572
- # Compute mean and std across spatial dimensions (0,1,2), keeping feature dimension
573
- feature_means = np.mean(features, axis=(0, 1, 2), keepdims=True)
574
- feature_stds = np.std(features, axis=(0, 1, 2), keepdims=True)
575
-
576
- # Avoid division by zero for constant features
577
- feature_stds = np.where(feature_stds == 0, 1, feature_stds)
578
-
579
- # Normalize in-place for memory efficiency
580
- features = (features - feature_means) / feature_stds
581
- """
582
- # Normalize only morphological features, keep intensity features raw
583
- intensity_features = features[..., :num_basic_features] # original + gaussians + DoGs
584
- morphology_features = features[..., num_basic_features:] # gradients + laplacians + eigenvalues
585
-
586
- # Normalize only morphological features
587
- morph_means = np.mean(morphology_features, axis=(0,1,2), keepdims=True)
588
- morph_stds = np.std(morphology_features, axis=(0,1,2), keepdims=True)
589
- morph_stds = np.where(morph_stds == 0, 1, morph_stds)
590
- morphology_features = (morphology_features - morph_means) / morph_stds
591
-
592
- # Recombine
593
- features = np.concatenate([intensity_features, morphology_features], axis=-1)
594
-
595
- return features
596
-
597
-
598
486
  def compute_feature_maps_cpu(self, image_3d=None): #lil
599
487
  """Optimized version that caches Gaussian filters to avoid redundant computation"""
600
488
  if image_3d is None:
601
489
  image_3d = self.image_3d
602
490
 
603
- if image_3d.ndim == 4 and image_3d.shape[-1] == 3:
491
+ if image_3d.ndim == 4 and (image_3d.shape[-1] == 3 or image_3d.shape[-1] == 4):
604
492
  # RGB case - process each channel
605
493
  features_per_channel = []
606
- for channel in range(3):
494
+ for channel in range(image_3d.shape[-1]):
607
495
  channel_features = self.compute_feature_maps_cpu(image_3d[..., channel])
608
496
  features_per_channel.append(channel_features)
609
497
 
@@ -1420,7 +1308,10 @@ class InteractiveSegmenter:
1420
1308
  chunk_size = max(16, min(chunk_size, min(self.image_3d.shape) // 2))
1421
1309
  chunk_size = ((chunk_size + 7) // 16) * 16
1422
1310
 
1423
- depth, height, width = self.image_3d.shape
1311
+ try:
1312
+ depth, height, width = self.image_3d.shape
1313
+ except:
1314
+ depth, height, width, rgb = self.image_3d.shape
1424
1315
 
1425
1316
  # Calculate chunk grid dimensions
1426
1317
  z_chunks = (depth + chunk_size - 1) // chunk_size
@@ -320,10 +320,10 @@ class InteractiveSegmenter:
320
320
  if image_3d is None:
321
321
  image_3d = self.image_3d # Assuming this is already a cupy array
322
322
 
323
- if image_3d.ndim == 4 and image_3d.shape[-1] == 3:
323
+ if image_3d.ndim == 4 and (image_3d.shape[-1] == 3 or image_3d.shape[-1] == 4):
324
324
  # RGB case - process each channel
325
325
  features_per_channel = []
326
- for channel in range(3):
326
+ for channel in range(image_3d.shape[-1]):
327
327
  channel_features = self.compute_feature_maps_gpu(image_3d[..., channel])
328
328
  features_per_channel.append(channel_features)
329
329
 
@@ -376,10 +376,10 @@ class InteractiveSegmenter:
376
376
  if image_3d is None:
377
377
  image_3d = self.image_3d # Assuming this is already a cupy array
378
378
 
379
- if image_3d.ndim == 4 and image_3d.shape[-1] == 3:
379
+ if image_3d.ndim == 4 and (image_3d.shape[-1] == 3 or image_3d.shape[-1] == 4):
380
380
  # RGB case - process each channel
381
381
  features_per_channel = []
382
- for channel in range(3):
382
+ for channel in range(image_3d.shape[-1]):
383
383
  channel_features = self.compute_deep_feature_maps_gpu(image_3d[..., channel])
384
384
  features_per_channel.append(channel_features)
385
385
 
@@ -507,10 +507,10 @@ class InteractiveSegmenter:
507
507
  if image_2d is None:
508
508
  image_2d = cp.asarray(self.image_3d[z, :, :])
509
509
 
510
- if image_2d.ndim == 3 and image_2d.shape[-1] == 3:
510
+ if image_2d.ndim == 3 and (image_2d.shape[-1] == 3 or image_2d.shape[-1] == 4):
511
511
  # RGB case - process each channel
512
512
  features_per_channel = []
513
- for channel in range(3):
513
+ for channel in range(image_2d.shape[-1]):
514
514
  channel_features = self.compute_feature_maps_gpu_2d(image_2d = image_2d[..., channel])
515
515
  features_per_channel.append(channel_features)
516
516
 
@@ -567,10 +567,10 @@ class InteractiveSegmenter:
567
567
  if image_2d is None:
568
568
  image_2d = cp.asarray(self.image_3d[z, :, :])
569
569
 
570
- if image_2d.ndim == 3 and image_2d.shape[-1] == 3:
570
+ if image_2d.ndim == 3 and (image_2d.shape[-1] == 3 or image_2d.shape[-1] == 4):
571
571
  # RGB case - process each channel
572
572
  features_per_channel = []
573
- for channel in range(3):
573
+ for channel in range(image_2d.shape[-1]):
574
574
  channel_features = self.compute_deep_feature_maps_gpu_2d(image_2d = image_2d[..., channel])
575
575
  features_per_channel.append(channel_features)
576
576
 
@@ -1082,7 +1082,10 @@ class InteractiveSegmenter:
1082
1082
  chunk_size = max(16, min(chunk_size, min(self.image_3d.shape) // 2))
1083
1083
  chunk_size = ((chunk_size + 7) // 16) * 16
1084
1084
 
1085
- depth, height, width = self.image_3d.shape
1085
+ try:
1086
+ depth, height, width = self.image_3d.shape
1087
+ except:
1088
+ depth, height, width, rgb = self.image_3d.shape
1086
1089
 
1087
1090
  # Calculate chunk grid dimensions
1088
1091
  z_chunks = (depth + chunk_size - 1) // chunk_size
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nettracer3d
3
- Version: 0.9.6
3
+ Version: 0.9.8
4
4
  Summary: Scripts for intializing and analyzing networks from segmentations of three dimensional images.
5
5
  Author-email: Liam McLaughlin <liamm@wustl.edu>
6
6
  Project-URL: Documentation, https://nettracer3d.readthedocs.io/en/latest/
@@ -110,10 +110,6 @@ McLaughlin, L., Zhang, B., Sharma, S. et al. Three dimensional multiscalar neuro
110
110
 
111
111
  NetTracer3D was developed by Liam McLaughlin while working under Dr. Sanjay Jain at Washington University School of Medicine.
112
112
 
113
- -- Version 0.9.6 Updates --
113
+ -- Version 0.9.8 Updates --
114
114
 
115
- * Moved some file menu options around.
116
- * The 'merge node id' option now offers interactive support for assisted thresholding for any new identity channels the user is trying to merge with.
117
- * Bug Fixes
118
- * The 'merge nodes' option now can provide centroids prior to the merge, since oftentimes objects end up on top of each other.
119
- * A few other minor adjustments.
115
+ * Some minor bug fixes
@@ -6,20 +6,20 @@ nettracer3d/modularity.py,sha256=pborVcDBvICB2-g8lNoSVZbIReIBlfeBmjFbPYmtq7Y,224
6
6
  nettracer3d/morphology.py,sha256=jyDjYzrZ4LvI5jOyw8DLsxmo-i5lpqHsejYpW7Tq7Mo,19786
7
7
  nettracer3d/neighborhoods.py,sha256=iIaHU1COIdRtzRpAuIQKfLGLNKYFK3dL8Vb_EeJIlEA,46459
8
8
  nettracer3d/nettracer.py,sha256=d9Mhz-pHox5OfGGUSTrkTBJzCWCrbQvClTu2ANt-jUE,267943
9
- nettracer3d/nettracer_gui.py,sha256=ZJzW3-P3m18LPhoIkCqLVTqsRb8nRFzzwYmQ-vfIs5Y,628407
9
+ nettracer3d/nettracer_gui.py,sha256=2OuTeJ1xnarlZAYjW9R4hvBA4ZiW_Ce0NtfTamqpbWU,628156
10
10
  nettracer3d/network_analysis.py,sha256=kBzsVaq4dZkMe0k-VGvQIUvM-tK0ZZ8bvb-wtsugZRQ,46150
11
11
  nettracer3d/network_draw.py,sha256=F7fw6Pcf4qWOhdKwLmhwqWdschbDlHzwCVolQC9imeU,14117
12
12
  nettracer3d/node_draw.py,sha256=kZcR1PekLg0riioNeGcALIXQyZ5PtHA_9MT6z7Zovdk,10401
13
13
  nettracer3d/painting.py,sha256=K_dwngivw80r-Yyg4btKMsWGn566ZE9PnrQl986uxJE,23497
14
14
  nettracer3d/proximity.py,sha256=WaHPwE6ypeInFO_LnMT0zaVE53jX3TJx6h7nmtYtr8U,41824
15
15
  nettracer3d/run.py,sha256=xYeaAc8FCx8MuzTGyL3NR3mK7WZzffAYAH23bNRZYO4,127
16
- nettracer3d/segmenter.py,sha256=-Llkhp3TlAIBXZNhcfMFQRdg0vec1xtlOm0c4_bSU9U,75761
17
- nettracer3d/segmenter_GPU.py,sha256=optCZ_zLIfe99rgqmyKWUZlWW5TF5jEC_C3keu1m7VQ,77771
16
+ nettracer3d/segmenter.py,sha256=aOO3PwZ2UeizEIFX7N8midwzTzbEDzgM2jQ7WTdbrUg,70671
17
+ nettracer3d/segmenter_GPU.py,sha256=OUekQljLKPiC4d4hNZmqrRa9HSVQ6HcCnILiAfHE5Hg,78051
18
18
  nettracer3d/simple_network.py,sha256=dkG4jpc4zzdeuoaQobgGfL3PNo6N8dGKQ5hEEubFIvA,9947
19
19
  nettracer3d/smart_dilate.py,sha256=TvRUh6B4q4zIdCO1BWH-xgTdND5OUNmo99eyxG9oIAU,27145
20
- nettracer3d-0.9.6.dist-info/licenses/LICENSE,sha256=jnNT-yBeIAKAHpYthPvLeqCzJ6nSurgnKmloVnfsjCI,764
21
- nettracer3d-0.9.6.dist-info/METADATA,sha256=MHM0yBkUeOtSk_cdnD6-5KEmgS7oiQaLBBDGg4ZMbE8,7343
22
- nettracer3d-0.9.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
- nettracer3d-0.9.6.dist-info/entry_points.txt,sha256=Nx1rr_0QhJXDBHAQg2vcqCzLMKBzSHfwy3xwGkueVyc,53
24
- nettracer3d-0.9.6.dist-info/top_level.txt,sha256=zsYy9rZwirfCEOubolhee4TyzqBAL5gSUeFMzhFTX8c,12
25
- nettracer3d-0.9.6.dist-info/RECORD,,
20
+ nettracer3d-0.9.8.dist-info/licenses/LICENSE,sha256=jnNT-yBeIAKAHpYthPvLeqCzJ6nSurgnKmloVnfsjCI,764
21
+ nettracer3d-0.9.8.dist-info/METADATA,sha256=h-H4X4k6Yf1n9ZFgVbyYBLmXQDvcpgQncQt5QZfBh6k,6997
22
+ nettracer3d-0.9.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ nettracer3d-0.9.8.dist-info/entry_points.txt,sha256=Nx1rr_0QhJXDBHAQg2vcqCzLMKBzSHfwy3xwGkueVyc,53
24
+ nettracer3d-0.9.8.dist-info/top_level.txt,sha256=zsYy9rZwirfCEOubolhee4TyzqBAL5gSUeFMzhFTX8c,12
25
+ nettracer3d-0.9.8.dist-info/RECORD,,