Class MultiSpectralRefiner

java.lang.Object
sc.fiji.snt.analysis.MultiSpectralRefiner
All Implemented Interfaces:
Callable<Path>

public class MultiSpectralRefiner extends Object implements Callable<Path>
Post-hoc refinement of traced paths in multispectral (e.g., Brainbow) images.

For each path, the algorithm computes a reference color vector (the average intensity across all channels at each node), then iteratively adjusts node positions and radii to minimize a cost function combining:

  1. Intensity penalty fraction of voxels in the node's sphere whose total intensity falls outside the expected range
  2. Color penalty fraction of voxels whose spectral angle (cosine similarity) to the reference color vector is below threshold
  3. Radius penalty 1/r², favoring compact cross-sections
This is an SNT-native re-implementation of the nCorrect algorithm described in:
Azzouz, S et al., "Optimized Neuron Tracing Using Post Hoc Reanalysis." doi:10.1101/2022.10.10.511642
The minimum path-length quality gate is informed by:
Leiwe et al., "Automated neuronal reconstruction with super-multicolour Tetbow labelling and threshold-based clustering of colour hues", Nat Commun 15, 5279 (2024). doi:10.1038/s41467-024-49455-y

Like PathFitter, each instance operates on a single Path. call() is thread-safe for parallel execution; apply() must be called sequentially to commit results back to the original path.

