Class SeedConfidence

java.lang.Object
sc.fiji.snt.seed.SeedConfidence

public final class SeedConfidence extends Object
Shared helper for turning a detector's raw per-candidate scores (integrated density, local contrast, cluster density, ...) into SeedPoint.confidence values in [0, 1], or NaN when there is no basis to judge one candidate against another.

Plain min-max normalization (dimmest/lowest-scoring candidate -> 0, brightest/highest -> 1) is fragile: a single outlier candidate stretches or compresses the whole scale, often bunching every "ordinary" candidate into a narrow slice of the range. percentileClipNormalize(double[], double) instead maps a percentile window of the data onto a matching confidence sub-range and lets anything beyond that window extrapolate past it - curbed (clamped) to [0, 1] - so a few extreme candidates spread out at the ends without compressing everyone else. A clip of 0 recovers plain min-max normalization exactly.

Used by every SNT detector that assigns confidence from a raw score: SomaDetectorCmd, AlongPathDetectorCmd, PeripathDetectorCmd, and DensityClusterer (shared by TuftDetector and RootDetector) - rather than each keeping its own copy, which is how these previously drifted out of sync on edge-case behavior (e.g. what confidence a tie gets).

Author:
Tiago Ferreira
  • Method Details

    • percentileClipNormalize

      public static double[] percentileClipNormalize(double[] scores, double clipPercent)
      Percentile-clipped linear normalization of scores into confidence [0, 1].

      The clipPercentth and (100-clipPercent)th percentiles of the non-NaN entries of scores map onto confidence clipPercent/100 and 1-clipPercent/100 respectively; values beyond those percentiles extrapolate past that sub-range but are curbed (clamped) to [0, 1] - so real outliers still spread toward the extremes without compressing every other score into a narrow band, the way plain min-max normalization would. clipPercent = 0 exactly recovers plain min-max normalization onto [0, 1] (lowest score -> 0, highest -> 1).

      A NaN entry in scores (no score available for that candidate) always maps to confidence NaN - "nothing to judge it by" is a distinct, honest "unknown" state, never a fabricated real value. If fewer than two distinct non-NaN scores remain (empty input, every score NaN, or every non-NaN score tied), every entry likewise gets confidence NaN - there is nothing to normalize against. Callers that read SeedPoint.confidence as a real number (range filters, LUT color sampling, descending-confidence sorts) must treat NaN explicitly rather than relying on incidental NaN comparison/arithmetic semantics; see SeedOverlayRenderer and SeedOverlay#topKByConfidence for the established pattern.

      Parameters:
      scores - raw per-candidate scores (higher = more confident); NaN allowed; null or empty returns an empty array
      clipPercent - percentile clip width, clamped to [0, 45] (0 = plain min-max)
      Returns:
      one confidence value per entry of scores, same order, each in [0, 1] or NaN