toupy.resolution package

Submodules

toupy.resolution.FSC module

FOURIER SHELL CORRELATION modules (optimized)

class toupy.resolution.FSC.FRCPlot(img1, img2, threshold='halfbit', ring_thick=1, apod_width=20, pixel_size=1.0)[source]

Bases: FSCPlot

Fourier Ring Correlation (FRC) — the 2-D analogue of the FSC.

Identical to FSCPlot but enforces two-dimensional input and uses “FRC” in all labels and output filenames. FRC is standard in cryo-EM and increasingly used in X-ray ptychography and nano-tomography.

Parameters:
  • img1 (ndarray) – A 2-dimensional array containing the first image.

  • img2 (ndarray) – A 2-dimensional array containing the second image.

  • threshold (str, optional) – 'halfbit' (default) or 'onebit'.

  • ring_thick (int, optional) – Ring thickness in pixels. Default 1.

  • apod_width (int, optional) – Apodization width in pixels. Default 20.

Returns:

  • fn (ndarray) – Spatial frequencies normalised by the Nyquist frequency.

  • FRC (ndarray) – Fourier Ring Correlation curve.

  • T (ndarray) – Threshold curve.

Raises:

ValueError – If either input image is not 2-dimensional.

Notes

The mathematical definition and threshold criteria are identical to the FSC; only the geometry changes (rings in 2-D vs shells in 3-D).

References

plot()[source]

Plot the FRC and threshold curves and return the underlying data.

Returns:

  • fn (ndarray) – Spatial frequencies normalised by the Nyquist frequency.

  • T (ndarray) – Threshold curve (half-bit or one-bit).

  • FRC (ndarray) – Fourier Ring Correlation curve (real part).

  • fn_res_cpx (float or None) – Resolution crossing frequency in cycles/pixel. Use resolution_full or resolution_half for results already converted to physical units. None if FRC never exceeds the threshold.

class toupy.resolution.FSC.FSCPlot(img1, img2, threshold='halfbit', ring_thick=1, apod_width=20, pixel_size=1.0)[source]

Bases: FourierShellCorr

Upper level object to plot the FSC and threshold curves

Parameters:
  • img1 (ndarray) – A 2-dimensional array containing the first image

  • img2 (ndarray) – A 2-dimensional array containing the second image

  • threshold (str, optional) – The option onebit means 1 bit threshold with SNRt = 0.5, which should be used for two independent measurements. The option halfbit means 1/2 bit threshold with SNRt = 0.2071, which should be use for split tomogram. The default option is half-bit.

  • ring_thick (int, optional) – Thickness of the frequency rings. Normally the pixels get assined to the closest integer pixel ring in Fourier Domain. With ring_thick, each ring gets more pixels and more statistics. The default value is 1.

  • apod_width (int, optional) – Width in pixel of the edges apodization. It applies a Hanning window of the size of the data to the data before the Fourier transform calculations to attenuate the border effects. The default value is 20.

  • pixel_size (float, optional) – Physical size of one pixel/voxel in any consistent unit (e.g. metres, nanometres). Used to compute resolution_full and resolution_half in physical units. Default 1.0 (result in pixels).

fn_res

Resolution crossing as a fraction of the Nyquist frequency (dimensionless, range [0, 1]). None if FSC never exceeds the threshold.

Type:

float or None

fn_res_cpx

Resolution crossing frequency in cycles/pixel (fn_res * 0.5). None if FSC never exceeds the threshold.

Type:

float or None

resolution_full

Full-period resolution in physical units (van Heel / FSC convention): pixel_size / fn_res_cpx. This is the spatial period of the finest resolvable grating — the standard quantity reported in FSC analyses. None if FSC never exceeds the threshold.

Type:

float or None

resolution_half

Half-period resolution in physical units (Rayleigh / feature-size convention): resolution_full / 2. This equals the smallest resolvable feature size and is the quantity most often reported in optical microscopy. None if FSC never exceeds the threshold.

Type:

float or None

Returns:

  • fn (ndarray) – A 1-dimensional array containing the frequencies normalized by the Nyquist frequency

  • FSC (ndarray) – A 1-dimensional array containing the Fourier Shell correlation curve

  • T (ndarray) – A 1-dimensional array containing the threshold curve

plot()[source]

Plot the FSC and threshold curves and return the underlying data.

Delegates the actual plotting to show_fsc_curve().

