Class AbstractGWDTTracer<T extends net.imglib2.type.numeric.RealType<T>>

java.lang.Object
sc.fiji.snt.tracing.auto.AbstractAutoTracer
sc.fiji.snt.tracing.auto.AbstractGWDTTracer<T>
Type Parameters:
T - pixel type
All Implemented Interfaces:
AutoTracer
Direct Known Subclasses:
DiskBackedGWDTTracer, GWDTTracer, SparseGWDTTracer

public abstract class AbstractGWDTTracer<T extends net.imglib2.type.numeric.RealType<T>> extends AbstractAutoTracer
Abstract base class for GWDT-based tracers: APP2-style neuron tracer using Gray-Weighted Distance Transform and Fast Marching. The tree is built directly on the grayscale image using intensity-weighted paths.

Subclasses specify storage backend via createStorageBackend().

This implementation follows the APP2 algorithm:
  1. GWDT - Gray-weighted distance transform on grayscale (no binarization)
  2. Fast Marching - Build initial tree from seed using geodesic distance on GWDT
  3. Hierarchical Pruning - Long-segment-first with intensity-weighted coverage
Author:
Tiago Ferreira
See Also:
  • Field Details

    • FAR

      public static final byte FAR
      Fast Marching state: voxel has not yet been reached.
      See Also:
    • TRIAL

      public static final byte TRIAL
      Fast Marching state: voxel is in the narrow-band trial set.
      See Also:
    • ALIVE

      public static final byte ALIVE
      Fast Marching state: voxel distance has been finalized.
      See Also:
    • source

      protected final net.imglib2.RandomAccessibleInterval<T extends net.imglib2.type.numeric.RealType<T>> source
    • spacing

      protected final double[] spacing
    • dims

      protected final long[] dims
    • minBounds

      protected final long[] minBounds
    • maxBounds

      protected final long[] maxBounds
    • backgroundThreshold

      protected double backgroundThreshold
    • minBranchIntensityLength

      protected double minBranchIntensityLength
    • srRatio

      protected double srRatio
    • sphereOverlapThreshold

      protected double sphereOverlapThreshold
    • leafPruneOverlap

      protected double leafPruneOverlap
    • leafPruneEnabled

      protected boolean leafPruneEnabled
    • jointLeafPruneEnabled

      protected boolean jointLeafPruneEnabled
    • smoothEnabled

      protected boolean smoothEnabled
    • smoothWindowSize

      protected int smoothWindowSize
    • resampleEnabled

      protected boolean resampleEnabled
    • resampleStep

      protected double resampleStep
    • cnnType

      protected int cnnType
    • zigzagRemovalEnabled

      protected boolean zigzagRemovalEnabled
    • overshootRemovalEnabled

      protected boolean overshootRemovalEnabled
    • branchTuneMaxAngle

      protected double branchTuneMaxAngle
    • parallelBranchPruneEnabled

      protected boolean parallelBranchPruneEnabled
    • scoreMapEnabled

      protected boolean scoreMapEnabled
    • scoreMap

      protected net.imglib2.RandomAccessibleInterval<? extends net.imglib2.type.numeric.RealType<?>> scoreMap
    • scoreMapFilterType

      protected SNT.FilterType scoreMapFilterType
    • scoreMapScales

      protected double[] scoreMapScales
    • scoreMapPruneThreshold

      protected double scoreMapPruneThreshold
    • maxIntensity

      protected double maxIntensity
    • minIntensity

      protected double minIntensity
    • seedVoxel

      protected long[] seedVoxel
    • storage

      protected StorageBackend storage
  • Constructor Details

    • AbstractGWDTTracer

      public AbstractGWDTTracer(net.imglib2.RandomAccessibleInterval<T> source, double[] spacing)
      Creates a new GWDTTracer.
      Parameters:
      source - the grayscale image to trace
      spacing - voxel dimensions [x, y, z] in physical units
  • Method Details

    • createStorageBackend

      protected abstract StorageBackend createStorageBackend()
      Create the storage backend for this tracer. Subclasses override to specify array, sparse, or disk-backed storage.
    • getSpacing

      protected double[] getSpacing()
      Description copied from class: AbstractAutoTracer
      Gets the voxel spacing used by this tracer.
      Specified by:
      getSpacing in class AbstractAutoTracer
      Returns:
      array of [x, y, z] spacing values
    • getDimensions

      protected long[] getDimensions()
      Description copied from class: AbstractAutoTracer
      Gets the image dimensions.
      Specified by:
      getDimensions in class AbstractAutoTracer
      Returns:
      array of dimension sizes
    • createIsotropicSpacing

      protected static double[] createIsotropicSpacing(int nDims)
    • getSpacing

      protected static double[] getSpacing(ij.ImagePlus imp, int nDims)
    • setBackgroundThreshold

      public void setBackgroundThreshold(double threshold)
      Sets the background threshold. Pixels at or below this value are considered background. If negative (default), threshold is auto-computed as the image mean.
    • setSrRatio

      public void setSrRatio(double ratio)
      Sets the SR (Signal-to-Redundant) ratio threshold used in hierarchical pruning. Default: 3/9 = 0.333 Segments with signal/redundant >= this ratio are kept.
    • setMinBranchIntensityLength

      public void setMinBranchIntensityLength(double threshold)
      Sets the minimum branch intensity-length threshold. This is the sum of normalized intensities (intensity / maxIntensity) along a branch segment. Branches whose cumulative score falls below this value are pruned. A value of 5.0 (default) means a branch needs the equivalent of 5 voxels at maximum intensity, or more voxels at lower intensity.

      Note: despite the name of the APP2 parameter (length_thresh), this is NOT a Euclidean distance: it is an intensity-weighted length that favors bright branches.

      Parameters:
      threshold - minimum intensity-length score (default: 5.0)
    • setMinSegmentLengthVoxels

      @Deprecated public void setMinSegmentLengthVoxels(double lengthInVoxels)
      Deprecated.
    • setMinSegmentLength

      @Deprecated public void setMinSegmentLength(double lengthInPhysicalUnits)
      Deprecated.
      Use setMinBranchIntensityLength(double) instead. Note: the physical-to-voxel conversion is not meaningful for this parameter since it is an intensity sum, not a distance.
    • setSphereOverlapThreshold

      public void setSphereOverlapThreshold(double threshold)
      Sets the sphere overlap threshold for detecting redundant nodes during hierarchical pruning. When a node's sphere has more than this fraction covered by claimed nodes, it's considered redundant. Default: 0.4. Lower = more aggressive pruning.
    • setLeafPruneOverlap

      public void setLeafPruneOverlap(double threshold)
      Sets the leaf pruning overlap threshold. Leaves with more than this fraction overlapping their parent are pruned. Values ≤ 0 disable leaf pruning entirely. Default: 0.9
      Parameters:
      threshold - overlap fraction in (0, 1], or ≤ 0 to disable
    • setJointLeafPruneEnabled

      public void setJointLeafPruneEnabled(boolean enabled)
      Enables or disables joint leaf pruning independently of leaf pruning. Joint leaf pruning removes leaves whose sphere is 90% covered by other nodes' spheres. See jointLeafPruning(sc.fiji.snt.analysis.graph.DirectedWeightedGraph) for known cascading issue. Default: true
    • setSmoothWindowSize

      public void setSmoothWindowSize(int windowSize)
      Sets the smoothing window size (must be odd and ≥ 3). Values below 3 disable smoothing entirely. Default: 5
      Parameters:
      windowSize - the moving-average window, or any value < 3 to disable
    • setResampleStep

      public void setResampleStep(double step)
      Sets the resampling step size in voxels. Points closer than this distance will be merged. Values ≤ 0 disable resampling entirely. Default: 2.0
      Parameters:
      step - step size in voxels, or ≤ 0 to disable
    • setConnectivityType

      public void setConnectivityType(int type)
      Sets the connectivity type for Fast Marching.

      3D images:

      • 1 = 6-connectivity (face neighbors)
      • 2 = 18-connectivity (face + edge neighbors) - default
      • 3 = 26-connectivity (face + edge + corner neighbors)
      2D images:
      • 1 = 4-connectivity (edge neighbors)
      • 2, 3 = 8-connectivity (edge + corner neighbors)
      Parameters:
      type - connectivity type (1, 2, or 3)
    • setAllowVoxelGap

      public void setAllowVoxelGap(boolean allow)
      Sets whether to allow bridging single-voxel intensity gaps during fast marching.

      When enabled, the wavefront can cross a single dark voxel to connect broken neurites. The crossing is only allowed if the current voxel is above threshold (i.e., bright → dark → bright, but not dark → dark).

      This is useful for images with fragmented signals or small imaging artifacts, but may falsely connect separate structures. For bridging larger, multi-voxel gaps between disconnected tree components, see setMaxGapVoxels(int) or setTipExtensionDistance(double).

      Parameters:
      allow - true to allow crossing single dark voxels (default: false)
      See Also:
    • isAllowVoxelGap

      public boolean isAllowVoxelGap()
      Returns whether gap bridging is enabled (single- or multi-voxel).
      Returns:
      true if dark voxels can be crossed during tracing
      See Also:
    • setMaxGapVoxels

      public void setMaxGapVoxels(int maxVoxels)
      Sets the maximum number of consecutive dark voxels that Fast Marching can bridge during tracing. When the FM wavefront encounters a dark neighbor, it probes ahead along the same direction for up to this many steps looking for bright signal. If found, the far-side bright voxel is added to the FM heap with accumulated gap cost, and FM continues expanding from there normally (including all branches).

      Set to 0 to disable gap bridging entirely, 1 for the legacy single-voxel bridge, or higher values (e.g. 50) for beaded or fragmented signal. The gap cost assumes synthetic intensity of threshold + 1 for each dark voxel crossed, keeping the cost model consistent with normal FM traversal while penalizing gap traversal.

      Parameters:
      maxVoxels - maximum gap width in voxels (default: 3)
      See Also:
    • getMaxGapVoxels

      public int getMaxGapVoxels()
      Returns the maximum number of consecutive dark voxels FM can bridge.
      Returns:
      maximum gap width in voxels; 0 if disabled
      See Also:
    • setZigzagRemovalEnabled

      public void setZigzagRemovalEnabled(boolean enabled)
      Enables or disables zigzag removal. When enabled, consecutive nodes that form back-and-forth direction reversals (both with angles ≥ 90°) are collapsed. Default: true
      Parameters:
      enabled - true to enable zigzag removal
    • setOvershootRemovalEnabled

      public void setOvershootRemovalEnabled(boolean enabled)
      Enables or disables overshoot removal. When enabled, continuation nodes that reverse direction adjacent to a branch point are collapsed. This removes short stubs where the tracing overshoots past a bifurcation and doubles back. Default: true
      Parameters:
      enabled - true to enable overshoot removal
    • setBranchTuneMaxAngle

      public void setBranchTuneMaxAngle(double maxAngleDeg)
      Sets the maximum angle (in degrees) for the branch tuning turn test. During branch tuning, a node adjacent to a branch point is re-parented to a closer neighbor only if the original connection forms an angle ≥ this threshold (i.e., a direction reversal). Lower values make tuning more aggressive (more rewiring); higher values make it more conservative.

      Set to Double.NaN or a negative value to disable branch tuning entirely. Default: 90.0 (equivalent to NeuTube's dot-product ≤ 0 test).

      Parameters:
      maxAngleDeg - maximum angle in degrees, or NaN/negative to disable
    • setParallelBranchPruneEnabled

      public void setParallelBranchPruneEnabled(boolean enabled)
      Enables or disables parallel branch pruning. When enabled, sibling branches that run alongside each other (their nodes stay within a radius-dependent proximity threshold) are detected, and the shorter sibling is removed. This eliminates redundant paths that trace the same neurite on opposite sides of its centerline, a common artifact in FM-based tracers operating on thick or bright structures.

      Default: true.

      Parameters:
      enabled - whether to prune parallel sibling branches
    • isParallelBranchPruneEnabled

      public boolean isParallelBranchPruneEnabled()
      Returns whether parallel branch pruning is enabled.
      Returns:
      true if parallel branch pruning is active
    • setPathFittingEnabled

      public void setPathFittingEnabled(boolean enabled)
      Enables or disables post-hoc path fitting using PathFitter. When enabled, after all graph-level processing is complete and Trees have been assembled, each path is refined using cross-sectional intensity fitting (PathFitter.RADII_AND_MIDPOINTS). This snaps node positions to the signal centerline and computes accurate radii from the local intensity profile, replacing the initial estimates from the autotracer.

      Default: false (disabled).

      Parameters:
      enabled - whether to apply PathFitter refinement to output paths
      See Also:
    • isPathFittingEnabled

      public boolean isPathFittingEnabled()
      Returns whether post-hoc path fitting is enabled.
      Returns:
      true if PathFitter refinement is active
    • setTipExtensionDistance

      public void setTipExtensionDistance(double distance)
      Sets the maximum distance (in voxels) for A*-based tip extension. When set to a positive value, leaf tips that end at gap boundaries (where the signal drops below threshold) are extended by scanning for bright signal in a forward cone and running bidirectional A* to bridge the gap. This complements FM gap bridging (setMaxGapVoxels(int)), which handles small gaps during wavefront expansion: tip extension targets larger contiguous gaps that exceed maxGapVoxels.

      Set to 0 (the default) to disable. Typical values are 20–50 voxels. Note: this is an experimental feature. In noisy images, large values may produce spurious bridges.

      Parameters:
      distance - maximum gap distance in voxels (default: 0 = disabled)
      See Also:
    • getTipExtensionDistance

      public double getTipExtensionDistance()
      Returns the maximum distance (in voxels) for A*-based tip extension.
      Returns:
      maximum tip extension distance; 0 if disabled
      See Also:
    • setCaliperFraction

      public void setCaliperFraction(double fraction)
      Sets the fraction of the nearest-neighbor soma distance used as the caliper radius for Fast Marching spread in multi-soma tracing. For each soma, the caliper radius is fraction × nearest_neighbor_distance, limiting how far the wavefront can propagate. This prevents one cell's tracing from invading a neighbor's territory.

      Smaller fractions are more conservative (less cross-cell contamination) but may truncate long processes that extend past the midpoint between cells. Larger fractions allow the tracer to follow distal processes further, relying on the exclusion mask (setTracedRegionBuffer(int)) to prevent overlap.

      Set to a negative value (e.g., -1) to disable the caliper entirely, allowing unrestricted Fast Marching spread. In this mode, territory boundaries are enforced solely by the exclusion mask. Default: 0.5.

      Parameters:
      fraction - fraction of nearest-neighbor distance (default: 0.5), or negative to disable the caliper
      See Also:
    • getCaliperFraction

      public double getCaliperFraction()
      Returns the caliper fraction used for limiting Fast Marching spread in multi-soma tracing, or a negative value if the caliper is disabled.
      Returns:
      caliper fraction, or negative if disabled
      See Also:
    • setTracedRegionBuffer

      public void setTracedRegionBuffer(int buffer)
      Sets the buffer (in voxels) applied around traced regions between passes in traceMultiSoma(List). After tracing from one soma, the traced voxels are expanded by this buffer before being excluded from subsequent Fast Marching runs. Larger values create wider exclusion zones, preventing re-tracing of neurites already claimed by a previous soma.

      Set to 0 to disable buffering (only exact traced voxels are excluded). Default: 5.

      Parameters:
      buffer - buffer size in voxels (non-negative)
    • getTracedRegionBuffer

      public int getTracedRegionBuffer()
      Returns the buffer size (in voxels) applied around traced regions between multi-soma passes.
      Returns:
      buffer size in voxels
      See Also:
    • setMinSomaDistance

      public void setMinSomaDistance(double distance)
      Sets the minimum distance (in voxels) between soma centers for multi-soma tracing. This value controls two filtering stages:
      1. Non-maximum suppression in SomaUtils.detectAllSomas(net.imglib2.RandomAccessibleInterval<? extends net.imglib2.type.numeric.RealType<?>>, double, double): callers should pass this value as the minSomaDistance parameter.
      2. Post-hoc consolidation in traceMultiSoma(java.util.List<sc.fiji.snt.tracing.auto.SomaUtils.SomaResult>): any somas closer than this distance are merged before tracing.

      Set this to the minimum known distance between real soma centers in the image. If ≤ 0 (default), both filtering stages are disabled.

      Parameters:
      distance - minimum inter-soma distance in voxels
    • getMinSomaDistance

      public double getMinSomaDistance()
      Returns the minimum inter-soma distance (in voxels).
      Returns:
      minimum distance, or 0 if not set
      See Also:
    • setNSomas

      public void setNSomas(int nSomas)
      Sets the expected number of somas in the image for multi-soma tracing. When set to a positive value, traceMultiSoma(List) selects the top-N somas ranked by EDT thickness via SomaUtils.selectTopSomasByThickness(java.util.List<sc.fiji.snt.tracing.auto.SomaUtils.SomaResult>, net.imglib2.RandomAccessibleInterval<T>, int).

      Experimental: The EDT-based ranking relies on a global binarization threshold (currently the Minimum auto-threshold) to compute the distance transform. For images with large connected foreground regions, the EDT may measure distance-to-nearest-dark-pixel rather than actual soma body half-width, causing false detections deep inside bright regions to rank higher than real somas. In practice, setMinSomaDistance(double) is more reliable and should be preferred when the approximate inter-soma spacing is known.

      This parameter is orthogonal to setMinSomaDistance(double):

      • nSomas > 0 only: top-N selection by EDT thickness
      • minSomaDistance > 0 only: NMS during detection, consolidation during tracing
      • Both set: minSomaDistance drives NMS/consolidation upstream, nSomas acts as a downstream cap
      • Neither set: auto-estimation via thickness filtering + gap analysis (best-effort, also experimental)

      Set to -1 to trigger auto-estimation (default). Set to 0 to disable the count-based filter entirely.

      Parameters:
      nSomas - expected number of somas (> 0), -1 for auto, or 0 to disable
      See Also:
    • getNSomas

      public int getNSomas()
      Returns the expected number of somas.
      Returns:
      expected count, -1 if auto-estimating, or 0 if disabled
      See Also:
    • setAutoFilter

      public void setAutoFilter(boolean enabled)
      Enables or disables automatic soma filtering in traceMultiSoma(List). When enabled (the default), the pipeline applies EDT-based thickness filtering, count-based selection, gap analysis, and/or NMS consolidation depending on the values of setNSomas(int) and setMinSomaDistance(double).

      Set to false when providing pre-curated soma lists, e.g.,somas detected from user-provided ROI seeds via SomaUtils.detectSomasAt(net.imglib2.RandomAccessibleInterval<? extends net.imglib2.type.numeric.RealType<?>>, java.util.List<long[]>). In that case the input list is authoritative and should not be reduced by heuristic filters. When disabled, the only processing applied is NMS consolidation if minSomaDistance > 0 (which the caller explicitly requested).

      Example usage with user-provided seeds:

      
       List<SomaUtils.SomaResult> somas = SomaUtils.detectSomasAt(imp, rois);
       tracer.setAutoFilter(false);   // trust user seeds
       tracer.setNSomas(0);           // no count-based cap
       List<Tree> trees = tracer.traceMultiSoma(somas);
       
      Parameters:
      enabled - whether to enable automatic soma filtering (default: true)
      See Also:
    • isAutoFilter

      public boolean isAutoFilter()
      Returns whether automatic soma filtering is enabled.
      Returns:
      true if auto-filtering is active (the default)
      See Also:
    • setScoreMapEnabled

      public void setScoreMapEnabled(boolean enabled)
      Enables or disables per-node score computation using a vesselness or probability map. When enabled, node scores are stored in PointInImage.v and can influence pruning decisions. The score map is also available to ComponentReconnector for bridge validation.

      If an external score map has been set via setScoreMap(net.imglib2.RandomAccessibleInterval<? extends net.imglib2.type.numeric.RealType<?>>), it is used directly. Otherwise, a score map is computed internally using the filter specified by setScoreMapFilterType(sc.fiji.snt.SNT.FilterType). Default: false.

      Parameters:
      enabled - whether to enable score-based node evaluation
      See Also:
    • setScoreMap

      public void setScoreMap(net.imglib2.RandomAccessibleInterval<? extends net.imglib2.type.numeric.RealType<?>> map)
      Sets an external score/probability map to use for per-node scoring.

      This can be any RandomAccessibleInterval whose values represent structure confidence at each voxel, e.g., a deep-learning prediction, a pre-computed vesselness image, or any other probability map. The RAI must have the same spatial dimensions as the source image.

      Setting this automatically enables score-based evaluation (equivalent to calling setScoreMapEnabled(true)). Set to null to revert to internal filter computation.

      Parameters:
      map - the score/probability map, or null to use internal computation
    • getScoreMap

      public net.imglib2.RandomAccessibleInterval<? extends net.imglib2.type.numeric.RealType<?>> getScoreMap()
      Returns the current score map, whether externally provided or internally computed. May be null if scoring has not yet been performed or is disabled.
      Returns:
      the score map RAI, or null
    • setScoreMapFilterType

      public void setScoreMapFilterType(SNT.FilterType type)
      Sets the filter type used to compute the score map internally when no external map is provided. Only SNT.FilterType.TUBENESS and SNT.FilterType.FRANGI are supported. Default: TUBENESS.
      Parameters:
      type - the filter type
      Throws:
      IllegalArgumentException - if type is not TUBENESS or FRANGI
    • setScoreMapScales

      public void setScoreMapScales(double[] scales)
      Sets the scales (in physical units) for the internal vesselness filter. Set to null to auto-derive scales from the radius distribution computed by recalculateRadiiFromImage(sc.fiji.snt.analysis.graph.DirectedWeightedGraph, double). Default: null (auto).
      Parameters:
      scales - array of scales in physical units, or null for auto
    • setScoreMapPruneThreshold

      public void setScoreMapPruneThreshold(double threshold)
      Sets the minimum score threshold for score-aware pruning. Nodes with scores below this value are considered unreliable. Set to 0 to use any positive score as the acceptance criterion. Default: 0.
      Parameters:
      threshold - minimum acceptable score
    • setSeed

      public void setSeed(long[] voxelCoords)
      Sets the seed point (soma location) in voxel coordinates. For 2D images, only x and y are used (z is ignored if provided).
    • setSeedPhysical

      public void setSeedPhysical(double[] physicalCoords)
      Sets the seed point in physical coordinates. For 2D images, only x and y are used (z is ignored if provided).
    • honoredSeedRoles

      public EnumSet<AutoTracer.SeedRole> honoredSeedRoles()
      GWDT tracers consume AutoTracer.SeedRole.ROOT (the Fast-Marching source voxel), AutoTracer.SeedRole.TIP (target endpoints reachable from the root via parent pointers), and AutoTracer.SeedRole.WAYPOINT (soft path attractors implemented by biasing the GWDT cost map before Fast Marching). When tips are supplied, the resulting tree is the union of root-to-tip walks. When waypoints are supplied, the GWDT values at and around each waypoint voxel are pulled toward maxGWDT (making those voxels cheap to traverse) so the FM wavefront preferentially routes paths through them; the root-to-waypoint paths are then protected from the pruning passes that would otherwise eliminate them.
      Returns:
      the AutoTracer.SeedRoles this tracer actually honors. Callers (e.g. an "Autotrace from Seeds" wrapper command) can use this to gate UI choices and to error early when the user picks a role the tracer ignores. Default: empty set.
    • setRoots

      public void setRoots(Collection<SeedPoint> seeds)
      Sets the run's root from a collection of seeds. Currently, takes the first seed and delegates to setSeedPhysical(double[]); any additional seeds are ignored. The wrapper command is expected to iterate one tracer run per seed if it wants per-seed trees. Future iterations may handle multi-root expansion in a single run.
      Parameters:
      seeds - candidate roots; null/empty is a silent no-op
    • setTips

      public void setTips(Collection<SeedPoint> seeds)
      Configures the run's tips. Stores an internal snapshot; null or empty disables tip-driven extraction (the tracer falls back to the usual full-graph + hierarchical-prune flow).
      Parameters:
      seeds - candidate tips; may be null or empty
    • setWaypoints

      public void setWaypoints(Collection<SeedPoint> seeds)
      Configures the run's waypoints. Stores an internal snapshot; null or empty disables the bias step.
      Parameters:
      seeds - candidate waypoints; may be null or empty
    • setWaypointBiasSource

      public void setWaypointBiasSource(AbstractGWDTTracer.WaypointBiasSource source)
    • setWaypointBiasStrength

      public void setWaypointBiasStrength(double strength)
      Sets the overall bias strength; values are clamped to [0, 1].
    • setWaypointBiasRadiusVoxels

      public void setWaypointBiasRadiusVoxels(double radius)
      Sets the bias sphere radius in voxels; non-positive disables the spherical extent (only the exact waypoint voxel is biased).
    • setWaypointBiasFixedFactor

      public void setWaypointBiasFixedFactor(double factor)
      Sets the fixed bias factor used when source is AbstractGWDTTracer.WaypointBiasSource.FIXED; clamped to [0, 1].
    • traceToGraph

      public DirectedWeightedGraph traceToGraph()
      Description copied from class: AbstractAutoTracer
      Traces the structure and returns a DirectedWeightedGraph.
      Specified by:
      traceToGraph in class AbstractAutoTracer
      Returns:
      the traced graph
    • runFastMarching

      protected void runFastMarching(double threshold, long seedIndex)
      Initializes storage and runs Fast Marching from the given seed. This is the standard entry point used by traceToGraph().
    • addNeighborsToHeap

      protected void addNeighborsToHeap(long[] pos, net.imglib2.RandomAccess<T> srcRA, PriorityQueue<long[]> heap, double threshold)
      Add neighbors to Fast Marching heap. Uses cached arrays to reduce allocations in hot path.
    • smoothCurve

      protected void smoothCurve(DirectedWeightedGraph graph, int windowSize)
      Smooths the final curve using a moving average filter.
      Parameters:
      graph - the graph to smooth
      windowSize - the smoothing window (default 5: 2 neighbors on each side)
    • removeZigzags

      protected void removeZigzags(DirectedWeightedGraph graph)
      Removes zigzag artifacts from the graph. A zigzag is two consecutive continuation nodes that both reverse direction (angle ≥ 90°). The inner node is merged to its parent, collapsing the back-and-forth pattern. The process repeats until no more zigzags are found.

      Adapted from NeuTube's Swc_Tree_Remove_Zigzag.

      Parameters:
      graph - the graph to clean
      See Also:
    • removeOvershoots

      protected void removeOvershoots(DirectedWeightedGraph graph)
      Removes overshoot artifacts from the graph. An overshoot is a continuation node that reverses direction and sits adjacent to a branch point—either its parent is a branch point (and its child is not) or its child is a branch point (and its parent is not). This pattern indicates the tracing overshot past a bifurcation and doubled back.

      Adapted from NeuTube's Swc_Tree_Remove_Overshoot.

      Parameters:
      graph - the graph to clean
      See Also:
    • tuneBranches

      protected void tuneBranches(DirectedWeightedGraph graph, double cosThreshold)
      Tunes branch-point topology by re-parenting nodes adjacent to bifurcations. For each continuation node whose parent is a branch point, the method considers alternative attachment targets (grandparent, siblings) and picks the closest one that does not create a turn exceeding the configured angle threshold.

      Adapted from NeuTube's Swc_Tree_Node_Tune_Branch (Part 1: nodes whose parent is a branch point).

      Parameters:
      graph - the graph to modify
      cosThreshold - cosine of the maximum allowed angle. Connections with cosAngle <= cosThreshold are considered turns and the node becomes eligible for rewiring.
      See Also:
    • recalculateRadiiFromImage

      protected void recalculateRadiiFromImage(DirectedWeightedGraph graph, double effectiveThreshold)
      Recalculates radii for all nodes using image-based method (like APP2). This is critical for accurate coverage detection during pruning.
    • computeAndApplyScoreMap

      protected void computeAndApplyScoreMap(DirectedWeightedGraph graph)
      Computes or applies a score map and stamps each graph node's PointInImage.v with its score. If an external score map was set via setScoreMap(net.imglib2.RandomAccessibleInterval<? extends net.imglib2.type.numeric.RealType<?>>), it is sampled directly. Otherwise, a Tubeness or Frangi filter is computed from the source image.

      When scoreMapScales is null, scales are auto-derived from the radius distribution already present in the graph (from recalculateRadiiFromImage(sc.fiji.snt.analysis.graph.DirectedWeightedGraph, double)), using 3 percentiles (25th, 50th, 75th) of the non-zero radii.

      Parameters:
      graph - the graph whose nodes will be scored
    • darkNodeAndSegmentPruning

      protected void darkNodeAndSegmentPruning(DirectedWeightedGraph graph, double effectiveThreshold)
      APP2-style dark node and segment pruning.

      Phase 1: Dark Node Pruning (iterative) - For each leaf, if intensity <= background threshold, remove the leaf - Repeat until no more dark leaves found

      Phase 2: Dark Segment Pruning - For each terminal branch (path from leaf to branch point): - Delete if average intensity <= background threshold, OR - Delete if >= 20% of nodes are dark (intensity <= threshold)

    • hierarchicalPrune

      protected void hierarchicalPrune(DirectedWeightedGraph graph, double effectiveThreshold)
      Performs hierarchical pruning using intensity-weighted coverage.

      Algorithm: 1. Decompose tree into segments (paths between branch points) 2. Calculate segment length as SUM OF NORMALIZED INTENSITIES (not Euclidean!) 3. Sort segments by length (longest first) 4. For each segment, compute intensity-weighted coverage ratio using PIXEL MASK 5. If coverage > threshold, prune segment and children

    • pruneParallelBranches

      protected void pruneParallelBranches(DirectedWeightedGraph graph)
      Prunes parallel sibling branches, i.e., pairs of terminal branches that fork from the same branch point and then run alongside each other (their nodes stay within a radius-dependent proximity threshold). This is a common FM artifact: when the wavefront crosses a wide neurite, voxels on opposite sides of the centerline form separate parent chains that never re-merge (trees have no cycles), producing two paths that trace the same structure.

      For every branch point with 2+ children, each pair of sibling terminal segments is compared. A segment is "parallel" to its sibling when most of its nodes fall within max(meanRadius * 3, 3 voxels) of the nearest node on the other segment. The shorter parallel sibling is pruned.

    • computeIntensityWeightedJointCoverage

      protected double[] computeIntensityWeightedJointCoverage(SWCPoint node, net.imglib2.RandomAccess<net.imglib2.type.numeric.integer.UnsignedShortType> countRA, net.imglib2.RandomAccess<? extends net.imglib2.type.numeric.RealType<?>> srcRA)
      Computes INTENSITY-WEIGHTED joint coverage fraction (like APP2). Returns [coveredSig, totalSig] where coverage is weighted by image intensity.
    • computeIntensityRange

      protected void computeIntensityRange()
      Computes intensity range for GI normalization. APP2 uses actual image min/max, not threshold-based.
    • resampleCurve

      protected void resampleCurve(DirectedWeightedGraph graph, double stepSize)
      Resamples the curve to have evenly spaced points. Keeps branch points and endpoints, removes intermediate points that are too close.
    • getEffectiveThreshold

      protected double getEffectiveThreshold()
    • posToIndex

      protected long posToIndex(long[] pos)
    • posToIndex

      public static long posToIndex(long[] pos, long[] dims)
      Converts an N-dimensional position to a flat array index using row-major order.
    • indexToPos

      protected void indexToPos(long idx, long[] pos)
      Convert linear index to position, writing to provided array (avoids allocation).
    • nodeToVoxelPos

      protected void nodeToVoxelPos(SWCPoint node, long[] pos)
      Converts an SWCPoint's physical coordinates to voxel position. Handles both 2D and 3D images.
      Parameters:
      node - The SWCPoint with physical coordinates
      pos - Output array (must be dims.length size)
    • isInBounds

      protected boolean isInBounds(long[] pos)
      Checks if a voxel position is within image bounds. Uses ImgUtils.outOfBounds with cached interval bounds.
    • computeAverageSpacing

      protected double computeAverageSpacing()
      Computes average voxel spacing, handling both 2D and 3D images.
    • iterateNeighbors

      public static void iterateNeighbors(int[] delta, int dim, int nDims, Runnable action)
      Iterates over all neighbor offsets (26-connectivity in 3D).
    • trace

      public Tree trace()
      Traces the neuron and returns a Tree.
      Returns:
      the traced neuron morphology, or null if tracing fails
    • traceTrees

      public List<Tree> traceTrees()
      Traces the neuron and returns a list of Trees.

      With AutoTracer.ROI_EDGE strategy, returns separate trees for each neurite exiting the soma ROI. With other strategies, returns a single tree.

      Returns:
      list of traced trees, or empty list if tracing fails
    • traceMultiSoma

      public List<Tree> traceMultiSoma(List<SomaUtils.SomaResult> somas)
      Traces multiple somas in a single image using a NeuTube-style recovery pass strategy. The expensive GWDT is computed once; Fast Marching is then run once per soma, with previously-traced regions (dilated by getTracedRegionBuffer()) excluded from each subsequent pass.

      Somas should be sorted largest-first (as returned by SomaUtils.detectAllSomas(net.imglib2.RandomAccessibleInterval<? extends net.imglib2.type.numeric.RealType<?>>, double, double)). Each soma's contour is used to configure the ROI strategy, and the seed is placed at the soma center. Post-processing (pruning, smoothing, etc.) is applied independently to each trace.

      Auto-filtering: By default, the input list is processed through a soma reduction pipeline (EDT thickness filtering, count-based selection, gap analysis, and/or NMS consolidation) before tracing. This is appropriate when somas come from automatic detection (e.g., SomaUtils.detectAllSomas(net.imglib2.RandomAccessibleInterval<? extends net.imglib2.type.numeric.RealType<?>>, double, double)), which may produce many false positives. When providing pre-curated somas, e.g., from user-supplied ROIs via SomaUtils.detectSomasAt(net.imglib2.RandomAccessibleInterval<? extends net.imglib2.type.numeric.RealType<?>>, java.util.List<long[]>). Call setAutoFilter(false) to bypass the reduction pipeline and trace all input somas as-is. NMS consolidation via setMinSomaDistance(double) is still honored when auto-filtering is disabled, since the caller explicitly requested it.

      Parameters:
      somas - the detected somas, sorted by radius (largest first)
      Returns:
      list of trees, one per successfully traced soma
      Throws:
      IllegalStateException - if no seed can be derived from any soma
      See Also: