zernpy.zernpsf
PSF class definition based on Zernike polynomial for computation of its kernel for convolution / deconvolution.
@author: Sergei Klykov, @year: 2025, @licence: MIT
The PSF (2D) class for focal plane of a microscopic system assuming that the phase profile is described by the Zernike polynomial.
In other words, the PSF describing the image of point source formed by the microscopic system.
Check the set_physical_props() method for the list of expected physical parameters for PSF calculation and calculate_psf_kernel() for the references to the diffraction integral used for calculations.
References
[1] Principles of Optics, by M. Born and E. Wolf, 4 ed., 1968
[2] https://en.wikipedia.org/wiki/Optical_aberration#Zernike_model_of_aberrations
[3] https://wp.optics.arizona.edu/jsasian/wp-content/uploads/sites/33/2016/03/ZP-Lecture-12.pdf
[5] https://nijboerzernike.nl/_PDF/JOSA-A-19-849-2002.pdf#[0,{%22name%22:%22Fit%22}]
Initiate the PSF wrapping class.
Parameters
- zernpol (ZernPol | Sequence[ZernPol]): Single instance of ZernPol() class or Sequence with ZernPol instances.
Raises
- ValueError: 1) If not instance(-s) of ZernPol class provided as the input parameter;
2) If the provided sequence has zero length;
3) If not all members of the provided sequence are instance of the "ZernPol" class;
4) If the provided sequence contain repeated polynomials.
Returns
- ZernPSF() class instance.
Set parameters in physical units.
Parameters
- NA (float): Numerical aperture of an objective, assumed usage of microscopic ones.
- wavelength (float): Wavelength of monochromatic light (λ) used for imaging in physical units (e.g., as µm).
expansion_coeff (float | Sequence[float]): Amplitude(-s) or expansion coefficient(-s) of the Zernike polynomial in physical units. Note that according to the used equation for PSF calculation it will be adjusted to the units of wavelength: alpha = expansion_coeff/wavelength. See the equation in the method "calculate_psf_kernel".
Note that if Airy pattern (PSF for Piston polynomial) is provided, it's required to provide amplitude for it. However, this amplitude will be ignored in general for calculation because of its properties.
- pixel_physical_size (float): Pixel size of the formed image in physical units (do not mix up with the physical sensor (camera) pixel size!). The sanity check performed as the comparison with the Abbe resolution limit (see ref. [1] and [2]), provided pixel size should be less than this limit.
Raises
- ValueError: If one of the sanity check has been failed, check the Error message for details.
References
[2] https://www.edinst.com/de/blog/the-rayleigh-criterion-for-microscope-resolution/
Returns
- None.
Set calculation properties: kernel size, number of integration points on polar coordinates.
Note that it's recommended to set the physical properties by set_physical_props() method for getting estimated required kernel size.
Parameters
- kernel_size (int): Size of PSF kernel (2D matrix used for convolution). Should be odd integer not less than 3.
- n_integration_points_r (int): Number of integration points used for calculation diffraction integral on the radius of the entrance pupil (normalized to the range [0.0, 1.0]). Should be integer not less than 20.
- n_integration_points_phi (int): Number of integration points used for calculation diffraction integral on the polar angle phi of the entrance pupil (from the range [0.0, 2pi]). Should be integer not less than 36.
Raises
- ValueError: If sanity checks fail (if provided parameters less than sanity values).
Returns
- None
Calculate PSF kernel using the specified or default calculation parameters and physical values.
Calculation based on the diffraction integral for the circular aperture. The final equation is derived based from the 2 References.
Kernel is defined as the image formed on the sensor (camera) by the diffraction-limited, ideal microscopic system. The diffraction integral is calculated numerically on polar coordinates, assuming circular aperture of an imaging system (micro-objective).
The order of integration and used equations in short: 1st - integration going on radius p, using trapezoidal rule: p•(alpha•zernike_pol.polynomial_value(p, phi) - r•p•cos(phi - theta))•1j
2nd - integration going on angle phi, using Simpson rule, calling the returned integrals by 1st call for each phi and as the final output, it provides as the np.power(np.abs(integral_sum), 2)•integral_normalization, there integral_normalization = 1.0/(pi•pi) - the square of the module of the diffraction integral (complex value), i.e. intensity as the PSF value.
For details of implementation, explore methods in 'calculations' module, calc_psfs.py file.
Note that the Nijboer's approximation for calculation of diffraction integral also has been tested, but the results is not in agreement with the reference [3] due to the large expansion coefficients for Zernike polynomials.
Note that for Piston (m=0, n=0) the exact equation is used, that provides Airy pattern as the result.
Parameters
- suppress_warnings (bool, optional): Flag to suppress all possible warnings. The default is False.
- normalized (bool, optional): Flag to return normalized PSF values to max=1.0. The default is True.
- verbose_info (bool, optional): Flag to print out each step completion report and measured elapsed time in ms. The default is False.
- accelerated (bool, optional): Flag to accelerate the calculations by using numba library for scripts compilation. Acceleration will be used automatically, if None is provided and 'numba' library is installed. The default is None.
References
[1] Principles of Optics, by M. Born and E. Wolf, 4 ed., 1968
[2] https://nijboerzernike.nl/_downloads/Thesis_Nijboer.pdf
[3] PSF shapes: https://en.wikipedia.org/wiki/Zernike_polynomials#/media/File:ZernikeAiryImage.jpg
[4] https://opg.optica.org/ao/abstract.cfm?uri=ao-52-10-2062 (DOI: 10.1364/AO.52.002062)
Returns
- numpy.ndarray: 2D PSF kernel.
Plot on the external figure (matplotlib.pyplot.figure()) calculated PSF kernel.
Parameters
- id_str (str, optional): String with ID for making unique Figure. The default is "".
Returns
- None.
Convolute the provided image with PSF kernel as 2D arrays and return the convolved image with the same type as the original one.
Parameters
- image (numpy.ndarray): Sample image, not colour.
- scale2original (bool): Convolution resulting image will be rescaled to the max intensity of the provided image if True. The default is True.
Returns
- convolved_image (numpy.ndarray): Result of convolution (by using function scipy.ndimage.convolve).
Plot convolution of the PSF kernel and sample image (even centered disk with blurred edges).
Parameters
- radius (float, optional): Radius of the centered disk. The default is 4.0.
- max_intensity (int, optional): Maximum intensity of the even disk. The default is 255.
Returns
- None.
Crop redundant points from kernel.
By default, all rows and columns containing any single value that more than 1% of max kernel value, are not cropped.
Cropped kernel saved in class variable 'kernel'.
Parameters
- min_part_of_max (float, optional): Part of kernel max that is used for checking rows / columns for cropping. The default is 0.01.
Raises
- ValueError: If parameter 'min_part_of_max' is not > 0.0 and not < 0.5.
Returns
- None.
Save class attributes (PSF kernel, physical properties, etc.) in the JSON file for further reloading and avoiding long computation.
Parameters
- abs_path (str | Path, optional): Absolute path for the file. If None, the file will be saved in the folder "saved_psfs" in the root of the package. The default is None.
- overwrite (bool, optional): Flag for overwriting the existing file. The default is False.
Returns
- None.
Read the JSON file with the saved attributes and setting it for the class.
Parameters
- abs_path (str | Path, optional): Absolute path to the file. If None is provided, then the stored in the attribute path will be checked. The default is None.
Returns
- None.
Initialize 4 Processes() for performing integration.
See intmproc.py script (utils module) for implementation details. Tests showed that this way doesn't provide performance gain.
Returns
- None.
Parallel implementation of numerical integration.
Parameters
- r (float): Input radial polar coordinate.
- theta (float): Input angular polar coordinate.
Returns
- float: Each point for PSF kernel.
Parallelized implementation of PSF kernel calculation.
Note it's much less effective than common calculate_psf_kernel() method.
Parameters
- normalize_values (bool, optional): Flag to normalize values. The default is True.
Returns
- numpy.ndarray: PSF kernel.
Force compilation of computing functions for round and ellipse 'precise' shaped objects.
verbose_report : bool, optional Flag for printing out the elapsed for compilation time. The default is False.
Returns
- None or tuple with 2 used ZernPSF instances depending on 'numba_installed' flag.