SASpro-exclusive dynamic-range compressor for the bright half of the histogram. The classical problem it solves: inside a galaxy core, a planetary nebula shell, or a bright star's near-saturated inner profile, there is real structure — dust lanes, HII regions, concentric shells, a tiny companion — but it has been squeezed into such a narrow luminance range near unity that it reads to the eye as featureless white. WaveScale HDR decomposes the luminance into starlet wavelet planes, amplifies the fine-detail planes only where the image is bright, aligns midtones so the overall look doesn't shift, and finally applies a gentle dimming curve that pulls the result back down into display range. The lost detail reappears without destroying the dark background.
Slider, 2–10, default 5. How many wavelet detail layers the luminance is split into. Each additional scale reaches structures roughly twice as large in pixels, so 5 scales covers everything from single-pixel detail out to ~32-pixel features; 10 scales reaches kilopixel-scale structure.
Also drives the automatic dimming gamma applied at the end (§ 6.6), so more scales means more highlight-taming after the amplification.
Slider, 0.10–5.00, default 1.50. The strength of the local-contrast boost per plane. Only takes effect where the luminance mask is non-zero.
Slider, 0.10–10.00, default 5.00. Shapes the luminance mask that decides where the effect is applied. The mask is the image's own normalised luminance raised to this gamma, so higher values pull the mask threshold up toward unity.
The side HDR Mask window shows exactly what this slider produces, updated live (debounced to 250 ms) so you can watch the white region shrink as you push gamma higher. If the current document has an active mask, the window title changes to “HDR Mask (L × Active Mask)” and the two masks are multiplied together before display and application.
A small 400×400 side window that appears when the dialog opens. It shows the current effective mask — the luminance mask built from the image's L* channel at the current gamma, multiplied by the document's active mask if one exists. White means “full effect here”, black means “leave alone”, greys are proportional blends.
The window updates automatically as you drag the Mask Gamma slider (with a 250 ms debounce to avoid lag on large images), and after each Preview completes, so you can always see what mask the next Apply will use. It's purely display — nothing you do in this window changes the result.
Runs the full pipeline on a background QThread and streams progress updates to the small progress bar at the bottom-right (“Converting to Lab color space”, “Decomposing luminance with starlet”, “Finalizing”). When it completes, the main view updates to show the mask-blended result and the Apply button is enabled.
A toggle button next to Preview. When pressed, flips the main view to the untouched original so you can compare before and after; the button label switches to “Show Preview” so a second press flips back. The side mask window is unaffected.
Commits the current preview to the document as an undoable edit named “WaveScale HDR”, with the current three slider values stored as its preset. The dialog does not close afterward — you can switch to another open document and run again with the same (or edited) settings. Reset returns all sliders to their defaults and clears the preview; Close discards everything.
The handle at the bottom-left carries the current three slider values and can be dragged onto the canvas to make a shortcut tile, or dropped onto an image to apply those settings headlessly. Double-clicking the tile reopens this dialog with the settings pre-filled.
All processing on float32. Luminance channel is CIE L* in [0, 100]; RGB channels are in [0, 1]. The pipeline is non-destructive right up to the final mask-blended composite.
End-to-end, Preview runs:
The image's L* channel (0–100) is normalised and raised to the user's gamma to produce a value in [0, 1] per pixel:
With γ = 1 the mask is just the
normalised luminance itself; higher gamma pulls the mask response
toward only the brightest pixels. If the document has an active
mask mdoc, the effective mask used
downstream is their product:
which lets you spatially restrict the HDR effect to any arbitrary shape drawn in a mask layer, on top of the automatic luminance-driven selection.
SASpro uses the classical B3-spline starlet wavelet for luminance decomposition. The analysis kernel is the normalised B3 spline:
applied separably with reflection boundaries. The decomposition
produces n detail planes wi and
one coarse residual cn, reconstructing the
original L* exactly:
Each successive scale is produced by convolving with a
spaced version of the base kernel — zeros inserted
between its coefficients so that scale i captures
features of roughly 2i pixels in extent:
with c0 = L*. The à trous
scheme leaves plane dimensions unchanged (no decimation), which is
what makes a plane-by-plane multiplicative amplification possible
without resampling artefacts.
Each detail plane is multiplied by a per-pixel scale factor
built from the compression C, the mask
meff, and a geometric decay with rate
ρ = 0.5 across scales:
Two things worth unpacking:
ρ = 0.5,
plane 0 (the finest detail) gets the full compression effect
(C−1)·m, plane 1 gets half of that,
plane 2 a quarter, and so on. This concentrates the
amplification on fine detail (where the real recoverable
structure in a glare-washed region tends to live) and leaves
coarse structure comparatively alone.C = 1 or m = 0,
every plane is doubled. This isn't an accident — it's a
deliberate per-plane contrast lift that WaveScale HDR applies
in addition to the compression:
C = 1 isn't a no-op — it's a
uniform detail lift. The mask-and-compression term rides on
top of that baseline to push extra amplification into bright
regions.After amplification, the modified planes and the untouched coarse residual are summed back to a new L*:
Because every plane was multiplied by at least 2, the raw
L' can land well above the original L* in bright
regions. To keep the overall tonal character consistent, SASpro
rescales L' so its median matches the original:
and clips to [0, 100]. The median is used because it's robust against the small handful of pixels that got pushed well past 100 — a mean would be dragged upward by them, defeating the alignment.
Even after midtone alignment, highlights that got boosted hard in the detail planes can still clip against unity. Rather than hard-clip them, SASpro applies a global gamma to the whole RGB output after converting back from Lab:
The dimming exponent scales with the number of wavelet scales
precisely because more scales means more overall amplification across
the pipeline — so with 5 scales g = 2.0,
with 10 scales g = 3.0. Larger g
pulls highlights down harder, keeping the output in range even on
aggressive settings.
The gamma-dimmed output of the pipeline (call it
RGBtransformed) is blended with the original
input through the same mask that drove the amplification:
So dark regions — where meff ≈ 0
— come through from the original untouched, while bright
regions — where meff ≈ 1
— get the full transformed version. The transitions follow
the mask shape, which the user controls via gamma, so you can
confine the effect to arbitrarily narrow ranges of luminance.
The composite is the preview you see in the main view and what gets
written to the document on Apply.
Grayscale and single-channel inputs are promoted to three identical channels for processing (the Lab conversion then produces a nonzero L* and zero a*/b*, which the pipeline handles correctly), and on Apply the result is collapsed back to the original shape — 2-D for 2-D inputs, (H, W, 1) for 1-channel 3-D inputs. The effect on mono data is identical to processing the luminance of an equivalent neutral-grey RGB.
wavelet_utils module. Lab
colour-space conversion follows CIE 1976.
The whole WaveScale HDR algorithm — the per-scale
amplification with geometric decay across scales, the
luminance-raised-to-gamma mask, the baseline-factor-of-2 detail
lift, the median-based midtone realignment, the
scales-dependent automatic dimming gamma, the integration with
the document's active mask, and the final mask-blended composite
— is SASpro-exclusive, designed and implemented by
SetiAstro to solve the glare-decompression problem in bright
astronomical regions.