Narrowband Integration

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.

SASpro-exclusive tool. Narrowband Integration is an original SetiAstro Suite Pro implementation by Franklin Marek. The screen compositor, per-channel hue slider with gradient preview and preset library, chevron-handle levels widget with PI-style relative midtone, saturation-to-greyscale lerp, dynamic filter rows with filename auto-matching, and the live downsampled preview with cursor-anchored zoom are all built from the ground up for SASpro's document model.
Workflow
Pick a broadband RGB image → enable one or more NB channels → choose a source image for each → tune hue, levels, saturation and amount against the live preview → Apply to Current View or Apply as New Document.

1. The preview area

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).

Zoom & pan:
🖱️ Drag — pan.
🖱️ Wheel — zoom in/out, anchored at the cursor. Pixel-delta trackpads use a gentle 1.03× factor; wheel-notch mice use 1.15×.
Zoom toolbar: zoom-out / zoom-in (1.25× steps) / 1:1 (100%) / fit (fill the viewport).
Zoom range is 5% to 1600%.

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.

2. Loading images

Broadband RGB

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.

The three fixed narrowband channels

Hα (656 nm), SII (672 nm) and OIII (496/501 nm) each have a dedicated group with:

Filename auto-match on load

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.

3. Hue

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:

ChannelDefault hueResulting colour
Hα4°warm red
SII0°pure/deep red
OIII156°green-cyan (teal)

4. Levels (Black / Mid / White)

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.

5. Amount & Saturation

6. Dynamic filter rows

Click + Add Filter to add a custom narrowband channel beneath the fixed three. Each dynamic row has everything the fixed channels have, plus:

PresetWavelengthDefault hue
Ha656 nm4°
SII672 nm0°
OIII496/501 nm156°
Neon585 nm52°
Argon488 nm196°
Nitrogen658 nm2°
Helium587 nm51°
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.

7. Applying

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.

8. Technical details

The compositor pipeline, per enabled channel, in order.

8.1 The screen blend

The core operation is standard screen compositing, applied per RGB channel:

\mathrm{out} = a + b - a\,b

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:

I_{k+1} = I_k + C''_k - I_k \cdot C''_k

with I_0 the input RGB and C''_k the amount-scaled colorized NB layer for channel k (see §8.5).

8.2 Hue colorization

The mono NB signal is converted to RGB by driving the HSV value channel while fixing saturation to 1:

C_{\mathrm{nb}}(x,y) = \mathrm{HSV2RGB}(h,\,1,\,m(x,y))

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.

8.3 Per-channel levels (MTF)

Before colorization, the mono NB signal x is remapped by the channel's Levels. First a linear black-point / white-point stretch:

t = \mathrm{clip}\!\left(\frac{x - K_{\mathrm{black}}}{K_{\mathrm{white}} - K_{\mathrm{black}}},\;0,\;1\right)

then a midtones transfer function (PixInsight-style MTF) using the channel's midtone balance M:

\mathrm{MTF}(t,\,M) = \frac{(M-1)\,t}{(2M-1)\,t - 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:

M_{\mathrm{abs}} = K_{\mathrm{black}} + M_{\mathrm{rel}}\,(K_{\mathrm{white}} - K_{\mathrm{black}})

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.

8.4 Saturation lerp

Before the colorized layer is screened, Saturation linearly interpolates it toward a greyscale copy of the mono signal:

C' = s\,C_{\mathrm{nb}} + (1-s)\,M_{\mathrm{rgb}}

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.

8.5 Amount scaling

Finally the layer is scaled and clipped before the screen:

C'' = \mathrm{clip}(C' \cdot \alpha,\;0,\;1)

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.

8.6 Resampling and preview

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.

8.7 Live-update debounce

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.

Credits. Narrowband Integration — the compositor, UI, hue slider, dynamic filter rows, filename auto-matching, chevron levels widget, and preview engine — is original work by Franklin Marek for SetiAstro Suite Pro. Standard components credited to community: the screen blend is a classical compositing operator (Porter & Duff 1984, “Compositing Digital Images”); the midtones transfer function is the standard rational MTF popularized by PixInsight's HistogramTransformation; HSV↔RGB conversion is the Smith (1978) six-sector hexcone construction (SASpro ships its own inline implementation and does not depend on an external library for it); Rec. 601 luminance weights (0.299, 0.587, 0.114) are a standard colorimetric convention. OpenCV is credited as an optional compute backend used for image resampling and for drawing the hue slider's gradient preview — the compositor runs identically without it. NumPy provides the array engine, and PyQt6 the UI framework.