Phase Processing and Visualisation
The raw output from numerical refocusing or off-axis demodulation is a complex
numpy array representing the complex field. The amplitude and phase of the field
are the amplitude and angle of the complex numbers in the array, respectively,
and can be extracted using pyholoscope.amp() and pyholoscope.phase().
PyHoloscope has several functions for further processing of the phase. A common
requirement is to subtract a reference phase, for example acquired with nothing
in the field of view. This can be done automatically when using the Holo
class by providing a background hologram and setting background and relative_phase
(e.g. holo.background = background_img and holo.relative_phase = True), or by setting
these parameters at instantiation.
Alternatively, this can be done manually using the pyholoscope.relative_phase()
function. For example, assume we have off-axis demodulated a hologram, to obtain hologram_demod,
for example by using the Holo class. We then also demodulate the
background image to obtain background_demod in the same way. Then:
correctedImage = pyholoscope.relative_phase(hologram_demod, background_demod)
returns a complex array with the reference phase from the background hologram
subtracted. It is also possible to provide the phase maps (i.e. pyholoscope.phase(hologram_demod)
and pyholoscope.phase(background_demod)) instead, in which case the corrected phase will
be returned. The function assumes that the inputs are phase maps if the datatype is not complex.
Phase Unwrapping
An unwrapped phase map can be created by passing the wrapped phase map to
pyholoscope.phase_unwrap(). Note that this function accepts either a
phase map or the complex field, but the output unwrapped phase map is always
real, i.e. the unwrapped phase cannot be represented as a complex field. The phase
unwrapping uses the method shipped with skimage, based on:
Miguel Arevallilo Herraez, David R. Burton, Michael J. Lalor, and Munther A. Gdeisat, “Fast two-dimensional phase-unwrapping algorithm based on sorting by reliability following a noncontinuous path”, Journal Applied Optics, Vol. 41, No. 35, pp. 7437, 2002
Tilt Removal
The way in which a sample is mounted may lead to further distortions of the phase
map that are not accounted for by subtraction of a reference phase. This often
manifests as a tilt. This can be removed by first estimating the tilt from the
unwrapped phase and then subtracting it, using pyholoscope.obtain_tilt() and
the removing this using pyholoscope.relative_phase(). Note that
pyholoscope.obtain_tilt() must be passed the unwrapped phase map, e.g.
from pyholoscope.phase_unwrap(), otherwise the tilt will not be
found correctly.
For example, assuming we have a complex field in hologram_demod:
unwrapped_phase = pyholoscope.phase_unwrap(hologram_demod)
tilt = pyholoscope.obtain_tilt(unwrapped_phase)
corrected_phase = pyholoscope.relative_phase(unwrapped_phase, tilt)
This returns the unwrapped and tilt-corrected phase map in corrected_phase.
It is possible to use pyholoscope.relative_phase() twice, once to remove
the background phase distortion due to the system (in which case the tilt should
be estimated from this background-corrected phase) and then again to correct
the tilt.
Phase Stabilisation
In live imaging or video recording, the global phase will tend to drift over time. To avoid this
visual effect, the phase can be referenced to a part of the image which is known not to contain any object using
pyholoscope.relative_phase_self(). Define a region of interest (ROI) using Roi and then pass this
along with the complex field or phase map, for example:
roi = pyholoscope.Roi(x=20, y=20, w = 100, h = 100)
corrected_phase = pyholoscope.relative_phase_self(hologram_demod, roi)
Alternatively, do not pass a ROI to make the phase relative to the mean phase across the entire image. This gives good results only when the object makes up a small fraction of the image.
The function works with both the complex field and phase maps, but will not be effective when
the complex field contains wrapped phase or uncorrected tilt or other distortions. It is normally
best to correct these issues first using the relative phase, tilt removal and phase unwrapping functions,
and then pass the unwrapped, corrected phase to pyholoscope.relative_phase_self().
Visualisation
PyHoloscope includes two functions, pyholoscope.phase_gradient() and pyholoscope.synthetic_DIC() to
generate a phase gradient image and an approximation to a DIC image, respectively.
Both functions accept either the complex field or phase map (i.e. a complex or
float array) and work with wrapped phase. Artefacts due to wrapping are avoided
by correcting large jumps in phase. pyholoscope.phase_gradient_amp() is used internally
by pyholoscope.phase_gradient(), and does not remove the wrapping
(on unwrapped phase maps either functions can be used and return identical values).
A third function, pyholoscope.phase_gradient_dir() can be used to return a directional
gradient map. This map is returned as a complex array, with the amplitudes being
the amplitude of the gradient at each point, and the angles being the direction. This
function should be provided with the unwrapped phase.
Saving Phase Maps
Wrapped phase maps can be saved to image files using pyholoscope.save_phase_image(), which
saves the phase map as a 16 bit tif, in which a pixel value of 0 corresponds to a phase of 0
and a pixel values of 65535 corresponds to 2pi. The function accepts either phase maps or complex fields.
If a phase map is provided, any phase values outside of the [0, 2pi] interval will be wrapped to this
interval.
An unwrapped phase map, stored as a float array, can be saved using
pyholoscope.save_image() or pyholoscope.save_image16(), to save as 8 or 16 bit images
respectively. Note that the images will be autoscaled so that the minimum phase value is 0 and the max
is either 255 or 65535, respectively. To avoid this, pass autoscale = False, in which case the phase
values will be cast directly to the relevant data type, in which case it is the caller’s
responsibility to ensure the range is sensible.