Screen one or more narrowband emission-line channels (Hα, SII, OIII, and any custom wavelengths you add) into a broadband RGB image, with per-channel hue, saturation, amount and black/mid/white levels — the counterpart to Continuum Subtraction, letting you put the recovered line-emission back onto a colour image as hue-tinted luminance.
The right pane shows the live result at the current zoom. It updates automatically whenever any control changes (debounced by 300 ms so dragging a slider stays smooth).
Small preview (fast) below the controls downsamples the preview to a 1200 px long axis for responsive editing. Turn it off to preview at full resolution (useful for pixel-peeping before Apply). The Apply buttons always use full resolution regardless.
Pick your base RGB image from the top dropdown. All currently open documents with an image are listed. ↺ Refresh re-reads the open document list without resetting your other picks — use it after you've loaded new images into SASpro.
Hα (656 nm), SII (672 nm) and OIII (496/501 nm) each have a dedicated group with:
0.299R + 0.587G + 0.114B) before being colorized.When you (re)populate the dropdowns via Refresh, SASpro scans every open document's title for narrowband markers and auto-selects the best match for each of Hα, SII and OIII — and switches that channel on. Patterns matched (case-insensitive): ha, hα, halpha, h-alpha for Hα; sii, s2, sulfur for SII; oiii, o3, oxygen for OIII. Matches get a higher score when the marker sits between separators (underscore, hyphen, dot, space), so M8_Ha_master.fit beats Charlotte.fit for the Hα slot.
Each channel gets its own colour via the hue gradient slider — drag the ball along the rainbow, or type a precise value (0–359.9°) in the Hue spin box next to it. The two stay in sync. Default hues:
| Channel | Default hue | Resulting colour |
|---|---|---|
| Hα | 4° | warm red |
| SII | 0° | pure/deep red |
| OIII | 156° | green-cyan (teal) |
Each channel has an inline Levels bar with three draggable chevrons sitting under a black↔white gradient:
Hover any chevron to get the resize cursor. Grab the one you want and drag; the dragged chevron grows 20% to confirm it's the one you've got hold of. Black and White are hard-clamped to stay in order with a 0.001 minimum gap; Mid is clamped to stay strictly between them. The levels remap happens before colorization — see §8.3 for the maths.
1.0 you get the full hue; at 0.0 the NB signal is added as pure luminance with no hue shift, preserving every bit of signal while stripping the colour cast. Useful when you want OIII detail to boost structural luminance without turning the galaxy teal.Click + Add Filter to add a custom narrowband channel beneath the fixed three. Each dynamic row has everything the fixed channels have, plus:
| Preset | Wavelength | Default hue |
|---|---|---|
| Ha | 656 nm | 4° |
| SII | 672 nm | 0° |
| OIII | 496/501 nm | 156° |
| Neon | 585 nm | 52° |
| Argon | 488 nm | 196° |
| Nitrogen | 658 nm | 2° |
| Helium | 587 nm | 51° |
| Custom | — | 0° (edit freely) |
Picking a preset also renames the row to match. Pick Custom if you want to keep your own name while editing the hue freehand. Each row has a × button to remove it; dynamic rows render in the order you added them.
set_image(). Falls back to opening a new document if the target doesn't support in-place updates.<rgb-name> [NB Integration], leaving your source untouched.Both Apply buttons compute at full input resolution regardless of the Small-preview toggle. The dialog remembers its geometry, splitter position and small-preview preference across sessions.
The compositor pipeline, per enabled channel, in order.
The core operation is standard screen compositing, applied per RGB channel:
which is the complement of multiplicative darkening: it brightens the base image by the colorized NB layer, with the result bounded in [0, 1] for inputs in [0, 1]. Screen is commutative and associative, so stacking multiple NB channels is order-independent (within numerical precision). The full composition for N enabled channels is:
with I_0 the input RGB and C''_k the amount-scaled colorized NB layer for channel k (see §8.5).
The mono NB signal is converted to RGB by driving the HSV value channel while fixing saturation to 1:
where h is the user-set hue (0–360°), saturation is held at 1.0, and value is the leveled mono signal m(x,y) from §8.3. SASpro ships its own inline HSV→RGB sector math (six-sector piecewise linear, no library dependency), so the colorizer runs identically whether or not OpenCV is installed. OpenCV is used only to draw the hue slider's gradient preview when available — the compositor doesn't depend on it.
Before colorization, the mono NB signal x is remapped by the channel's Levels. First a linear black-point / white-point stretch:
then a midtones transfer function (PixInsight-style MTF) using the channel's midtone balance M:
The result m(x,y) = MTF(t, M) becomes the value channel for the colorizer. The MTF implementation is the shared _mtf_vect from SASpro's histogram transform engine, so levels here behave identically to the Levels / Histogram Transform tool.
The Mid chevron is stored as a relative position inside [K_black, K_white] rather than an absolute level, so Black and White can be moved without changing the midtone balance:
Dragging Black or White rescales M_abs proportionally while M_rel stays put. This matches PixInsight's HistogramTransformation convention and is why your midtone looks "right" after you've narrowed the black/white range.
Before the colorized layer is screened, Saturation linearly interpolates it toward a greyscale copy of the mono signal:
where Mrgb = (m, m, m) — the leveled mono signal broadcast into all three channels.
At s = 1 this is a no-op (full hue preserved). At s = 0 the output is pure mono-into-three-channels — the signal still gets screened onto the RGB, but with no hue bias at all, so the base image's own colour balance is preserved and the NB adds luminance only. Intermediate values give a controllable “desaturated hue” look, useful for toning down an aggressive OIII blue in a bright galaxy core.
Finally the layer is scaled and clipped before the screen:
with α the Amount setting (0–2). Because the clip happens before screen, Amount > 1 doesn't push outputs past 1 — it saturates the colorized layer first, which in turn pushes the screen result toward the hue colour rather than toward white. This is why Amount 2 feels like a “colour boost” rather than a brightness boost.
NB sources that don't match the RGB resolution are resampled to the RGB grid with cv2.resize (INTER_AREA) when OpenCV is available; otherwise SASpro uses a nearest-neighbour index map so the pipeline still runs headless. The “Small preview (fast)” downsampler uses the same INTER_AREA path, capped at a 1200 px long axis; Apply buttons always run on the full-resolution RGB and resize each NB source into it.
Every control is wired to a 300 ms single-shot QTimer that coalesces rapid changes (dragging a slider, scrubbing a chevron) into one preview recompute. The result pixmap is cached and only re-scaled when the zoom changes, so slider interaction stays smooth even on large frames.