stdpipe.fringe_removal module

Fringe removal for astronomical images.

The main routine, remove_fringes(), models the fringe pattern as a smooth two-dimensional field at intermediate spatial scales (between stellar FWHM and the coarse sky background) and estimates it directly in image space: sources are masked, and the masked pixels are transparently “inpainted” by NaN-aware Gaussian smoothing, so the fringe structure is continued under the stars. This works for realistic curved, non-stationary fringes where frequency-domain methods fail.

The module also provides Fourier notch filtering (remove_fringes_fourier()) for genuinely periodic patterns such as electronic pickup noise, and visualize_fourier_spectrum() for diagnostics.

stdpipe.fringe_removal.remove_fringes(image, mask=None, scale='auto', noise_frac=0.25, bg_size=256, threshold=2.0, dilate=2, iterations=3, halo_sn=20.0, get_fringe_model=False, verbose=False)[source]

Remove fringes by estimating a smooth intermediate-scale background map with sources masked and inpainted.

The algorithm exploits the scale separation between stars (~FWHM, a few pixels), fringes (tens of pixels) and the sky background (hundreds of pixels):

  1. Subtract a coarse sky background (SEP mesh of bg_size pixels)

  2. Around bright stars (peaks above halo_sn sigmas with footprints wider than the smoothing kernel), model the non-monotone azimuthally symmetric circumstellar structure - ghost reflection rings, background estimation bowls - as azimuthal-median radial profiles with their smooth monotone envelope (the stellar wings and halo) removed, and subtract it from the working residual. This captures circular artifacts with full circular fidelity, which isotropic smoothing cannot do

  3. Mask pixels deviating by more than threshold sigma (sources and outliers), grow the mask by dilate pixels

  4. Smooth the masked residual with a Gaussian of sigma scale pixels using mask-aware normalized convolution - masked pixels are filled by the weighted average of the surrounding fringe structure (inpainting), each region by the finest scale of a multi-scale ladder that still has unmasked support there. The smoothing also absorbs the smooth sub-threshold envelope of stellar halos and wings

  5. Iterate: re-mask on the fringe-subtracted residual (so that fringe crests are not mistaken for sources), smooth it again and add to the fringe map. The additive refinement also recovers the part of the fringe structure attenuated by the smoothing, so narrower fringes are progressively captured with each iteration

The radial circumstellar fields are included in the returned fringe map and thus subtracted from the image along with the fringes.

The resulting fringe map is defined everywhere, including under the stars, and is subtracted from the original image. The coarse sky background is left in the image.

Parameters:
imagendarray

Input image

maskndarray, optional

Boolean mask (True = masked pixels to exclude from fringe estimation)

scalefloat or ‘auto’

Sigma of the Gaussian smoothing kernel in pixels. Should be of order the stellar FWHM or somewhat larger, and well below the narrowest fringe period. Smaller values track narrower fringes at the cost of slightly more noise and source flux absorbed into the map. If 'auto' (default), the scale is selected from the measured fringe-to-noise ratio (6 px for strong, sharp fringes up to a few tens of px for faint, broad ones), so that noise does not leak into the fringe model. Pass a number to set it explicitly.

noise_fracfloat

Aggressiveness of the automatic scale selection (used only when scale='auto'). The smallest scale whose predicted noise floor falls below noise_frac times the fringe amplitude is chosen. Smaller values give cleaner (less noisy) models but larger kernels, which can over-smooth very faint, broad fringes; larger values keep smaller kernels at the cost of more noise in the model. Default: 0.25

bg_sizeint or None

Mesh size in pixels for the coarse sky background subtracted before fringe estimation. Should be much larger than the fringe scale. If None, the global median is used instead. Default: 256

thresholdfloat

Source masking threshold in sigmas of the local background RMS. Applied symmetrically (both positive and negative outliers are masked) to avoid biasing the fringe map. Default: 2.0

dilateint

Number of binary dilation iterations applied to the source mask to cover the wings of the sources. Default: 2

iterationsint

Number of refinement iterations. Each iteration re-derives the source mask from the fringe-subtracted residual (the first one has to mask on the raw residual where fringe crests may exceed the threshold) and accumulates the smoothed residual into the fringe map. More iterations capture narrower fringes but absorb more noise. Default: 3

halo_snfloat or None

Peak significance (in sigmas) above which a source is considered bright enough to have halos and gets the radial halo treatment. Should be well above the peak significance of the fringe crests. Only sources whose thresholded footprint radius also exceeds scale are treated (ordinary stars have compact footprints and are not affected). None disables the halo modeling. Default: 20

get_fringe_modelbool

If True, return (corrected_image, fringe_model). Default: False

verbosebool or callable

Whether to show verbose messages during the run. May be either boolean, or a print-like function.

Returns:
corrected_imagendarray

Image with the fringe map subtracted

fringe_modelndarray, optional

The subtracted fringe map (if get_fringe_model=True)

Notes

Circumstellar structures - halos, ghost rings, background bowls - are locally indistinguishable from fringes (smooth structures at similar scales). The smooth ones are absorbed by the masked multi-scale smoothing along with the fringes; sharply circular ones (ghost donuts, bowls) are additionally captured with full circular fidelity by azimuthal-median radial profiles around bright stars (the halo_sn mechanism), which average the oscillating fringes passing through to nearly zero. Everything smooth or circular around bright stars is thus subtracted, including the sub-threshold part of their PSF wings; the star cores and everything above the masking threshold stay in the image. Use halo_sn=None to disable the radial modeling (isotropic smoothing only).

Faint extended sources (low surface brightness galaxies, nebulae) whose peaks stay below halo_sn remain partially degenerate with the fringe pattern: the part below the masking threshold gets absorbed into the fringe map and over-subtracted. For fields dominated by such sources, lower halo_sn, increase scale, or mask the sources explicitly via the mask argument.

Examples

>>> corrected = remove_fringes(image, mask=mask, scale=6)
>>> corrected, fringes = remove_fringes(image, get_fringe_model=True)
stdpipe.fringe_removal.remove_fringes_fourier(image, mask=None, fwhm=None, method='global', period_range=(30, 200), sigma_threshold=2.0, notch_width=3.0, protect_low_freq=True, protect_high_freq=True, get_fringe_model=False, verbose=False)[source]

Remove periodic patterns from image using Fourier notch filtering.

Suitable for genuinely periodic, stationary patterns (electronic pickup noise, readout banding) that produce sharp peaks in Fourier space. Realistic sky fringes are usually curved and non-stationary, with power spread over a broad frequency annulus - use remove_fringes() for those instead.

Parameters:
imagendarray

Input image

maskndarray, optional

Boolean mask (True = masked pixels to exclude from analysis)

fwhmfloat, optional

Stellar FWHM (pixels) for protecting high-frequency stellar content. If None, no high-frequency protection is applied.

methodstr

Pattern removal method:

  • ‘global’: Detect and notch out power spectrum peaks (default)

  • ‘bandpass’: Suppress a whole frequency range given by period_range

period_rangetuple

Expected pattern period range (min, max) in pixels. Default: (30, 200)

sigma_thresholdfloat

Threshold for automatic peak detection (in sigma above median power). Higher = more conservative. Default: 2.0

notch_widthfloat

Width of notch filter in frequency pixels. Larger = more aggressive. Default: 3.0

protect_low_freqbool

If True, don’t filter very low frequencies (large-scale background). Default: True

protect_high_freqbool

If True, protect high frequencies based on stellar FWHM. Requires fwhm. Default: True

get_fringe_modelbool

If True, return (corrected_image, fringe_model). Default: False

verbosebool or callable

Print diagnostic information

Returns:
corrected_imagendarray

Image with the periodic pattern removed

fringe_modelndarray, optional

Removed pattern (if get_fringe_model=True)

Examples

>>> # Automatic peak detection and notching
>>> corrected = remove_fringes_fourier(image, fwhm=3.0)
>>> # Bandpass filtering for known period range
>>> corrected = remove_fringes_fourier(
...     image, method='bandpass', period_range=(50, 150), fwhm=3.0)
stdpipe.fringe_removal.detect_fringe_peaks_fft(image, mask=None, sigma_threshold=5.0, period_range=(30, 200), fwhm=None, protect_low_freq=True, protect_high_freq=True, verbose=False)[source]

Detect peaks in the Fourier power spectrum corresponding to periodic patterns (e.g. electronic pickup noise).

Note that realistic sky fringes are usually not periodic - their power is spread over a broad annulus in frequency space with no distinct peaks. Use remove_fringes() for those.

Parameters:
imagendarray

Input image

maskndarray, optional

Boolean mask (True = masked pixels)

sigma_thresholdfloat

Detection threshold in sigma above median power

period_rangetuple

(min_period, max_period) in pixels

fwhmfloat, optional

Stellar FWHM for protecting high frequencies

protect_low_freqbool

Exclude very low frequencies (large-scale background)

protect_high_freqbool

Exclude high frequencies (stellar content); requires fwhm

verbosebool

Print diagnostic information

Returns:
peakslist of tuples

List of (fy, fx, period) peak positions in Fourier space (pixel offsets relative to the spectrum center) and the corresponding spatial period in pixels

stdpipe.fringe_removal.create_notch_filter(shape, peaks, width=3.0, smooth=True)[source]

Create notch filter to suppress specific Fourier peaks.

Parameters:
shapetuple

Image shape (ny, nx)

peakslist of tuples

Peak positions [(fy1, fx1), (fy2, fx2), …] or [(fy1, fx1, period1), …]

widthfloat

Notch width in frequency pixels

smoothbool

If True, use Gaussian notch; if False, use hard cutoff

Returns:
filterndarray

2D filter mask (1 = pass, 0 = suppress)

stdpipe.fringe_removal.create_bandpass_filter(shape, period_range, smooth=True)[source]

Create band-stop (notch) filter to suppress specific period range.

This is actually a band-STOP filter that suppresses frequencies corresponding to the given period range while passing others.

Parameters:
shapetuple

Image shape (ny, nx)

period_rangetuple

(min_period, max_period) in pixels to SUPPRESS

smoothbool

If True, use smooth Gaussian rolloff; if False, hard cutoff

Returns:
filterndarray

2D band-stop filter (1 = pass, 0 = suppress, smooth transition if smooth=True)

stdpipe.fringe_removal.visualize_fourier_spectrum(image, peaks=None, period_range=None, fwhm=None, log_scale=True, vmax_percentile=99.9, save_path=None)[source]

Visualize 2D Fourier power spectrum with detected peaks.

Useful for debugging and parameter tuning.

Parameters:
imagendarray

Input image

peakslist of tuples, optional

Detected peak positions [(fy, fx), …]

period_rangetuple, optional

If provided, overlay search region

fwhmfloat, optional

If provided, overlay high-frequency protection boundary

log_scalebool

Use log scale for power spectrum

vmax_percentilefloat

Percentile for color scale maximum

save_pathstr, optional

If provided, save plot to this path

Returns:
figmatplotlib.figure.Figure

The figure object