epdfsuite.utilities

Functions

compute_dqe(flat_paths, dark_paths, mtf_file)

Compute the radially-averaged DQE from flat-field and dark-field images.

compute_mtf_slanted_edge(image_path[, mask, ...])

Compute the MTF using the slanted-edge method, with automatic edge angle and position detection via Hough transform.

deconvolve_mtf_2d(image, mtf_file[, clip, ...])

Wiener 2D MTF deconvolution with optional high-frequency roll-off.

deconvolve_mtf_2d_rl(image, mtf_file[, ...])

Richardson-Lucy 2D deconvolution with a radial MTF.

deconvolve_mtf_dqe_2d(image, mtf_file, dqe_file)

Deconvolve an image using a DQE-weighted Wiener filter.

detect_edge_angle_hough(edge_data[, sigma, ...])

Detect the dominant straight edge in an image using the Hough transform.

draw_mask(dm4_image)

Launch the pyFAI-drawmask GUI to interactively draw a pixel mask.

estimate_wiener_epsilon_spectral(...[, ...])

Estimate the Wiener regularisation parameter epsilon from image data.

extract_noise_and_signal_patches(image, ...)

Extract noise and signal pixel patches on each side of the detected edge.

epdfsuite.utilities.draw_mask(dm4_image)[source]

Launch the pyFAI-drawmask GUI to interactively draw a pixel mask.

The input DM4 image is temporarily exported as an EDF file, passed to the pyFAI-drawmask tool, then the EDF file is deleted. The mask produced by the GUI is saved alongside the image by pyFAI.

Parameters:

dm4_image (str) – Path to the DM4 image file.

epdfsuite.utilities.detect_edge_angle_hough(edge_data, sigma=1, erosion_px=10, num_peaks=5, plot=False)[source]

Detect the dominant straight edge in an image using the Hough transform.

The pipeline is: normalise → erode NaN mask → Canny edge detection → standard Hough transform (0.05° angular resolution) → extract dominant peak.

Parameters:
  • edge_data (ndarray) – 2D image, possibly with NaN pixels marking invalid regions.

  • sigma (float, optional) – Gaussian smoothing sigma passed to the Canny detector. Default is 1. Use 1–2 for quasi-binary (beamstop/background) images.

  • erosion_px (int, optional) – Number of pixels to erode from the border of the valid mask before running Canny, to avoid false edges at mask boundaries. Default is 10.

  • num_peaks (int, optional) – Maximum number of peaks to extract from the Hough accumulator. Only the strongest peak is used. Default is 5.

  • plot (bool, optional) – If True, display diagnostic plots of the masked image, Canny edges, and the Hough accumulator. Default is False.

Returns:

  • line_angle_rad (float) – Angle of the detected edge line with respect to the horizontal, in radians.

  • line_angle_deg (float) – Same angle in degrees.

  • edge_point (tuple of float) – (x, y) coordinates of the point on the line at mid-image height.

  • edge_line (tuple) – (theta, rho, line_angle_deg) — Hough normal angle (rad), signed distance from origin (px), and line angle (deg).

epdfsuite.utilities.compute_mtf_slanted_edge(image_path, mask=None, pixel_size=None, binning_factor=1, roi_half_width=15, nbins=500, smooth_sigma=0.5, use_erf_fit=True, plot=True, outputfile=None)[source]

Compute the MTF using the slanted-edge method, with automatic edge angle and position detection via Hough transform.

Parameters:
  • image_path (str - Path to the image file.)

  • mask (str - Path to a fabio mask file (0=valid, 1=masked).)

  • pixel_size (float - Pixel size in µm.)

  • binning_factor (int - Binning factor applied to the detector (default 1).)

  • roi_half_width (int - Half-width of the band around the edge (pixels).)

  • nbins (int - Number of sub-pixel bins for the ESF.)

  • smooth_sigma (float - Sigma of the Gaussian smoothing applied to the ESF.)

  • use_erf_fit (bool - Fit the ESF with an error function before differentiation.)

  • plot (bool - Display diagnostic plots.)

  • outputfile (str - If provided, save the MTF to this text file.)

Returns:

  • freq_pixel (1D array - Spatial frequencies (cycles/pixel))

  • mtf (1D array - Corresponding MTF values)

epdfsuite.utilities.estimate_wiener_epsilon_spectral(noise_patch, signal_patch, subtract_noise=True)[source]

Estimate the Wiener regularisation parameter epsilon from image data.

Computes epsilon as the square root of the ratio of the mean power spectral densities (PSD) of the noise and signal patches: epsilon = sqrt( <|N(f)|²> / <|S(f)|²> )

This estimate is used to set the noise-to-signal power ratio in the Wiener filter: W(f) = MTF / (MTF² + epsilon²).

Parameters:
  • noise_patch (ndarray) – 2D (or 1D) sub-image extracted from the beamstop region (dark, noisy side).

  • signal_patch (ndarray) – 2D (or 1D) sub-image extracted from the bright background region.

  • subtract_noise (bool, optional) – If True (default), subtract the mean of noise_patch from signal_patch before computing the signal PSD, to account for any DC offset in the background.

Returns:

epsilon (float) – Estimated noise-to-signal PSD ratio, suitable for use as wiener_epsilon in deconvolve_mtf_2d().

epdfsuite.utilities.extract_noise_and_signal_patches(image, edge_line, band_width=500, noise_box=None, erosion_px=5)[source]

Extract noise and signal pixel patches on each side of the detected edge.

The image is split along the Hough line into two regions: - signal patch (bright side, d > +erosion_px): background pixels. - noise patch (dark side, d < -erosion_px): beamstop pixels.

An erosion band of erosion_px pixels around the edge is excluded from both patches to avoid contamination by the edge transition itself. Diagnostic plots are displayed showing the two zones.

Parameters:
  • image (ndarray) – 2D image, with NaN for masked/invalid pixels.

  • edge_line (tuple) – (theta, rho, angle_deg) as returned by detect_edge_angle_hough().

  • band_width (float, optional) – Total width of the extraction band centred on the edge (pixels). Default is 500.

  • noise_box (ignored) – Reserved for future use.

  • erosion_px (int, optional) – Width of the exclusion zone on each side of the edge (pixels). Default is 10.

Returns:

  • signal_patch (ndarray) – 1D array of pixel values from the bright (background) side.

  • noise_patch (ndarray) – 1D array of pixel values from the dark (beamstop) side.

epdfsuite.utilities.deconvolve_mtf_2d(image, mtf_file, clip=True, wiener_epsilon=None, min_epsilon=0.005, pre_smooth_sigma=0.5, use_rolloff=True, u_cutoff=0.4, rolloff_window='tukey', rolloff_alpha=0.5, rolloff_order=4, plot=False)[source]

Wiener 2D MTF deconvolution with optional high-frequency roll-off.

Applies a Wiener filter built from a radially symmetric MTF to restore spatial frequencies attenuated by the detector. An optional roll-off window suppresses noise amplification at high frequencies.

Parameters:
  • image (ndarray) – 2D image to deconvolve.

  • mtf_file (str) – Path to the MTF file (3-column text: freq (cyc/px), MTF, epsilon).

  • clip (bool, optional) – If True (default), clip negative values in the output to zero.

  • wiener_epsilon (float or None, optional) – Regularisation parameter. If None, read from column 3 of mtf_file (floored at min_epsilon).

  • min_epsilon (float, optional) – Minimum allowed epsilon to prevent filter instability. Default is 0.005.

  • pre_smooth_sigma (float, optional) – Sigma (pixels) of Gaussian pre-smoothing applied before deconvolution to reduce Poisson noise amplification. Default is 0.5. Set to 0 to disable.

  • use_rolloff (bool, optional) – If True (default), multiply the Wiener filter by a roll-off window to suppress noise at frequencies above u_cutoff.

  • u_cutoff (float or None, optional) – Roll-off cutoff frequency in cycles/pixel (max 0.5 = Nyquist). If None, automatically set to the frequency where MTF = epsilon. Default is 0.4.

  • rolloff_window ({‘tukey’, ‘hann’, ‘butterworth’}, optional) – Shape of the roll-off window. Default is 'tukey'.

  • rolloff_alpha (float, optional) – For the Tukey window: fraction of the passband that is flat (0 = Hann, 1 = rectangular). Default is 0.5.

  • rolloff_order (int, optional) – For the Butterworth window: filter order (higher = steeper). Default is 4.

  • plot (bool, optional) – If True, display the Wiener filter profile. Default is False.

Returns:

image_deconv (ndarray) – Deconvolved image, same shape as image. NaN pixels are preserved.

epdfsuite.utilities.compute_dqe(flat_paths, dark_paths, mtf_file, gain_reference=None, n_freq=128, plot=False, save=None)[source]

Compute the radially-averaged DQE from flat-field and dark-field images.

The DQE is defined as:

\[\mathrm{DQE}(f) = \frac{\mathrm{MTF}^2(f)}{\bar{n} \cdot \mathrm{NPS}(f)}\]

where \(\bar{n}\) is the mean number of electrons per pixel (signal level) and \(\mathrm{NPS}(f)\) is the normalised noise power spectrum:

\[\mathrm{NPS}(f) = \frac{1}{N_{\mathrm{img}}\, N_x N_y\, \bar{n}^2} \sum_k \left| \mathcal{F}\!\left[ I_k - \bar{I} \right](f) \right|^2\]

The dark-field mean is subtracted from each flat-field image before computing the NPS, so that the detector read-noise is excluded from \(\bar{n}\) but its contribution to the NPS is correctly accounted for.

