Three healing tools in one interactive dialog. The Blemish Blaster fixes round defects (dust motes, bad pixels, satellite flashes, residual stars after StarNet) with a one-click median-of-median heal. Linear Blaster paints out straight or bent line defects (satellite trails, cosmic rays, airplane trails) with a draggable path. Banding Blaster suppresses horizontal or vertical row/column banding across the entire frame.
Three radio buttons at the top of the controls panel choose the active mode. Switching modes resets any in-progress linear path and hides the controls that don't apply, so the panel stays uncluttered. The preview on the right responds differently in each mode — hover-and-click in Blemish, click-and-drag path building in Linear, pan-only in Banding (because banding operates on the whole frame at once).
Three toolbuttons at the top of the left pane: Zoom Out, Zoom In, Fit to Preview. Mouse-wheel and trackpad gestures also zoom with the cursor as the anchor — small trackpad swipes give fine control, click-wheel detents give coarse, hold Ctrl to zoom faster in either case. Zoom range is 0.05× to 4×. The first time the dialog opens the preview is auto-fit to its viewport; after that your zoom and pan state is preserved across mode switches.
These three sliders are shared by Blemish and Linear modes (Banding uses its own set). Each has a live numeric spinbox alongside the slider that stays in sync.
Below the mode-specific controls. When on (default), a statistical stretch is applied to the preview only — the underlying image data is never modified by this control. Essential when working on linear data where a dust mote would otherwise be invisible.
The in-dialog undo/redo ring holds the last 20 operations. Each blemish heal snapshots only its affected patch; linear and banding operations snapshot the whole image (since a line can span the frame and banding touches every pixel). Ctrl+Z and Ctrl+Y are intercepted inside the dialog so they don't trigger the main window's own undo — the dialog wins whenever it has focus.
Apply to Document commits the current working image back to the originating document as a single undoable edit named “Blemish Blaster” (whichever modes were used during the session), then closes the dialog. Close discards everything. The dialog's window geometry is saved per-user and restored on next open.
[ and ] decrease or increase the brush radius by 2 pixels at a time, and the preview circle updates immediately under the current cursor position. Standard for digital-brush tools; indispensable for working through a frame with mixed defect sizes without reaching for the slider.
Default mode. The classical SetiAstro one-click heal.
Set the radius just slightly larger than the defect itself (not larger than the defect plus its surroundings — the healer samples the surroundings, so leave them visible). Feather around 50% hides the transition on most backgrounds. Click once; if the result looks off, undo and try at a different radius or offset the click a few pixels to pick a different hex arrangement of sampling patches. The algorithm itself is described in § 6.1.
Draws a path that gets stroked at the current Thickness with rounded caps, and healed by sampling parallel offsets on either side. The path can be straight or bent as a quadratic Bézier, and can optionally extend all the way to the image borders.
The ⚡ Blast Line button is enabled once both endpoints are placed. Pressing it dispatches the linear worker (algorithm in § 6.2) and clears the path once the heal completes. The undo ring records the entire pre-blast image so a full undo always works.
Row- or column-banding reducer for Canon DSLRs (horizontal) and some CMOS sensors with column banding (vertical). This mode does not use the preview-click interface — the correction runs on the entire frame at once with a single button press. The preview switches to scroll-hand drag so you can pan to inspect the result, but clicking does nothing until you switch back to Blemish or Linear.
Horizontal (default) or Vertical. Horizontal targets rows — the common Canon DSLR pattern. Vertical targets columns — some CMOS astro cameras exhibit column banding especially on long exposures. Internally, vertical is implemented as a transpose + horizontal + un-transpose, so the algorithm is bit-identical in either direction.
0.00–4.00 spinbox, default 1.00. The strength of the correction, as a multiplier on the per-row median offset.
Protect highlights (checkbox, default on) excludes bright pixels from the per-row median so stars and DSO cores don't bias the correction. Essential for astronomical images and the only reason this tool works at all on a Milky Way frame or a nebula field. When off, the sigma control is disabled.
Sigma (0.01–5.00, default 1.00) is the rejection threshold above the global median, in robust-sigma units (§ 6.3). Lower is more aggressive. 1.0 keeps roughly 80% of a smooth background in the row-median estimate; drop to 0.3–0.5 on very star-dense fields.
The ⚡ Blast Banding button runs the correction and pushes the result into the preview and the dialog's undo stack as a whole-image patch. Undoable like any other operation.
All processing on float32 [0, 1]. The dialog displays a 3-channel copy of the working image regardless of source depth; on Apply, mono originals are collapsed back to a single plane.
For a click at pixel p = (x, y) and
brush radius r, six candidate neighbour centres are
placed on a hexagon at 1.5× the radius:
The median brightness is computed inside the circular mask of
radius r at the target position and at each of the six
candidates. The three candidates whose medians are closest to the
target's are selected:
For every pixel q inside the brush, the healed value
is the median of three samples at the matching offsets:
This two-level median (medians across patches to pick, then median across the three samples to synthesise) is what gives the heal its resistance to local features. A bright star in one neighbour patch would be flagged by its high median and excluded at the pick step; and even if a bright pixel slips through, the per-pixel median across three samples throws it out. The “match the median” pick is also what makes the heal look seamless on gradients — it automatically prefers neighbours of the same local brightness level as the defect's own surroundings.
The feathered mask is built from the Euclidean distance
d from the brush centre, inside the circular support
d ≤ r:
where f is the feather fraction. At
f = 0 the mask is a hard disk; at
f = 1 it ramps linearly from the centre.
The final blend uses the opacity slider as a scaling factor on this
weight:
Sample positions that would fall outside the image are REPLICATE-clipped to the nearest in-bounds pixel — a blemish near the edge still gets corrected, using the border rather than being skipped.
Per-click the operation is tiled to the bounding box
[x ± r, y ± r]
and runs on a background thread so the GUI stays responsive during
larger brushes.
The user's path (two endpoints and an optional bend handle) is
converted into a sequence of straight sub-segments. When bent, the
path is a quadratic Bézier through endpoints
A, B and a control point computed so the
curve passes through the user's handle m at
t = 0.5:
The curve is discretised into
n = clip(arclen/24, 4, 64)
vertices; each pair of consecutive vertices becomes a straight
sub-segment with its own local tangent. Full-line mode adds two more
sub-segments: a ray from A along −end-tangent
to the image border, and a ray from B along the far
end-tangent to the border.
Each sub-segment is healed in its own local frame of orthonormal
coordinates (ŵ, ń) along and perpendicular
to the segment:
Caps are rounded at true endpoints (first/last sub-segment under Segment mode); joints between internal sub-segments are flat and overlap each other by half the thickness so the stroke doesn't seam visibly along a bent path.
Within each sub-segment, SASpro samples the target band and six
offset slabs at ±T, ±2T,
±3T perpendicular to the segment (via
cv2.remap with reflect border). For each column
t, the three offset slabs whose medians most closely
match the target column's median are selected and used as the heal
source — the same two-level median idea as the blemish mode,
but applied column-wise along the segment so a curved path can heal
differently at each t.
The feather/opacity blend is identical to § 6.1 using
|s|/T as the distance variable instead of radial
d. When sub-segments overlap at joints, a
“keep-strongest” rule writes to the output only where
the current sub-segment's α exceeds whatever a previous
sub-segment already wrote — so the heal doesn't double-blend
along the join line.
Vertical banding is handled by transposing the array, running the horizontal algorithm, then transposing back. The horizontal algorithm operates per channel and per row.
Let g be the channel's global median and
I the full channel. The robust background sigma uses
mean (not median) of absolutes to match Georg's original script
bit-for-bit:
With Protect highlights on, the per-row median is computed over only those pixels at or below a threshold:
Rows with no pixels at or below the threshold fall back to
g (which makes fixr = 0
for those rows). The correction and application are:
Which is to say: each row is additively shifted so its surviving (dim) pixels sit at the global median, scaled by the amount slider. Rows whose medians already match the global sit still; rows that are anomalously dim or bright get pulled back by the same amount end-to-end, which is exactly the right fix for a readout-induced constant offset per row.
The naive implementation of
median(row where row ≤ threshold)
is np.nanmedian on a masked copy. SASpro ports Georg's
JS code to a vectorised numpy formulation that is 4–7×
faster on typical astro-image sizes while producing bit-identical
results: for each row count the survivors
nr = |{c : Ir,c ≤ threshold}|,
sort every row ascending (so survivors occupy positions
[0, nr)), and index out the median
positionally with an odd/even case split.
Purely display-side. On every image refresh, if the checkbox is on,
the working image is passed through
stretch_mono_image (for original mono source) or
stretch_color_image (for RGB) with the Target Median and
Linked settings. The result goes into a separate display buffer; the
working image used by the healers is never touched.
Each operation records a tuple
(y0, x0, prev) where
prev is a copy of the pre-op image bytes in the affected
rectangle. For blemish heals this is just the brush bounding box
plus the 1.5r sampling padding; for linear and banding it's the
whole image. Undo swaps the current pixels in that rectangle with
the saved copy and pushes the forward-direction patch into the redo
ring; redo is the mirror operation. The ring is bounded at 20 entries
to cap peak memory.
cv2.remap) are SetiAstro's own designs and
implementation, originally for SetiAstro Suite v2 and extended for
SASpro.