Returns:

  • fn (ndarray) – Spatial frequencies normalised by the Nyquist frequency (range [0, 1]).

  • T (ndarray) – Threshold curve (half-bit or one-bit).

  • FSC (ndarray) – Real part of the Fourier Shell Correlation values.

  • fn_res_cpx (float or None) – Resolution crossing frequency in cycles/pixel. Use resolution_full or resolution_half for results already converted to physical units. None if FSC never exceeds the threshold.

class toupy.resolution.FSC.FourierShellCorr(img1, img2, threshold='halfbit', ring_thick=1, apod_width=20)[source]

Bases: object

Computes the Fourier Shell Correlation [1]_ between image1 and image2, and estimate the resolution based on the threshold funcion T of 1 or 1/2 bit.

Parameters:
  • img1 (ndarray) – A 2-dimensional array containing the first image

  • img2 (ndarray) – A 2-dimensional array containing the second image

  • threshold (str, optional) – The option onebit means 1 bit threshold with SNRt = 0.5, which should be used for two independent measurements. The option halfbit means 1/2 bit threshold with SNRt = 0.2071, which should be use for split tomogram. The default option is half-bit.

  • ring_thick (int, optional) – Thickness of the frequency rings. Normally the pixels get assined to the closest integer pixel ring in Fourier Domain. With ring_thick, each ring gets more pixels and more statistics. The default value is 1.

  • apod_width (int, optional) – Width in pixel of the edges apodization. It applies a Hanning window of the size of the data to the data before the Fourier transform calculations to attenuate the border effects. The default value is 20.

Returns:

  • FSC (ndarray) – Fourier Shell correlation curve

  • T (ndarray) – Threshold curve

Notes

If 3D images, the first axis is the number of slices, ie., [slices, rows, cols]

References

apodization()[source]

Compute a Hanning apodization window matching the image dimensions.

The 3-D window is built via an einsum outer product instead of nested list-comprehensions, reducing memory allocations and Python overhead.

Returns:

window – Hanning window array of shape (nr, nc) for 2-D images or (ns, nr, nc) for 3-D volumes.

Return type:

ndarray

circle()[source]

Create a circular mask with apodized (cosine-tapered) edges.

Returns:

t – 2-D mask that is 1 inside the central circle, smoothly tapered to 0 over apod_width pixels at the edges.

Return type:

ndarray, shape (nr, nc)

fouriercorr()[source]

Compute the Fourier Shell Correlation (FSC) and its threshold curve.

Optimizations applied:

  • 3-D apodization window assembled with broadcasting instead of nested list-comprehensions and swapaxes calls.

  • Ring-shell loop: boolean mask computed once per shell and reused for both F1 and F2 extractions, halving the number of np.where calls.

  • np.where replaced by direct boolean indexing.

  • Cross/auto-correlation sums use np.dot on flat views, which is faster than .sum() on fancy-indexed complex arrays for large rings.

Returns:

  • FSC (ndarray, shape (n_shells,)) – Fourier Shell Correlation values for each frequency shell.

  • T (ndarray, shape (n_shells,)) – Threshold curve (half-bit or one-bit) for each frequency shell.

nyquist()[source]

Evaluate the Nyquist frequency and the corresponding frequency array.

The Nyquist ring index is nmax // 2 (integer division), where nmax is the largest image dimension. For an even-length DFT of size N the highest unambiguous positive-frequency bin is exactly N/2, so integer division gives the correct result for both even and odd N.

