Build a single RGB document from three mono channels — either from open views in the current session or from files on disk. Classical workflow for RGB/LRGB/narrowband assembly: process each filter's stack as mono (calibration, registration, denoise, stretch if you want pre-combine stretches) and bring the three together here. Always creates a new document; nothing is written to the source channels.
Two radio buttons at the top of the dialog pick where the three channels come from:
Only one mode is active at a time — the inactive mode's widgets are greyed out so there's no ambiguity about which inputs will be used.
Three combo boxes (Red / Green / Blue), each showing every open document by its window title.
When the dialog opens with at least three documents available, SASpro scores every title against the three channels and pre-selects the best match for each dropdown. Scoring looks at the title in lowercase and awards points for:
red, green,
blue) — +10._r_,
-g-, .b.) — +8._r, -g) or end-of-title
letter — +7.Ha
scores +6 for Red; SII scores +5 for Red;
OIII scores +5 for Green and +4 for Blue (the usual
HOO/SHO mappings).The best-scoring title is pre-selected; ties fall to the first match
in the dropdown order. If no title scores above zero for a channel,
the first document is chosen as a neutral default and you're expected
to pick manually. The heuristic is designed to Just Work on filenames
like NGC7000_Ha.fits / NGC7000_OIII.fits / NGC7000_SII.fits
or the more literal M31_red / M31_green / M31_blue, but
it never locks a choice — the dropdowns are always
user-overridable.
Each of the three Load… buttons opens an OS file dialog filtered to common astronomy formats. The chosen filename is shown next to its button; nothing is read from disk until Combine is pressed. Multi-channel files are supported — see § 6.1 for what happens to their channels.
Reads the three channels, verifies dimensions, stacks them into a
new RGB document named either RGB_Combined (views mode)
or RGB_<red-file-stem> (files mode), and opens a
subwindow for it. The source documents and files are left untouched.
In views mode, the new document inherits a World Coordinate System from the first donor among the three that carries one, in the order Green → Red → Blue. Green is tried first because it sits in the middle of the visible spectrum and is the usual astrometric calibration channel in LRGB rigs; the other two are tried only if green has no WCS. In files mode no WCS is inherited — the source documents don't exist in-session to pull headers from. If you want WCS on a files-mode combine, open the files as documents first, then use views mode.
All three channels must have identical dimensions. A mismatched set raises a message dialog with the mismatch and no new document is created; align or crop upstream and retry.
Everything happens on float32 [0, 1]. The combine is a plain stack-along-axis-2; the interesting work is in the input normalisation and the channel-match scoring.
Each selected input (view image or loaded file) passes through
_mono_from_any, which produces a 2-D float32 [0, 1]
array:
_to_f01 coerces every input to float32 [0, 1] without
assumptions about where the data came from:
max(|a|) > 1 and finite, the array
is divided by that max; otherwise the data is kept as-is. This
means 16-bit integer data gets divided by its own max (not 65535),
which keeps the per-image contrast but drops a frame's absolute
scale information — which is fine for colour combine, where
per-channel scaling will be re-done anyway by any downstream
balance operation.Each candidate title gets a per-channel score computed from case-folded regex matches. The scoring vector by channel is:
| Pattern | R | G | B |
|---|---|---|---|
Full colour word (red/green/blue) |
+10 | +10 | +10 |
Separator-bounded letter (_r_ etc.) |
+8 | +8 | +8 |
| Suffix / end-of-title letter | +7 | +7 | +7 |
Ha emission line |
+6 | — | — |
SII emission line |
+5 | — | — |
OIII emission line |
— | +5 | +4 |
| Conflicting colour word | −10 | −10 | −10 |
| Conflicting single-letter code | −5 | −5 | −5 |
Separator matching uses the character class
[_\-\s\.] for “letter boundary”, so dots in
filenames behave the same as underscores or hyphens. The three channel
scorers run independently per title, and the title with the highest
positive score wins its dropdown. Scores of zero or less leave the
dropdown at index 0 as a neutral default — which is why,
on a fresh session with three generically-named documents, you'll
sometimes see all three channels defaulting to the first document;
that's by design, not a bug.
Once R, G, B are three identically-shaped 2-D float32 arrays:
via np.stack([r, g, b], axis=2), then clipped once more
to [0, 1] as a belt-and-braces guard against anything the per-channel
normalisation might have missed in edge cases
(NaN-dominated frames, etc.).
The result is handed to the document manager via whichever of
open_array, open_numpy, or
create_document is available, with metadata
step_name = "RGB Combination" and the
title derived from the mode (as in § 4). The main window's
WCS helpers (_extract_wcs_dict, _apply_wcs_dict_to_doc)
are then called in the G → R → B donor
order until one of them yields a usable WCS, which is copied onto the
new document before its subwindow is spawned. If no donor has a WCS,
the new document carries none — a plate-solve can be run on it
afterwards from any of SASpro's astrometry tools.