2424from scipy import ndimage
2525
2626
27- def find_decision_points (seg : np .ndarray ,
28- voxel_size : Sequence [float ],
29- max_distance : Optional [float ] = None ,
30- subvol_box : Optional [bounding_box .BoundingBox ] = None
31- ) -> dict [tuple [int , int ], tuple [float , np .ndarray ]]:
27+ def find_decision_points (
28+ seg : np .ndarray ,
29+ voxel_size : Sequence [float ],
30+ max_distance : Optional [float ] = None ,
31+ subvol_box : Optional [bounding_box .BoundingBox ] = None ,
32+ optimize_sparse : bool = False ,
33+ sparse_noise_threshold : int = 0 ,
34+ ) -> dict [tuple [int , int ], tuple [float , np .ndarray ]]:
3235 """Identifies decision points in a segmentation subvolume.
3336
3437 Args:
@@ -39,12 +42,34 @@ def find_decision_points(seg: np.ndarray,
3942 subvol_box: selector for a subvolume within `seg` within which
4043 to search for decision points; the whole subvolume is always used
4144 to compute the distance transform
45+ optimize_sparse: if True, first counts the number of segments in `seg`
46+ and returns early if there are fewer than 2.
47+ sparse_noise_threshold: if > 0 and `optimize_sparse` is True, ignores
48+ components with voxel counts <= this threshold when counting segments.
4249
4350 Returns:
4451 dict from segment ID pairs to tuples of:
4552 approximate physical distance from the segment to the decision point
4653 (x, y, z) decision point
4754 """
55+ if optimize_sparse :
56+ # Use pandas to quickly get the unique labels and their counts (excluding 0)
57+ counts = pd .Series (seg .ravel ()).value_counts (sort = False )
58+ if 0 in counts :
59+ counts = counts .drop (0 )
60+
61+ if sparse_noise_threshold > 0 :
62+ small_segs = counts [counts <= sparse_noise_threshold ].index .to_numpy ()
63+ if len (small_segs ) > 0 :
64+ # Zero out small segments and update counts
65+ seg [np .isin (seg , small_segs )] = 0
66+ counts = counts .drop (small_segs )
67+
68+ if len (counts ) <= 1 :
69+ # If there are 0 or 1 unique segments (excluding background),
70+ # they cannot possibly touch another segment.
71+ return {}
72+
4873 # EDT is the Euclidean Distance Transform, specifying how far voxels added
4974 # in 'expanded_seg' are from the seeds in 'seg'.
5075 expanded_seg , edt = labels .watershed_expand (seg , voxel_size , max_distance )
0 commit comments