Parameters:
  • flat_paths (list of str) – Paths to the flat-field (uniform illumination) images. At least 5 images are recommended for a stable NPS estimate; 20–50 are ideal.

  • dark_paths (list of str) – Paths to the dark-field (shutter closed) images. Used to estimate and subtract the detector dark offset.

  • mtf_file (str) – Path to the MTF file (columns: frequency in cyc/px, MTF value), as produced by compute_mtf_slanted_edge().

  • gain_reference (ndarray or None, optional) – 2D gain reference map (same shape as the images). When provided, each flat-field image is divided by gain_reference before computing the NPS to correct for pixel-to-pixel sensitivity variations. None skips gain correction. Default is None.

  • n_freq (int, optional) – Number of radial frequency bins for the azimuthal average. Default is 128.

  • plot (bool, optional) – If True, display MTF², NPS, and DQE curves. Default is False.

  • save (str or None, optional) – If a file path is given, save the result as a two-column text file (frequency in cyc/px, DQE value) readable by deconvolve_mtf_2d_rl(). Default is None.

Returns:

  • freq_bins (ndarray, shape (n_freq,)) – Radial frequency axis in cycles/pixel (0 to 0.5).

  • dqe (ndarray, shape (n_freq,)) – Radially-averaged DQE, values in [0, 1].

Notes

  • All images must have the same shape.

  • Images are expected to be in raw detector counts (electrons or ADU).

  • At very low dose the DQE drops because read noise dominates; at very high dose it drops due to detector non-linearity. Run this function at several dose levels to characterise the dose dependence.

epdfsuite.utilities.deconvolve_mtf_dqe_2d(image, mtf_file, dqe_file)[source]

Deconvolve an image using a DQE-weighted Wiener filter.

This is a simplified version of deconvolve_mtf_2d() that applies the DQE weighting directly to the Wiener filter without pre-smoothing or roll-off. The filter is:

\[W(f) = \frac{\mathrm{DQE}(f)}{\mathrm{MTF}(f)}\]
Parameters
imagendarray

2D image to deconvolve.

mtf_filestr

Path to the MTF file (columns: frequency in cyc/px, MTF value, epsilon).

dqe_filestr

Path to the DQE file (columns: frequency in cyc/px, DQE value).

image_deconvndarray

Deconvolved image, same shape as image. NaN pixels are preserved.

epdfsuite.utilities.deconvolve_mtf_2d_rl(image, mtf_file, clip=True, n_iterations=50, tol=0.01, dqe_file=None, pre_smooth_sigma=0, verbose=False, plot=False)[source]

Richardson-Lucy 2D deconvolution with a radial MTF.

Suited to Poisson noise (electron/photon counting). Regularisation is implicit: too few iterations under-deconvolves; too many amplify noise.

The stopping criterion is the relative change of the current estimate u:

\[\text{rel} = \frac{\|u^{(k+1)} - u^{(k)}\|_\infty}{\|u^{(k)}\|_\infty} < \text{tol}\]

DQE-weighted correction (optional)

When dqe_file is provided, the back-projection step is weighted by the 2D DQE map instead of the plain MTF conjugate:

\[u^{(k+1)} = u^{(k)} \cdot \mathcal{F}^{-1}\!\left[ \mathrm{DQE}(f)\, H(f)\, \mathcal{F}\!\left[\frac{I}{h \circledast u^{(k)}}\right] \right]\]

where \(\mathrm{DQE}(f) = \mathrm{MTF}^2(f) / (\bar{n}\,\mathrm{NPS}(f))\). Frequencies where \(\mathrm{DQE}(f) \approx 0\) (noise-dominated) are naturally suppressed at every iteration, making the algorithm less sensitive to the choice of n_iterations and removing the need for pre_smooth_sigma in most cases.

Without dqe_file the standard R-L update is used and regularisation relies entirely on early stopping via tol and n_iterations.

Parameters:
  • image (ndarray) – 2D image to deconvolve.

  • mtf_file (str) – Path to the MTF file (columns: frequency in cyc/px, MTF value).

  • clip (bool, optional) – If True, clamp negative values to 0 after each iteration. Default is True.

  • n_iterations (int, optional) – Maximum number of iterations (safety cap). Default is 50.

  • tol (float or None, optional) – Early-stopping threshold on the relative change ||Δu||/||u||. None disables early stopping. Default is 1e-2.

  • dqe_file (str or None, optional) – Path to the DQE file (same format as mtf_file: columns are frequency in cyc/px and DQE value in [0, 1]). When provided, the correction at each iteration is weighted by the 2D DQE map, which suppresses noise-dominated frequencies without requiring aggressive early stopping or pre-smoothing. None disables DQE weighting and reproduces the standard R-L behaviour. Default is None.

  • pre_smooth_sigma (float, optional) – Standard deviation (pixels) for Gaussian pre-smoothing applied before deconvolution. 0 disables smoothing. Default is 0.

  • verbose (bool, optional) – If True, print the relative change at each iteration. Default is False.

  • plot (bool, optional) – If True, display the PSF profile. Default is False.

Returns:

image_deconv (ndarray) – Deconvolved 2D image.