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.