Function: Statistical Stretch - setiastro/setiastrosuitepro GitHub Wiki

Function: Statistical Stretch

Analytic, target-median stretch for mono and RGB images. This tool performs a closed-form tone mapping to move the image median from the current value (T) to a chosen Target Median (T'), with T,T' ∈ (0,1).

In SASpro, the stretch is implemented as a closed-form median-targeted curve applied after an optional blackpoint lift. It operates on float images (typically normalized to [0,1]) and supports:

  • Mono stretch
  • RGB Linked (single curve for all channels)
  • RGB Unlinked (per-channel curves)
  • Optional Curves Boost (gentle S-curve)
  • Optional HDR highlight compression
  • Optional Luminance-only stretch (RGB) with safe recombination
  • Optional High Range manager (robust rescale + soft clip)

Code: imageops/stretch.py


Tone curve & closed-form solution

Midtones-transfer family (conceptual)

Statistical Stretch models the midtones-transfer family:

f_a(x) = \frac{3^{a}\,x}{\left(3^{a}-1\right)x + 1}, \qquad x\in[0,1].

Here a is a real-valued “amount” that analytically continues the effect of applying a midtones operator a times.

Solve for the amount that maps median (T → T')

a \;=\; \frac{\log\!\Big(\dfrac{T'}{1-T'} \cdot \dfrac{1-T}{T}\Big)}{\log 3},
\qquad T,T'\in(0,1).

Then the image is mapped by x ↦ fₐ(x). This is not arcsinh; it is an analytic midtones transfer aimed precisely at a target median.

What SASpro evaluates (fast closed-form)

In SASpro the implementation is optimized to avoid building a full “rescaled image” first. Instead it evaluates the equivalent closed-form expression directly from the image and a few scalars:

Define:

  • bp = blackpoint
  • denom = max(1 − bp, ε)
  • r = (x − bp) / denom
  • med = (T − bp) / denom (median in the same rescaled space)
  • t = T' (target median)

Then each pixel is mapped by:

y \;=\; \frac{(med-1)\,t\,r}{med\,(t+r-1) - t\,r}.

This is the accelerated form used by the numba_*_from_img() kernels (or NumPy fallbacks) and is mathematically equivalent to the median-targeted midtones transfer.


Blackpoint handling (why the slider “works” now)

Before the analytic stretch, SASpro optionally raises the blackpoint using a robust noise estimate:

  • A robust sigma is estimated using MAD on the lower half of the distribution (fast sampling for speed).
  • Blackpoint is computed as:
bp = \mathrm{median} - (\sigma_{\text{slider}})\cdot\sigma_{\text{robust}}.

Then bp is clamped to [min(image), 0.99].

No Black Clipping

If No Black Clipping is enabled:

  • blackpoint becomes bp = min(image)
  • the sigma-based blackpoint lift is bypassed

For RGB Unlinked, blackpoint is computed per channel.


Parameters (UI)

Core

  • Target median (T'): desired median after stretching.

  • Normalize to [0,1]: optional post-stretch scaling so the maximum becomes 1.0.

    • Useful for display/workflow consistency.
    • Disable if you want to preserve absolute scaling relationships.
  • Blackpoint Sigma: strength of sigma-based blackpoint lift.

  • No Black Clipping: bypass sigma blackpoint; uses min(image) as blackpoint.

RGB options

  • Linked channels (RGB only)

    • On: compute one curve from global statistics and apply to all channels (best color preservation).
    • Off: compute/apply per channel (can correct color imbalance but may shift color balance).

Curves Boost (optional)

  • Apply Curves Adjustment: applies a gentle S-curve after the analytic stretch.
  • Strength (s ∈ [0,1]): controls contrast lift around mid-tones.

Implementation details:

  • The curve is defined by 6 control points and applied as a piecewise-linear LUT via np.interp.
  • Control points are cached for speed.

HDR highlight compression (optional)

  • HDR Compress: smooth soft-knee highlight rolloff after the stretch.
  • HDR Amount (0..1): strength of compression.
  • HDR Knee (0..1): where highlight compression begins.

For RGB, SASpro compresses luminance, then recombines by linear scaling to reduce color shifts and star bloat.

Luminance-only mode (RGB optional)

  • Luma Only: stretch luminance only, then recombine into RGB by linear luminance scaling.

  • Luma Mode: Rec.709 / Rec.601 / Rec.2020 (and supported profiles).

    • If snr weighting is selected, SASpro can estimate per-channel noise sigma for luminance calculation.

High Range mode (optional)

A “ready-to-use” high dynamic range manager (useful for extreme stacks):

  • Robust floor (median − k·sigma)
  • Soft/hard ceilings from percentiles
  • Safe rescale + pedestal
  • Optional MTF steering toward Target Median
  • Final soft highlight rolloff

Controls include:

  • Pedestal
  • Soft Ceil Percentile
  • Hard Ceil Percentile
  • Softclip Threshold
  • Softclip Rolloff

Mask-aware apply

If a mask m ∈ [0,1] is active, the result is blended:

I_{\text{final}} \;=\; m \cdot I_{\text{stretched}} \;+\; (1-m)\cdot I_{\text{source}}.

Workflow

  1. Pick Target Median (common starts: 0.20–0.35, often 0.25).

  2. Choose Linked vs Unlinked (RGB).

  3. Set Blackpoint Sigma (or enable No Black Clipping if you want to preserve faint background).

  4. Optional enhancements:

    • Curves Boost for midtone contrast
    • HDR Compress for star/core highlight control
    • Luma Only (RGB) to protect color while changing brightness
    • High Range for difficult high-dynamic-range data
  5. Preview and adjust; Apply commits (with undo).


Preview & Navigation (non-destructive)

  • Zoom In/Out, 100%, Fit
  • Ctrl + Wheel zooms at cursor; drag to pan
  • Preview shows the stretched image only; the source is untouched until Apply

Notes & tips

  • The stretch is monotone and median-targeted, making it generally star-friendly compared to aggressive global curves.

  • For RGB stacks with color imbalance:

    • try Unlinked first to equalize channels,
    • then a small Curves Boost to restore contrast.
  • If bright stars/cores are harsh, enable HDR Compress (and adjust Knee).

  • Use Luma Only when you want to change brightness/contrast while keeping chroma stable.

  • Normalize is convenient, but it changes absolute scaling—disable it if downstream steps expect unchanged relative scaling.