Returns:

  • f (ndarray of int32) – Integer ring indices from 0 (DC) to fnyquist (inclusive).

  • fnyquist (int) – Ring index of the Nyquist frequency (nmax // 2).

ringthickness()[source]

Compute the shell index for each voxel in Fourier space.

Each dimension’s frequency axis is built with scipy.fft.fftfreq (which returns values in cycles/pixel, already in FFT layout) and then scaled so that every dimension’s Nyquist maps to the global Nyquist ring index nmax // 2. This is equivalent to the previous manual construction ifftshift(np.arange(-fix(n/2), ceil(n/2))) * (nmax//2) / (n//2) but requires no ifftshift, np.fix, or np.ceil calls.

Uses broadcasting instead of np.meshgrid to avoid large temporary arrays.

Returns:

index – Array of the same shape as the input image containing the integer shell index (rounded radius in scaled Fourier pixels) for each voxel.

Return type:

ndarray of int32

ssnr()[source]

Compute the Spectral Signal-to-Noise Ratio (SSNR) from the FSC curve.

The SSNR is a direct transformation of the FSC:

\[\mathrm{SSNR}(r) = \frac{2 \cdot \mathrm{FSC}(r)}{1 - \mathrm{FSC}(r)}\]

SSNR > 1 indicates signal-dominated shells; SSNR = 1 corresponds to the resolution limit. This method calls fouriercorr() internally if the FSC has not already been computed.

Returns:

  • f (ndarray) – Integer shell indices (same as nyquist()).

  • fnyquist (float) – Nyquist frequency (in pixels).

  • FSC (ndarray) – Fourier Shell Correlation curve.

  • SSNR (ndarray) – Spectral Signal-to-Noise Ratio as a function of spatial frequency.

References

transverse_apodization()[source]

Compute a tapered Hanning-like (Tukey) apodization window.

The 1-D window construction is delegated to _make_1d_tukey() to avoid duplication. The 3-D window is assembled with broadcasting instead of per-column list-comprehensions with swapaxes calls.

Returns:

window – For 2-D images: a single 2-D window array of shape (nr, nc). For 3-D volumes: a list [outer(w_row, w_col), outer(w_sli, w_col)] matching the original API expected by fouriercorr().

Return type:

ndarray or list of ndarray

class toupy.resolution.FSC.LocalFSC(vol1, vol2, pixel_size=1.0, box_size=32, step=None, threshold=0.143)[source]

Bases: object

Local resolution estimation via block-wise FSC (3-D) or FRC (2-D).

Divides the volume into overlapping boxes, computes an independent Fourier Shell/Ring Correlation within each box, and assembles a spatial map of local resolution interpolated to the input shape.

Parameters:
  • vol1 (ndarray) – First independent half-reconstruction (2-D or 3-D).

  • vol2 (ndarray) – Second independent half-reconstruction, same shape as vol1.

  • pixel_size (float, optional) – Physical voxel size (any consistent unit). Default 1.0.

  • box_size (int, optional) – Side length (in voxels) of the cubic (or square) analysis box. Smaller boxes give finer spatial sampling but noisier estimates. Default 32.

  • step (int or None, optional) – Step size in voxels between adjacent box centres. Default box_size // 2 (50 % overlap).

  • threshold (float, optional) – FSC/FRC threshold used to define the local resolution limit. Default 0.143 (half-bit criterion).

resolution_map

Local full-period resolution in pixels (van Heel convention), same shape as vol1.

Type:

ndarray

resolution_map_phys

Local full-period resolution in physical units (resolution_map * pixel_size).

Type:

ndarray

resolution_map_half

Local half-period resolution in pixels (Rayleigh convention): resolution_map / 2.

Type:

ndarray

resolution_map_phys_half

Local half-period resolution in physical units: resolution_map_phys / 2.

Type:

ndarray

resolution_median

Median full-period local resolution in pixels.

Type:

float

resolution_mean

Mean full-period local resolution in pixels.

Type:

float

resolution_std

Standard deviation of full-period local resolution in pixels.

Type:

float

resolution_median_half

Median half-period local resolution in pixels.

Type:

float

resolution_mean_half

Mean half-period local resolution in pixels.

Type:

float

resolution_std_half

Standard deviation of half-period local resolution in pixels.

Type:

float

plot(slice_idx=None, axis=0, cmap='viridis_r', vmin=None, vmax=None)[source]

Display the local resolution map and save it to LocalFSC_resmap.png.

For 3-D volumes the central slice (or the slice specified by slice_idx) along axis is shown. The colour bar is in pixels.

Parameters:
  • slice_idx (int or None, optional) – Slice index along axis to display. Defaults to the central slice. Ignored for 2-D input.

  • axis (int, optional) – Volume axis along which to slice. Default 0.

  • cmap (str, optional) – Matplotlib colourmap. Default 'viridis_r'.

  • vmin (float or None, optional) – Lower colour-scale limit. None uses the data minimum.

  • vmax (float or None, optional) – Upper colour-scale limit. None uses the data maximum.

Returns:

resolution_map – The full local-resolution map (same shape as the input volume).

Return type:

ndarray

class toupy.resolution.FSC.RandomFSC(img1, img2, threshold='halfbit', ring_thick=1, apod_width=20, fsc_cutoff=0.8, random_seed=None, pixel_size=1.0)[source]

Bases: FourierShellCorr

Phase-randomization test for FSC validation (Chen et al., 2013).

After computing the standard FSC, the Fourier phases of both half-volumes are independently randomized above a chosen spatial frequency *f*_cutoff (the shell where FSC_obs first drops below fsc_cutoff). The FSC computed from the two phase-randomized volumes (FSC_rand) is the noise floor expected from model bias or overfitting. A corrected FSC is then defined as:

\[\mathrm{FSC_{corr}}(r) = \frac{\mathrm{FSC_{obs}}(r) - \mathrm{FSC_{rand}}(r)} {1 - \mathrm{FSC_{rand}}(r)}\]

If no overfitting is present, FSC_rand drops quickly to zero beyond *f*_cutoff and FSC_corr ≈ FSC_obs. An elevated FSC_rand indicates that the two half-maps share information beyond *f*_cutoff via a common external model used during iterative reconstruction.

Parameters:
  • img1 (ndarray) – First half-reconstruction (2-D or 3-D).

  • img2 (ndarray) – Second half-reconstruction, same shape as img1.

  • threshold (str, optional) – 'halfbit' (default) or 'onebit'.

  • ring_thick (int, optional) – Ring thickness in pixels. Default 1.

  • apod_width (int, optional) – Apodization width in pixels. Default 20.

  • fsc_cutoff (float, optional) – FSC value that defines the phase-randomization cut-off frequency. Phases are randomized at all shells where FSC_obs < fsc_cutoff. Default 0.8.

  • random_seed (int or None, optional) – Seed for the random phase generator (for reproducibility). Default None (non-reproducible).

FSC_obs

Standard (observed) FSC curve.

Type:

ndarray

FSC_rand

FSC of the phase-randomized half-volumes.

Type:

ndarray

FSC_corr

Phase-randomization corrected FSC.

Type:

ndarray

T

Threshold curve (same as standard FSC).

Type:

ndarray

f

Shell indices.

Type:

ndarray

fnyquist

Nyquist frequency in pixels.

Type:

float

cutoff_shell

Shell index used as the phase-randomization boundary.

Type:

int

References

plot()[source]

Plot FSC_obs, FSC_rand, FSC_corr, and the bias (FSC_obs − FSC_rand).

Left panel: all three FSC curves and the threshold T. Right panel: FSC_obs FSC_rand (overfitting bias).

Saves RandomFSC.png.

Returns:

  • fn (ndarray) – Spatial frequencies normalised by the Nyquist frequency.

  • FSC_obs (ndarray) – Standard FSC.

  • FSC_rand (ndarray) – Phase-randomized FSC.

  • FSC_corr (ndarray) – Corrected FSC.

  • T (ndarray) – Threshold curve.

class toupy.resolution.FSC.SSNRPlot(img1, img2, threshold='halfbit', ring_thick=1, apod_width=20, pixel_size=1.0)[source]

Bases: FourierShellCorr

Compute and plot the Spectral Signal-to-Noise Ratio (SSNR).

The SSNR is derived from the FSC via:

\[\mathrm{SSNR}(r) = \frac{2 \cdot \mathrm{FSC}(r)}{1 - \mathrm{FSC}(r)}\]

The resolution limit is defined by a frequency-dependent SSNR threshold curve obtained by applying the same transformation to the half-bit (or one-bit) FSC threshold \(T(r)\):

\[\mathrm{SSNR}_T(r) = \frac{2 \cdot T(r)}{1 - T(r)}\]

This curve is not a horizontal line — it starts very high at low spatial frequencies (few Fourier coefficients, large \(T\)) and asymptotes to a fixed value at high frequencies:

  • half-bit threshold: asymptote \(\approx 0.414\)

  • one-bit threshold: asymptote \(= 1.0\)

Using a horizontal line at SSNR = 1 as the resolution criterion is therefore only correct for the one-bit case (two fully independent measurements). For a split dataset (threshold='halfbit'), the correct criterion is the frequency-dependent \(\mathrm{SSNR}_T(r)\) curve, whose asymptote is ≈ 0.414.

Parameters:
  • img1 (ndarray) – First half-dataset (2-D or 3-D array).

  • img2 (ndarray) – Second half-dataset, same shape as img1.

  • threshold (str, optional) – 'halfbit' (default) or 'onebit'.

  • ring_thick (int, optional) – Ring thickness in pixels. Default 1.

  • apod_width (int, optional) – Apodization width in pixels. Default 20.

FSC

Fourier Shell/Ring Correlation curve.

Type:

ndarray

SSNR

Spectral Signal-to-Noise Ratio curve.

Type:

ndarray

SSNR_T

Frequency-dependent SSNR threshold derived from the FSC threshold curve \(T(r)\).

Type:

ndarray

f

Shell indices.

Type:

ndarray

fnyquist

Nyquist frequency in pixels.

Type:

float

fn_res

Resolution crossing as a fraction of the Nyquist frequency (dimensionless, range [0, 1]). None if SSNR never exceeds the threshold.

Type:

float or None

fn_res_cpx

Resolution crossing frequency in cycles/pixel (fn_res * 0.5). None if SSNR never exceeds the threshold.

Type:

float or None

resolution_full

Full-period resolution in physical units (van Heel / FSC convention): pixel_size / fn_res_cpx. This is the spatial period of the finest resolvable grating — the standard quantity reported in FSC analyses. None if SSNR never exceeds the threshold.

Type:

float or None

resolution_half

Half-period resolution in physical units (Rayleigh / feature-size convention): resolution_full / 2. This equals the smallest resolvable feature size and is the quantity most often reported in optical microscopy. None if SSNR never exceeds the threshold.

Type:

float or None

References

plot()[source]

Plot the SSNR curve with its frequency-dependent threshold and return the underlying data.

The plot shows:

  • The SSNR curve (blue).

  • The frequency-dependent SSNR threshold \(\mathrm{SSNR}_T(r)\) (red solid curve), derived by transforming the FSC threshold \(T(r)\) through \(\mathrm{SSNR}_T = 2T/(1-T)\).

  • A dotted horizontal line at the asymptotic threshold value (≈ 0.414 for half-bit, 1.0 for one-bit).

  • A vertical dashed line at the estimated resolution (last frequency where SSNR > SSNR_T).

Returns:

  • fn (ndarray) – Spatial frequencies normalised by the Nyquist frequency.

  • FSC (ndarray) – Fourier Shell/Ring Correlation curve.

  • SSNR (ndarray) – Spectral Signal-to-Noise Ratio curve.

  • SSNR_T (ndarray) – Frequency-dependent SSNR threshold curve.

  • fn_res_cpx (float or None) – Resolution crossing frequency in cycles/pixel (last frequency where SSNR > SSNR_T). Divide pixel_size by this value to obtain the resolution in physical units. None if SSNR never exceeds the threshold.

toupy.resolution.FSCtools module

FOURIER SHELL CORRELATION

toupy.resolution.FSCtools.compute_2tomograms(sinogram, theta, **params)[source]

Split the tomographic dataset in 2 datasets and compute 2 tomograms from them.

Parameters:
  • sinogram (ndarray) – A 2-dimensional array containing the sinogram

  • theta (ndarray) – A 1-dimensional array of thetas

Returns:

  • recon1 (ndarray) – A 2-dimensional array containing the 1st reconstruction.

  • recon2 (ndarray) – A 2-dimensional array containing the 2nd reconstruction.

toupy.resolution.FSCtools.compute_2tomograms_splitted(sinogram1, sinogram2, theta1, theta2, **params)[source]

Compute 2 tomograms from an already-split tomographic dataset.

The two reconstructions are independent, so they are run concurrently using a ThreadPoolExecutor. Because tomo_recons ultimately calls scipy.ndimage / iradon C extensions that release the GIL, two OS threads can execute true parallel C code with negligible overhead.

If threading fails for any reason (e.g. the backend is not thread-safe), the function transparently falls back to the original sequential path.

Parameters:
  • sinogram1 (ndarray) – A 2-dimensional array containing sinogram 1

  • sinogram2 (ndarray) – A 2-dimensional array containing sinogram 2

  • theta1 (ndarray) – A 1-dimensional array of thetas for sinogram1

  • theta2 (ndarray) – A 1-dimensional array of thetas for sinogram2

Returns:

  • recon1 (ndarray) – A 2-dimensional array containing the 1st reconstruction

  • recon2 (ndarray) – A 2-dimensional array containing the 2nd reconstruction

toupy.resolution.FSCtools.split_dataset(sinogram, theta)[source]

Split the tomographic dataset in 2 datasets

Parameters:
  • sinogram (ndarray) – A 2-dimensional array containing the sinogram

  • theta (ndarray) – A 1-dimensional array of thetas

Returns:

  • sinogram1 (ndarray) – A 2-dimensional array containing the 1st sinogram.

  • sinogram2 (ndarray) – A 2-dimensional array containing the 2nd sinogram.

  • theta1 (ndarray) – A 1-dimensional array containing the 1st set of thetas.

  • theta2 (ndarray) – A 1-dimensional array containing the 2nd set of thetas.

toupy.resolution.MTF module

Modulation Transfer Function (MTF) estimation for X-ray imaging systems.

class toupy.resolution.MTF.MTFEstimator(image, pixel_size=1.0, method='edge', roi=None, center=None, roi_size=16, oversample=4)[source]

Bases: object

Modulation Transfer Function (MTF) estimation.

Two estimation strategies are supported:

Edge method (method='edge'):

Implements the slanted-edge MTF algorithm (ISO 12233 / Burns 2000 variant). A sharp edge in the image is located, its orientation measured, and an oversampled Edge Spread Function (ESF) is constructed by projecting all pixel values onto the edge-normal direction. The ESF is differentiated to give the Line Spread Function (LSF), and the MTF is the modulus of the Fourier transform of the LSF normalised to unity at zero frequency.

Point-source method (method='point'):

A small bright feature (bead, wire cross-section) is used as an approximation to the system Point Spread Function (PSF). The MTF is the modulus of the 2-D FFT of the PSF, radially averaged and normalised.

Parameters:
  • image (ndarray) – A 2-dimensional image containing the edge or point source.

  • pixel_size (float, optional) – Physical size of one pixel. Default 1.0.

  • method ({'edge', 'point'}, optional) – Estimation strategy. Default 'edge'.

  • roi (tuple of slice or None, optional) – (row_slice, col_slice) defining the region of interest. For 'edge': crop to this region before edge fitting. For 'point': crop to this region before bead finding. None uses the full image.

  • center (tuple of int or None, optional) – (row, col) coordinates of the point source centre. Only used when method='point'. None finds the brightest pixel.

  • roi_size (int, optional) – Half-size (in pixels) of the extraction box around the point source. Only used when method='point'. Default 16.

  • oversample (int, optional) – Oversampling factor for the ESF construction (edge method only). Typically 4. Default 4.

freq

Spatial frequency axis in cycles/pixel.

Type:

ndarray

MTF

MTF values at each frequency (normalised to 1.0 at zero frequency).

Type:

ndarray

freq_phys

Spatial frequency in cycles per physical unit (freq / pixel_size).

Type:

ndarray

f50

Spatial frequency (cycles/pixel) where MTF = 0.5.

Type:

float

f10

Spatial frequency (cycles/pixel) where MTF = 0.1.

Type:

float

resolution_50

Resolution at MTF = 0.5 in physical units (pixel_size / f50).

Type:

float

resolution_10

Resolution at MTF = 0.1 in physical units (pixel_size / f10).

Type:

float

References

plot()[source]

Plot the MTF curve and save to MTF_<method>.png.

Marks the MTF=0.5 and MTF=0.1 crossings with vertical dashed lines. When pixel_size != 1.0 a second x-axis in physical units is added.

Returns:

  • freq (ndarray) – Spatial frequency axis (cycles/pixel).

  • MTF (ndarray) – MTF values normalised to 1.0 at zero frequency.

toupy.resolution.decorr module

Single-image resolution estimation via decorrelation analysis.

class toupy.resolution.decorr.ImageDecorr(image, pixel_size=1.0, n_r=100, threshold=0.15, apod_width=20, axis=0, n_slices=10, slice_range=None)[source]

Bases: object

Single-image resolution estimation via decorrelation analysis [1]_.

For each radial spatial frequency r the image is correlated with its phase-normalised ring-filtered self. In the signal-dominated band the phase is coherent and the correlation is high; beyond the resolution limit the Fourier phases are noise-dominated and the correlation drops. The highest spatial frequency at which the normalised correlation exceeds threshold is taken as the resolution limit.

No second image or half-dataset is required — the estimate is obtained from a single 2-D image (or from a set of 2-D slices sampled from a 3-D volume).

Parameters:
  • image (ndarray) – A 2-dimensional array (single image) or a 3-dimensional array (tomographic volume). When a 3-D volume is supplied the algorithm is applied slice-by-slice along axis and summary statistics are reported.

  • pixel_size (float, optional) – Physical size of one pixel (in any consistent unit, e.g. nm). Used to convert the resolution from pixels to physical units. Default 1.0 (result in pixels).

  • n_r (int, optional) – Number of radial frequency bins between the lowest non-zero frequency and the Nyquist limit (0.5 cycles/pixel). Default 100.

  • threshold (float, optional) – Correlation threshold used to define the resolution limit. The default 0.15 matches the FSC/FRC half-bit criterion.

  • apod_width (int, optional) – Width in pixels of the Hanning apodization applied to the image edges before computing the FFT. Set to 0 to disable apodization. Default 20.

  • axis (int, optional) – Axis along which slices are taken when image is 3-D. Default 0 (first axis, i.e. slices are image[i, :, :]).

  • n_slices (int, optional) – Number of evenly-spaced slices to sample from the 3-D volume (or from the sub-range defined by slice_range). Ignored when image is 2-D. Default 10.

  • slice_range (tuple of int or None, optional) – (start, stop) slice indices along axis that define the sub-range from which slices are sampled, following standard Python / NumPy half-open convention (start inclusive, stop exclusive). Negative indices are supported and are resolved against the axis length before use. None (default) samples the full extent of the volume.

r_values

Radial spatial frequencies (cycles/pixel) at which the correlation was evaluated. For 3-D input this is taken from the last slice processed.

Type:

ndarray

A

Normalised ring correlation A(r). For 3-D input: result of the last slice processed.

Type:

ndarray

d

Decorrelation function d(r) = 1 − A(r). For 3-D input: result of the last slice processed.

Type:

ndarray

r_res

Estimated resolution spatial frequency (cycles/pixel). For 3-D input: median over all sampled slices.

Type:

float

resolution_px

Estimated resolution in pixels (= 1 / r_res). For 3-D input: median over all sampled slices.

Type:

float

resolution

Estimated resolution in physical units (= pixel_size / r_res). For 3-D input: median over all sampled slices.

Type:

float

resolutions_px

Per-slice resolution estimates in pixels. None for 2-D input.

Type:

ndarray or None

resolution_px_mean

Mean per-slice resolution in pixels. None for 2-D input.

Type:

float or None

resolution_px_median

Median per-slice resolution in pixels. None for 2-D input.

Type:

float or None

resolution_px_std

Standard deviation of per-slice resolutions in pixels. None for 2-D input.

Type:

float or None

References

plot()[source]

Plot the decorrelation analysis result.

For a 2-D input (or after 3-D analysis) the decorrelation curve A(r) is shown together with the threshold line and the resolution estimate marker.

For a 3-D input a histogram of the per-slice resolution estimates is shown in addition to the A(r) curve of the last processed slice, so that the spread across slices is visible.

Returns:

  • r_values (ndarray) – Radial spatial frequencies (cycles/pixel).

  • A (ndarray) – Normalised ring correlation A(r).

  • d (ndarray) – Decorrelation function d(r) = 1 − A(r).

  • resolution_px (float) – Estimated resolution in pixels (median for 3-D input).

toupy.resolution.localres module

Single-map local resolution estimation via a ResMap-inspired statistical test.

class toupy.resolution.localres.LocalResolution(vol, pixel_size=1.0, significance=0.05, n_freq=20, window_sigma=7.0, mask=None, noise_method='corners', noise_mask=None, sigma_noise=None, corner_fraction=0.1, highfreq_fraction=0.1)[source]

Bases: object

Single-map local resolution estimation via a ResMap-inspired statistical test.

For each voxel and each spatial-frequency band the local signal energy is compared with the noise floor via a z-score derived from the chi-squared distribution. The local resolution is the finest spatial frequency at which the test passes at significance level significance.

A single reconstruction is sufficient — no half-datasets are required. Three noise estimation strategies are available (see noise_method), making the estimator usable even for local tomography datasets where the sample fills the entire field of view and the volume corners are not empty.

Parameters:
  • vol (ndarray) – A 2-dimensional image or 3-dimensional reconstruction. No half-maps are needed.

  • pixel_size (float, optional) – Physical size of one voxel (any consistent unit, e.g. nm). Default 1.0 (result in pixels).

  • significance (float, optional) – Significance level α for the one-sided z-test. Smaller values require stronger evidence of signal and yield more conservative (coarser) local resolution estimates. Default 0.05.

  • n_freq (int, optional) – Number of frequency bands tested between the lowest resolvable frequency and the Nyquist limit. Default 20.

  • window_sigma (float, optional) – Standard deviation (in voxels) of the Gaussian window used to estimate the local signal energy. Larger values produce a smoother but spatially lower-resolution map. Default 7.0.

  • mask (ndarray of bool or None, optional) – Binary mask identifying the sample region. Voxels outside the mask are set to NaN in the output map. If None (default) a mask is estimated automatically via Gaussian blurring and thresholding.

  • noise_method ({'corners', 'highfreq', 'mask'}, optional) –

    Strategy used to estimate the noise standard deviation:

    'corners' (default)

    Noise is estimated from small cubic sub-volumes at the eight (four for 2-D) corners of the reconstruction. Requires the corners to be free of sample signal. Not suitable for local tomography.

    'highfreq'

    Noise is estimated from the high-frequency tail of the power spectrum (frequencies above 1 - highfreq_fraction of the Nyquist range). Works even when the sample fills the entire field of view, because signal power typically falls well below the noise floor near the Nyquist limit. Suitable for local tomography and any dataset where empty corners are unavailable.

    'mask'

    Noise is estimated from the voxels indicated by noise_mask. The user must supply a boolean array marking known empty (noise-only) regions anywhere in the volume.

  • noise_mask (ndarray of bool or None, optional) – Boolean array (same shape as vol) whose True entries mark voxels that contain only noise (i.e. no sample signal). Required when noise_method='mask'; ignored otherwise.

  • sigma_noise (float or None, optional) – Directly supply the noise standard deviation, bypassing all automatic estimation. When provided, noise_method, noise_mask, and corner_fraction are all ignored.

  • corner_fraction (float, optional) – Fraction of each edge length used to define the corner noise regions. Must be in (0, 0.5). Only used when noise_method='corners'. Default 0.10.

  • highfreq_fraction (float, optional) – Fraction of the frequency range (counting down from Nyquist) used to estimate noise power. Only used when noise_method='highfreq'. Default 0.10 (top 10 %, i.e. frequencies from 0.45 to 0.50 cycles/pixel).

resolution_map

Local full-period resolution in pixels (van Heel convention, NaN outside the sample mask), same shape as vol.

Type:

ndarray

resolution_map_phys

Local full-period resolution in physical units (resolution_map * pixel_size).

Type:

ndarray

resolution_map_half

Local half-period resolution in pixels (Rayleigh convention): resolution_map / 2.

Type:

ndarray

resolution_map_phys_half

Local half-period resolution in physical units: resolution_map_phys / 2.

Type:

ndarray

sigma_noise

Noise standard deviation used for the hypothesis test.

Type:

float

freq_bands

Centre frequencies (cycles/pixel) of each tested band.

Type:

ndarray

mask

Binary sample mask (estimated or user-supplied).

Type:

ndarray of bool

resolution_median

Median full-period local resolution in pixels (within the mask).

Type:

float

resolution_mean

Mean full-period local resolution in pixels (within the mask).

Type:

float

resolution_std

Standard deviation of full-period local resolution in pixels (within the mask).

Type:

float

resolution_median_half

Median half-period local resolution in pixels (within the mask).

Type:

float

resolution_mean_half

Mean half-period local resolution in pixels (within the mask).

Type:

float

resolution_std_half

Standard deviation of half-period local resolution in pixels (within the mask).

Type:

float

Notes

The implementation follows the methodology of ResMap [1]_ but uses a Gaussian bandpass filter and a z-score threshold in place of the original steerable-filter chi-squared test. For most practical purposes the results are equivalent. The key advantage over the block-wise LocalFSC approach is that only a single reconstruction is required.

For local (region-of-interest) tomography, use noise_method='highfreq' or supply sigma_noise directly:

# Local tomography — corners are not empty
lr = LocalResolution(vol, pixel_size=28.6e-9,
                     noise_method='highfreq')

# Or if you already know sigma_noise from the sinogram
lr = LocalResolution(vol, pixel_size=28.6e-9,
                     sigma_noise=0.003)

References

plot(slice_idx=None, axis=0, cmap='viridis_r', vmin=None, vmax=None)[source]

Visualise the local resolution map and save to LocalResolution_map.png.

For a 3-D volume a single slice is shown; for a 2-D image the full map is displayed.

Parameters:
  • slice_idx (int or None, optional) – Index of the slice to display along axis (3-D only). Defaults to the central slice when None.

  • axis (int, optional) – Axis along which to take the slice (3-D only). Default 0.

  • cmap (str, optional) – Matplotlib colormap name. Default 'viridis_r' so that higher resolution (smaller value) appears bright.

  • vmin (float or None, optional) – Lower bound for the colormap. Defaults to the map minimum.

  • vmax (float or None, optional) – Upper bound for the colormap. Defaults to the map maximum.

Returns:

resolution_map – The resolution_map attribute (unchanged).

Return type:

ndarray