Author:
Tiago Ferreira
See Also:
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final record 
    Immutable parameter set for multispectral refinement.
  • Constructor Summary

    Constructors
    Constructor
    Description
    MultiSpectralRefiner(ij.ImagePlus imp, Path path)
    Creates a refiner for a single path using an ImagePlus.
    MultiSpectralRefiner(net.imagej.ImgPlus<T> img, Path path)
    Creates a refiner for a single path using an ImgPlus.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
     
    void
    Applies all settings from another refiner to this one.
    Runs the multispectral refinement on this path.
    static double[]
    computeNodeCosts(ij.ImagePlus imp, Path path)
    Computes the cost at each node of a path without modifying it.
    static <T extends net.imglib2.type.numeric.NumericType<T>>
    double[]
    computeNodeCosts(net.imagej.ImgPlus<T> img, Path path)
    Computes the cost at each node of a path without modifying it.
    double[]
    Returns the per-node cost values after refinement.
    double
    Returns the total penalty of the path after refinement.
    double[]
    Returns the per-node cost values before refinement.
    double
    Returns the total penalty of the path before refinement.
    void
    Reads stored preferences from MultiSpectralRefinerCmd and applies them to this refiner.
    static int
    refineTree(ij.ImagePlus imp, Tree tree)
    Refines all paths in a tree, processing each path in parallel.
    static int
    refineTree(ij.ImagePlus imp, Tree tree, MultiSpectralRefiner.Parameters params)
    Refines all paths in a tree with custom parameters.
    static <T extends net.imglib2.type.numeric.NumericType<T>>
    int
    refineTree(net.imagej.ImgPlus<T> img, Tree tree)
    Refines all paths in a tree, processing each path in parallel.
    static <T extends net.imglib2.type.numeric.NumericType<T>>
    int
    refineTree(net.imagej.ImgPlus<T> img, Tree tree, MultiSpectralRefiner.Parameters params)
    Refines all paths in a tree with custom parameters.
    void
    setAutoTune(boolean autoTune)
    Enables automatic parameter tuning from path and image statistics.
    void
    setBackgroundThreshold(double threshold)
    Sets the background fraction threshold.
    void
    setColorWeight(double weight)
    Sets the weight for the color (cosine similarity) penalty term.
    void
    setConvergenceThreshold(double threshold)
    Sets the convergence threshold for the refinement loop.
    void
    setCosSimilarityThreshold(double threshold)
    Sets the cosine similarity threshold below which a voxel is considered spectrally dissimilar to the reference color.
    void
    setIntensityRange(double minIntensity, double maxIntensity)
    Sets the intensity range for adaptive percent-C computation.
    void
    setIntensityWeight(double weight)
    Sets the weight for the intensity background penalty term.
    void
    setMaxIterations(int maxIterations)
    Sets the maximum number of iterations for the refinement loop.
    void
    setMaxRadius(int maxRadius)
    Sets the maximum radius (in pixels) to test during radius optimization.
    void
    setPercentCRange(double minPercent, double maxPercent)
    Sets the percent-C range for adaptive intensity tolerance.
    void
    setRadiusWeight(double weight)
    Sets the weight for the radius expansion penalty term.
    void
    setReferenceWindowRadius(int windowRadius)
    Sets the sliding-window radius for per-node reference color computation.
    boolean
    Whether the refinement succeeded (penalty decreased or path was already optimal).

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • MultiSpectralRefiner

      public MultiSpectralRefiner(ij.ImagePlus imp, Path path)
      Creates a refiner for a single path using an ImagePlus.
      Parameters:
      imp - the multichannel image (Brainbow, etc.)
      path - the path to refine
      Throws:
      IllegalArgumentException - if the image has fewer than 2 channels
    • MultiSpectralRefiner

      public MultiSpectralRefiner(net.imagej.ImgPlus<T> img, Path path)
      Creates a refiner for a single path using an ImgPlus.
      Parameters:
      img - the multichannel image (Brainbow, etc.)
      path - the path to refine
      Throws:
      IllegalArgumentException - if the image has fewer than 2 channels
      See Also:
  • Method Details

    • setIntensityWeight

      public void setIntensityWeight(double weight)
      Sets the weight for the intensity background penalty term.
      Parameters:
      weight - the weight (default 1.00)
    • setColorWeight

      public void setColorWeight(double weight)
      Sets the weight for the color (cosine similarity) penalty term.
      Parameters:
      weight - the weight (default 0.85)
    • setRadiusWeight

      public void setRadiusWeight(double weight)
      Sets the weight for the radius expansion penalty term.
      Parameters:
      weight - the weight (default 3.75)
    • setCosSimilarityThreshold

      public void setCosSimilarityThreshold(double threshold)
      Sets the cosine similarity threshold below which a voxel is considered spectrally dissimilar to the reference color.
      Parameters:
      threshold - the threshold (default 0.90)
    • setBackgroundThreshold

      public void setBackgroundThreshold(double threshold)
      Sets the background fraction threshold. If more than this fraction of voxels in a node's sphere fail the intensity test, the node is considered to be in the background.
      Parameters:
      threshold - the threshold (default 0.47)
    • setIntensityRange

      public void setIntensityRange(double minIntensity, double maxIntensity)
      Sets the intensity range for adaptive percent-C computation.
      Parameters:
      minIntensity - lower bound (total channel sum); default 10000
      maxIntensity - upper bound (total channel sum); default 85000
    • setPercentCRange

      public void setPercentCRange(double minPercent, double maxPercent)
      Sets the percent-C range for adaptive intensity tolerance.
      Parameters:
      minPercent - tolerance at high intensities (default 0.05)
      maxPercent - tolerance at low intensities (default 0.30)
    • setMaxRadius

      public void setMaxRadius(int maxRadius)
      Sets the maximum radius (in pixels) to test during radius optimization.
      Parameters:
      maxRadius - the max radius (default 12)
    • setMaxIterations

      public void setMaxIterations(int maxIterations)
      Sets the maximum number of iterations for the refinement loop. The loop also stops early if convergence is reached.
      Parameters:
      maxIterations - the iteration cap (default 50)
    • setConvergenceThreshold

      public void setConvergenceThreshold(double threshold)
      Sets the convergence threshold for the refinement loop. The loop stops when the relative improvement per iteration falls below this fraction (e.g., 0.001 = stop when improvement is less than 0.1% of total penalty).
      Parameters:
      threshold - the relative improvement threshold (default 0.001)
    • setReferenceWindowRadius

      public void setReferenceWindowRadius(int windowRadius)
      Sets the sliding-window radius for per-node reference color computation. When enabled, each node's reference color is the average of the ±N neighboring nodes along the path, rather than a single global average. This handles color drift along long axons in Brainbow images.
      Parameters:
      windowRadius - number of nodes on each side to include. Use -1 (default) for a single global reference, or a positive value (e.g., 10–30) for sliding window.
    • setAutoTune

      public void setAutoTune(boolean autoTune)
      Enables automatic parameter tuning from path and image statistics. When enabled, call() will adjust maxRadius, cosSimilarityThreshold, and intensity thresholds based on the actual data before running the optimization loop.
      Parameters:
      autoTune - true to enable (default false)
    • getInitialPenalty

      public double getInitialPenalty()
      Returns the total penalty of the path before refinement. Only valid after call() has been invoked.
    • getFinalPenalty

      public double getFinalPenalty()
      Returns the total penalty of the path after refinement. Only valid after call() has been invoked.
    • succeeded

      public boolean succeeded()
      Whether the refinement succeeded (penalty decreased or path was already optimal).
    • getInitialNodeCosts

      public double[] getInitialNodeCosts()
      Returns the per-node cost values before refinement. Only valid after call() has been invoked.
      Returns:
      array of per-node costs (same length as the path), or null if call() hasn't run
    • getFinalNodeCosts

      public double[] getFinalNodeCosts()
      Returns the per-node cost values after refinement. Only valid after call() has been invoked.
      Returns:
      array of per-node costs (same length as the path), or null if call() hasn't run
    • applySettings

      public void applySettings(MultiSpectralRefiner ref)
      Applies all settings from another refiner to this one. Useful for batch operations where a reference refiner holds the user-configured parameters.
      Parameters:
      ref - the reference refiner to copy settings from
    • readPreferences

      public void readPreferences()
      Reads stored preferences from MultiSpectralRefinerCmd and applies them to this refiner. If auto-intensity is enabled in the preferences, the auto-calibrated values from the constructor are preserved.
    • call

      public Path call()
      Runs the multispectral refinement on this path. Thread-safe: does not modify the original path. Call apply() afterward (sequentially) to commit results.
      Specified by:
      call in interface Callable<Path>
      Returns:
      the refined path, or null if refinement failed
    • apply

      public void apply()
    • refineTree

      public static int refineTree(ij.ImagePlus imp, Tree tree)
      Refines all paths in a tree, processing each path in parallel.
      Parameters:
      imp - the multichannel image
      tree - the tree to refine
      Returns:
      the number of paths successfully refined
    • refineTree

      public static <T extends net.imglib2.type.numeric.NumericType<T>> int refineTree(net.imagej.ImgPlus<T> img, Tree tree)
      Refines all paths in a tree, processing each path in parallel.
      Parameters:
      img - the multichannel image (ImgPlus)
      tree - the tree to refine
      Returns:
      the number of paths successfully refined
      See Also:
    • refineTree

      public static <T extends net.imglib2.type.numeric.NumericType<T>> int refineTree(net.imagej.ImgPlus<T> img, Tree tree, MultiSpectralRefiner.Parameters params)
      Refines all paths in a tree with custom parameters.
      Parameters:
      img - the multichannel image (ImgPlus)
      tree - the tree to refine
      params - the parameter set to apply to all refiners
      Returns:
      the number of paths successfully refined
      See Also:
    • refineTree

      public static int refineTree(ij.ImagePlus imp, Tree tree, MultiSpectralRefiner.Parameters params)
      Refines all paths in a tree with custom parameters.
      Parameters:
      imp - the multichannel image
      tree - the tree to refine
      params - the parameter set to apply to all refiners
      Returns:
      the number of paths successfully refined
    • computeNodeCosts

      public static <T extends net.imglib2.type.numeric.NumericType<T>> double[] computeNodeCosts(net.imagej.ImgPlus<T> img, Path path)
      Computes the cost at each node of a path without modifying it. Useful for diagnostics and for the "Color Drift" plausibility check.
      Parameters:
      img - the multichannel image (ImgPlus)
      path - the path to evaluate
      Returns:
      per-node cost values (same length as path.size())
      See Also:
    • computeNodeCosts

      public static double[] computeNodeCosts(ij.ImagePlus imp, Path path)
      Computes the cost at each node of a path without modifying it. Useful for diagnostics and for the "Color Drift" plausibility check.
      Parameters:
      imp - the multichannel image
      path - the path to evaluate
      Returns:
      per-node cost values (same length as path.size())