Convolvables¶
Prysm features a rich implemention of Linear Shift Invariant (LSI) system theory. Under this mathematical ideal, the transfer function is the product of the Fourier transform of a cascade of components, and the spatial distribution of intensity is the convolution of a cascade of components. These features are usually used to blur objects or images with Point Spread Functions (PSFs), or model the transfer function of an opto-electronic system. Within prysm there is a class Convolvable
which objects and PSFs inherit from. You should rarely need to use the base class, except when subclassing it with your own models or objects.
>>> from prysm.convolution import Convolvable
The built-in convolvable objects are Slits, Pinholes, Tilted Squares, and Siemens Stars. There are also two components, PixelAperture and OLPF, used for system modeling.
>>> from prysm import Slit, Pinhole, TiltedSquare, SiemensStar, PixelAperture, OLPF
Each is initialized with object-specific parameters,
>>> s = Slit(width=1, orientation='crossed') # diameter, um
>>> p = Pinhole(width=1)
>>> t = TiltedSquare(angle=8, background='white', sample_spacing=0.05, samples=256)) # degrees
>>> star = SiemensStar(num_spokes=32, sinusoidal=False, background='white', sample_spacing=0.05, samples=256)
>>> pa = PixelAperture(width_x=5) # diameter, um
>>> ol = OLPF(width_x=5*0.66)
Objects that take a background parameter will be black-on-white for background=white
, or white-on-black for background=black
. Two objects are convolved via the conv
method, which returns self
on a new Convolvable
instance and is chainable,
>>> monstrosity = s.conv(p).conv(t).conv(star).conv(pa).conv(ol)
Some models require sample spacing and samples parameters while others do not. This is because prysm has many methods of executing an FFT-based Fourier domain convolution under the hood. If an object has a known analytical Fourier transform, the class has a method (Convolvable).analytic_ft
which has abscissa units of reciprocal microns. If the analytic FT is present, it is used in lieu of numerical data. Models that have analytical Fourier transforms also accept sample_spacing and samples parameters, which are used to define a grid in the spatial domain. If two objects with analytical Fourier transforms are convolved, the output grid will have the finer sample spacing of the two inputs, and the larger span or window width of the two inputs.
The Convolvable constructor takes only four parameters,
>>> import numpy as np
>>> x = y = np.linspace(-20,20,256)
>>> z = np.random.uniform((256,256))
>>> c = Convolvable(data=z, unit_x=x, unit_y=y, has_analytic_ft=False)
has_analytic_ft
has a default value of False
.
Minimal labor is required to subclass Convolvable
. For example, the Pinhole
implemention is simply:
class Pinhole(Convolvable):
def __init__(self, width, sample_spacing=0.025, samples=0):
self.width = width
# produce coordinate arrays
if samples > 0:
ext = samples / 2 * sample_spacing
x, y = m.linspace(-ext, ext, samples), m.linspace(-ext, ext, samples)
xv, yv = m.meshgrid(x, y)
w = width / 2
# paint a circle on a black background
arr = m.zeros((samples, samples))
arr[m.sqrt(xv**2 + yv**2) < w] = 1
else:
arr, x, y = None, m.zeros(2), m.zeros(2)
super().__init__(data=arr, unit_x=x, unit_y=y, has_analytic_ft=True)
def analytic_ft(self, unit_x, unit_y):
xq, yq = m.meshgrid(unit_x, unit_y)
# factor of pi corrects for jinc being modulo pi
# factor of 2 converts radius to diameter
rho = m.sqrt(xq**2 + yq**2) * self.width * 2 * m.pi
return m.jinc(rho).astype(config.precision)
which is less than 20 lines long.
Convolvable
objects have a few convenience properties and methods. (Convolvable).slice_x
and its y variant exist and behave the same as slices on subclasses of OpticalPhase
such as Pupil
. (Convolvable).plot_slice_xy
also works the same way. (Convolvable).shape
is a convenience wrapper for (Convolvable).data.shape
, an (Convolvable).support_x, .support_y,
an .support
mimic the equivalent diameter
properties on OpticalPhase
inheritants.
(Convolvable).show
and (Convolvable).show_fourier
behave the same way as plot2d
methods found throughout prysm, except there are xlim
and ylim
parameters, which may be either single values, taken to be symmetric axis limits, or length-2 iterables of lower and upper limits.
Finally, Convolvable
objects may be initialized from images,
>>> c = Convolvable.from_file(path_to_your_image, scale=1) # plate scale in um
and written out as 8-bit images,
>>> p = 'foo.png' # or jpg, any format imageio can handle
>>> c.save(save_path)
In practical use, one will generally only use the conv
, from_file
, and save
methods with any degree of regularity. The complete API documentation is below. Attention should be paid to the docstring of conv
, as it describes some of the details associated with convolutions in prysm, their accuracy, and when they are used.
-
class
prysm.convolution.
Convolvable
(data, unit_x, unit_y, has_analytic_ft=False)[source]¶ Bases:
object
A base class for convolvable objects to inherit from.
- data : numpy.ndarray
- numerical representation of object
- has_analytic_ft : bool
- whether this convolvable has an analytical Fourier transform
- sample_spacing : float
- center to center spacing of samples
- unit_x : numpy.ndarray
- x-axis unit
- unit_y : numpy.ndarray
- y-axis unit
-
conv
(other)[source]¶ Convolves this convolvable with another.
- other : Convolvable
- A convolvable object
- Convolvable
- a convolvable that lacks an analytical fourier transform
- The algoithm works according to the following cases:
Both self and other have analytical fourier transforms: - The analytic forms will be used to compute the output directly. - The output sample spacing will be the finer of the two inputs. - The output window will cover the same extent as the “wider”
input. If this window is not an integer number of samples wide, it will be enlarged symmetrically such that it is. This may mean the output array is not of the same size as either input.
- An input which contains a sample at (0,0) may not produce an output with a sample at (0,0) if the input samplings are not favorable. To ensure this does not happen confirm that the inputs are computed over identical grids containing 0 to begin with.
One of self and other have analytical fourier transforms: - The input which does NOT have an analytical fourier transform
will define the output grid.
- The available analytic FT will be used to do the convolution in Fourier space.
Neither input has an analytic fourier transform: 3.1, the two convolvables have the same sample spacing to within
a numerical precision of 0.1 nm:
- the fourier transform of both will be taken. If one has fewer samples, it will be upsampled in Fourier space
- 3.2, the two convolvables have different sample spacing:
- The fourier transform of both inputs will be taken. It is assumed that the more coarsely sampled signal is Nyquist sampled or better, and thus acts as a low-pass filter; the more finaly sampled input will be interpolated onto the same grid as the more coarsely sampled input. The higher frequency energy would be eliminated by multiplication with the Fourier spectrum of the more coarsely sampled input anyway.
- The subroutines have the following properties with regard to accuracy:
- Computes a perfect numerical representation of the continuous output, provided the output grid is capable of Nyquist sampling the result.
- If the input that does not have an analytic FT is unaliased, computes a perfect numerical representation of the continuous output. If it does not, the input aliasing limits the output.
- Accuracy of computation is dependent on how much energy is present at nyquist in the worse-sampled input; if this input is worse than Nyquist sampled, then the result will not be correct.
-
deconv
(other, balance=1000, reg=None, is_real=True, clip=False, postnormalize=True)[source]¶ Perform the deconvolution of this convolvable object by another.
- other : Convolvable
- another convolvable object, used as the PSF in a Wiener deconvolution
- balance : float, optional
- regularization parameter; passed through to skimage
- reg : numpy.ndarray, optional
- regularization operator, passed through to skimage
- is_real : bool, optional
- True if self and other are both real
- clip : bool, optional
- clips self and other into (0,1)
- postnormalize : bool, optional
- normalize the result such that it falls in [0,1]
- Convolvable
- a new Convolable object
See skimage: http://scikit-image.org/docs/dev/api/skimage.restoration.html#skimage.restoration.wiener
-
static
from_file
(path, scale)[source]¶ Read a monochrome 8 bit per pixel file into a new Image instance.
- path : string
- path to a file
- scale : float
- pixel scale, in microns
- Convolvable
- a new image object
-
plot_slice_xy
(axlim=20, lw=3, fig=None, ax=None)[source]¶ Create a plot of slices through the X and Y axes of the PSF.
- axlim : float or int, optional
- axis limits, in microns
- lw : float, optional
- linewidth provided directly to matplotlib
- fig : matplotlib.figure.Figure, optional
- Figure to draw plot in
- ax : matplotlib.axes.Axis
- Axis to draw plot in
- fig : matplotlib.figure.Figure, optional
- Figure containing the plot
- ax : matplotlib.axes.Axis, optional
- Axis containing the plot
-
save
(path, nbits=8)[source]¶ Write the image to a png, jpg, tiff, etc.
- path : string
- path to write the image to
- nbits : int
- number of bits in the output image
-
shape
¶
-
show
(xlim=None, ylim=None, interp_method=None, power=1, show_colorbar=True, fig=None, ax=None)[source]¶ Display the image.
- xlim : iterable, optional
- x axis limits
- ylim : iterable,
- y axis limits
- interp_method : string
- interpolation technique used in display
- power : float
- inverse of power to stretch image by. E.g. power=2 will plot img ** (1/2)
- show_colorbar : bool
- whether to show the colorbar or not.
- fig : matplotlib.figure.Figure, optional:
- Figure containing the plot
- ax : matplotlib.axes.Axis, optional:
- Axis containing the plot
- fig : matplotlib.figure.Figure, optional:
- Figure containing the plot
- ax : matplotlib.axes.Axis, optional:
- Axis containing the plot
-
show_fourier
(freq_x=None, freq_y=None, interp_method='lanczos', fig=None, ax=None)[source]¶ Display the fourier transform of the image.
- interp_method : string
- method used to interpolate the data for display.
- freq_x : iterable
- x frequencies to use for convolvable with analytical FT and no data
- freq_y : iterable
- y frequencies to use for convolvable with analytic FT and no data
- fig : matplotlib.figure.Figure
- Figure containing the plot
- ax : matplotlib.axes.Axis
- Axis containing the plot
- fig : matplotlib.figure.Figure
- Figure containing the plot
- ax : matplotlib.axes.Axis
- Axis containing the plot
freq_x and freq_y are unused when the convolvable has a .data field.
-
slice_x
¶ Retrieve a slice through the x axis of the PSF.
- self.unit_x : numpy.ndarray
- ordinate data
- self.data : numpy.ndarray
- coordinate data
-
slice_y
¶ Retrieve a slice through the y axis of the PSF.
- self.unit_y : numpy.ndarray
- ordinate data
- self.data : numpy.ndarray
- coordinate data
-
support
¶
-
support_x
¶
-
support_y
¶