Saturation
Controlled nonlinear chroma enhancement over color relationships that have already been established by calibration -- a rendering transformation applied to calibrated relationships, not additional calibration and not creation of new spectral information. Covers three related but non-equivalent strategies: global saturation enhancement, hue-selective enhancement, and masked enhancement.
schema 1 · revision 1Recognize it
- Color relationships are already established (post-SPCC or another calibration/palette path) but chromatic separation is subtle and hard to see -- target color, galaxy arm/bulge distinction, or narrowband palette separation reads as muted.
Intended output
Existing chromatic separation becomes easier to see, intended hue relationships are preserved unless a hue-selective strategy deliberately changes emphasis, background chroma noise does not become visible colored grain, and bright star cores/high-chroma regions are not driven into clipped/flat color.
Required input state
- Nonlinear/stretched data, already through the intended broad color-calibration path (SPCC, other calibration, or an explicitly non-calibrated/palette path), free of major unresolved background color casts that saturation would simply amplify, in a stable tonal state since saturation interacts strongly with stretch and curves, with enough floating-point channel headroom that enhancement does not pile channels against output limits. Note: the ontology describes color_sat as applied after curves, but the actual runtime call order in `pixinsight.run_postprocess()` is `... HDRMT -> LHE -> ColorSat -> Curves` for a specific production run -- the higher-level autoprocess call sequence is authoritative for what actually happened, not the ontology sentence.
What NOVA does
The ontology exposes one uniform parameter, color_sat_boost (nominal range 0.10-0.60, default 0.25), dispatched through `run_postprocess(color_sat=True, color_sat_boost=...)` to PixInsight ColorSaturation. pi_postprocess.js supports three hue-vs-saturation-delta curve presets: uniform (same boost at all hue control points), galaxy (modest red, negative yellow/orange, stronger cyan/blue/violet), and nebula (strong Ha-red, OIII/cyan, magenta blend-zone boost) -- but `sat_preset` defaults to None and no production caller currently supplies "galaxy" or "nebula", so the JS falls through to uniform regardless of object type. Separately, after a successful PixInsight NarrowbandNormalization with nbn_hoo_boost > 0, NOVA applies its own hue-selective ColorSaturation curve (strong red/Ha boost, substantial OIII/cyan boost, low boost near yellow-green/blue star regions) specifically to restore HOO visual separation NBN can leave muted -- this is a strategy tied to narrowband normalization, not evidence for broadband OSC saturation choices.
Use when
- Color relationships are already calibrated/established and existing chromatic separation is genuinely muted, not merely a consequence of an upstream problem that should be fixed earlier.
Skip when
- The data is monochrome or not yet mapped into a color composite/palette -- compute_color_sat() correctly returns disabled for non-color images.
- An unresolved background color cast exists upstream -- saturation would amplify the cast rather than fix it.
- The desired outcome is actually color recovery at clipped/near-clipped pixels -- that information is already gone and cannot be restored by this step.
Limits
- Saturation increases channel separation/chroma while attempting to preserve hue family; it does not create new spectral information. If the original data, filter, calibration, stretch, or clipping already destroyed color contrast, saturation can only remap the color information still present -- it cannot recover it.
- Near-white/clipped star cores cannot regain color by saturation: if all channels are already clipped/equalized at a pixel, the channel-ratio information needed to reconstruct color is already gone at that pixel. Saturation may only color the surrounding unclipped profile/halo.
- The current `color_sat` Experiment Mode family is a single-method strength experiment (sat_feather/gentle/moderate/strong, all uniform, plus a declared `none` control) -- not a method experiment and not a complete strategy experiment. The declared `none` candidate does not currently dispatch as a real copy-through (issue #669: `fn: "none"` falls through to a nonexistent `seti_astro.none` rather than the dispatcher's `engine == "none"` copy-through path), so today's comparisons lack even that baseline until it is fixed. The runtime also contains materially different hue-selective strategies (galaxy preset, nebula preset, post-NarrowbandNormalization HOO restoration) that the normal `sat_*` variants do not test: `_run_variant()` forwards `color_sat_boost` but not `sat_preset`, so all four active `sat_*` variants execute the wrapper's uniform curve regardless of the dormant galaxy/nebula presets existing in code. A historical `sat_moderate` win cannot be cited as evidence for the galaxy preset, nebula preset, or HOO restore -- they are different strategies with different confounders.
- `_NL_STEPS` (the generic nonlinear adaptation/masking step set) contains the string `color_saturation`, while the ontology's real step key is `color_sat`. A normal Experiment Mode call using the actual ontology key therefore does not enter the generic nonlinear adaptation path at all -- no generic luminance-mask injection, and `tool_params.compute_color_sat()`'s measured boost is not used to scale the `sat_*` variants around a measured baseline. The ontology's fixed amounts (0.08/0.15/0.25/0.38) are the effective amounts today, not adapted values.
- `compute_color_sat()`'s boost estimate is a whole-frame-median channel-spread proxy, not per-pixel chroma in target ROIs and not a calibrated color-science saturation measurement. It can be dominated by sky background, a large emission nebula, a bright galaxy bulge, filter response, or residual cast -- useful as an engineering heuristic for "the image may look globally muted," not as a direct saturation-quality measurement.
Scientific and aesthetic notes
- A fair comparison starts every candidate from the same parent FITS and exact upstream state (color-calibration/NBN state, stretch, curves, star-removal/recombination state, masking) and uses a real copied-input control -- currently a manual copy, since the ontology's own declared `none` candidate does not yet dispatch (issue #669). Hue-selective-vs-uniform comparisons must be labeled a strategy experiment, not a strength experiment, and the exact HS control points/preset should be recorded, not just a variant ID.
- More saturation is not more color accuracy -- a transform can make an incorrectly calibrated image more vividly incorrect. A low-saturation output is not automatically deficient either; some targets/data paths are genuinely dominated by one emission component or have weak recorded color contrast.
- Background chroma can masquerade as target improvement: if a global boost increases both nebula red and red sky noise, a preview may look more dramatic while objective target-vs-background separation actually gets worse.
- Real condition-specific evidence (NGC 4565, NGC 6334) recommends masked/hue-selective enhancement over a strong global boost when sky chroma noise is visible or the target is a large fraction of the frame -- single-condition execution evidence, not universal validation.
Evidence and measurements
| Measurements | Acceptance criteria |
|---|---|
|
|
Cross-tool matrix
| Tool | Equivalence | Expected result | Evidence |
|---|---|---|---|
| nova | Exact replay | Existing chromatic separation becomes easier to see with hue relationships preserved and no new colored background grain or clipped/flat star cores. | nova-saturation-source, nova-ngc4565-ngc6334-saturation-evidence |
| pixinsight | Same engine, adapted host | A hue-conditioned saturation delta applied via the HS control-point curve. | pixinsight-saturation-intro-p28, nova-saturation-source |
| saspro | Functional alternative | Not applicable to NOVA's current color_sat dispatch; documented for completeness only. | nova-saturation-source |
| siril | Functional alternative | Enhanced chroma via Siril's own saturation tooling. | nova-saturation-source |
NOVA Python pipeline uniform ColorSaturation dispatch; galaxy/nebula HS presets and compute_color_sat() dormant/unwired for the normal color_sat experiment
- Record the effective HS curve/preset (even though it is currently always uniform for the sat_* family), the applied amount, mask state, and upstream color-calibration/NBN state -- candidate ID alone does not capture treatment identity here.
- Do not generalize a sat_* strength-ladder result to the dormant galaxy/nebula hue-selective presets or the HOO restore path; none of them are exercised by the normal experiment today.
- Do not treat compute_color_sat()'s whole-frame-median proxy as a saturation-quality measurement.
Controls and starting ranges
- sat_feather / sat_gentle / sat_moderate / sat_strong
- uniform boost 0.08 / 0.15 / 0.25 / 0.38
- none
- declared control, currently non-dispatching -- see limits
- galaxy / nebula HS presets, NBN HOO restore
- source-confirmed capability, not currently an Experiment Mode candidate
Mask behavior: JS implementation supports an optional luminance mask via lum_masks.color_sat, but the color_sat/color_saturation step-name mismatch currently prevents the standard experiment from receiving the generic adapted mask.
Failure modes
- Global color/noise exaggeration -- vivid target but colored/grainy sky.
- Garish or posterized stars from too much boost on clipped/near-clipped stellar profiles.
- Monochromatic emission staying monochromatic -- stronger global saturation mostly amplifies one already-dominant channel rather than producing real separation.
Recovery
- Reduce amount; use a luminance/range/object mask; compare against the no-op control; diagnose the underlying channel content before forcing separation.
PixInsight ColorSaturation ColorSaturation (HS curve); project runtime pin 1.9.3 Lockhart
- ColorSaturation.HS is a saturation-delta-vs-hue-position curve, matching PixInsight's own documented saturation-transfer model.
- Distinguish CurvesTransformation's own saturation-curve capability from ColorSaturation -- both can manipulate saturation as a function of hue but are functionally similar, not automatically numerically equivalent.
Controls and starting ranges
- uniform / galaxy / nebula HS curve
- control-point presets; galaxy and nebula are NOVA-authored, not generic vendor presets
Mask behavior: Supported for masked enhancement; not exercised by the current standard color_sat experiment due to the step-name mismatch.
Failure modes
- Assuming display appearance alone (an exported preview) proves color-managed correctness rather than checking floating-point channel extrema.
Recovery
- Reduce boost; protect highlights; inspect the floating-point export rather than only a preview JPEG.
Seti Astro Suite Pro (context only for this family) not the primary engine for this step; P28 does not materially depend on SASpro for the saturation transform itself
- This process family's actual transform is PixInsight ColorSaturation, not a SASpro wrapper -- treat any SASpro saturation tooling as a separate, functionally similar alternative rather than the engine NOVA currently uses here.
Controls and starting ranges
- availability
- not currently NOVA's dispatch path for this step
Mask behavior: Not applicable to NOVA's current dispatch for this step.
Failure modes
- Assuming SASpro saturation tooling and NOVA's PixInsight-based color_sat produce equivalent output without a controlled comparison.
Recovery
- N/A -- not NOVA's current dispatch path.
Siril saturation/color tools native saturation/color tools; exact version not independently confirmed in this repo
- Treat as the same conceptual goal -- chroma enhancement over already-established color -- with different implementation than NOVA's PixInsight-based path.
- Apply the same before/after chroma/hue/headroom measurement discipline used for NOVA's own candidates.
Controls and starting ranges
- saturation tools
- typically applied post-stretch/post-calibration
Mask behavior: Not independently confirmed in this repo.
Failure modes
- Treating a Siril saturation result as evidence about NOVA's PixInsight ColorSaturation candidates.
Recovery
- Prefer the no-op control if the result damages target or star color.
Validation status
Not yet Jeff-validated. Use this as sourced guidance, not a certification.
Sources
- Phase-2 research packet P28, 2026-08-28
packet:P28:2026-08-28— NOVA source-confirmed - NOVA ColorSaturation implementation, HS presets, and the color_sat/color_saturation step-name mismatch
nas_server/pi_postprocess.js; nas_server/pixinsight.py:run_postprocess; nas_server/tool_params.py:compute_color_sat; nas_server/experiments.py _NL_STEPS— NOVA source-confirmed - NGC 4565 and NGC 6334 real runs: masked/hue-selective enhancement recommended over global boost
critiques/20260722_073443_seestar_galaxy.md; critiques/20260722_074547_seestar_nebula.md— NOVA execution record - PixInsight introductory material: saturation transfer and selective hue examples — Vendor-documented
- NIST/SEMATECH Engineering Statistics Handbook: design of experiments — Vendor-documented
- Ontology 'none' control candidates fail dispatch instead of running a true copy-through (issue #669)
nas_server/experiments.py:_run_variant; SeeStar-db#669— NOVA source-confirmed
Related evidence
The M66 recipe and Jeff-validation ledger will link here when their static exports are available. Until then, this article remains explicitly unvalidated.