Off-Axis Holography Basics
Off-axis Holography is performed using the Holo
class of PyHoloscope by setting mode = pyholoscope.OFFAXIS
. This allows
demodulation of the off-axis carrier frequency to recover the quantitative phase as well numerical refocusing. See the
Holo class documentation for a full list of methods and arguments. For code examples see the Off-axis Holography Example and the
Off-axis Holography with Refocusing Example on github.
Getting Started using Holo Class
Begin by importing the package:
import pyholoscope as pyh
and create an instance of the Holo
class. At a minimum we need to set the mode to off-axis
holography and, if we would like to perform numerical refocusing, provide the physical pixel size and the wavelength:
holo = pyh.Holo(mode = pyh.OFF_AXIS, pixelSize = 2e-6, wavelength = 0.5e-6)
We also need to know the spatial frequency of the modulation. We can determine this automtically using:
holo.calib_off_axis(backgroundImg)
where we have provided a background hologram to use for this purpose. It is possible to use the image hologram as well for this purpose, but this may be unreliable if there is another strong spatial frequency. If a background image has first been set using:
holo.set_background(backgroundImg)
or by passing background = backgroundImage
when creating the Holo
object, then
this will be used for the calibration if calib_off_axis
is called with no argument.
Alternatively the demodulation parameters can be specified manually using:
holo.set_off_axis_mod(cropCentre, cropRadius)
where cropCentre
is a tuple of (x,y), giving the pixel location of the centre of the modulation peak in the FFT of the hologram,
and cropRadius
is half the size of the box around the modulation centre which is demodulated. cropRadius
can also
be a tuple giving the x and y radii of an ellipse, for cases where the hologram is non-square.
We can then demodulate to obtain the complex field using:
reconField = hol.process()
To obtain the amplitude and phase, use:
amplitude = pyh.amplitude(reconField)
phase = pyh.phase(reconField)
If we would like to also refocus to a different depth we can specify this when we create the Holo
object:
holo = pyh.Holo(mode = pyh.OFFAXIS_MODE, pixelSize = 2e-6, wavelength = 0.5e-6, refocus = True, depth = 0.001)
Then when we call:
reconField = holo.process()
Both the demodulation and the refocusing will take place in a single step.
We can change the refocus depth and whether or not to refocus witout recreating the Holo
object using:
holo.set_depth(depth)
holo.set_refocus(True)
Note that the first time a hologram is refocused to a particular depth the process will be slower due to the need to create a propagator for that depth. This is particularly noticable when using GPU acceleration as the propagator creation will often be the rate limiting step. Subsequent refocusing to the same depth will be faster providing no parameters are changed that force a new propagator to be created (depth, pixel size, wavelength or grid size). The propagator can also be pre-computed by calling:
holo.update_propagator()
in advance.
To correct for a background phase (i.e the phase map of the background hologram), set:
holo.set_relative_phase(True)
or pass relative_phase = True
when creating the Holo
object. You should then call:
holo.background_field()
to compute the background phase.
Getting Started Using Lower-Level Functions
As an alternative to using the Holo
class, low-level functions can be called directly. Begin by importing the library:
import pyholoscope as pyh
We will assume we have a hologram hologram
and a background image backgroundImg
which are both square 2D numpy arrays of the same size.
If we do not know the modulation frequency in advance we can use:
cropCentre = pyh.off_axis_find_mod(backgroundImg)
cropRadius = pyh.off_axis_find_crop_radius(backgroundImg)
We can then demodulate using:
reconField = pyh.off_axis_demod(hologram, cropCentre, cropRadius)
To remove the background, recover the background field using:
backgroundField = pyh.off_axis_demod(background, cropCentre, cropRadius)
Remove the background phase (for example to due to aberrations in the imaging system) using:
correctedField = pyh.relative_phase(reconField, backgroundField)
The numpy array correctedField
is complex, to obtain the amplitude and phase, use:
amplitude = pyh.amplitude(reconField)
phase = pyh.phase(reconField)
If we would like to numerically refocus, we first define a propagator for use with the angular spectrum method. This requires specification of the hologram size, wavelength, pixel size and the depth we wish to refocus to:
gridSize = cropRadius * 2
wavelength = 0.5e-6
pixelSize = 2e-6
depth = 1e-3
prop = pyh.propagator(gridSize, wavelength, pixelSize, depth)
Note here that the gridSize
is the size of the reconstructed field following demodulation which is smaller than the original image.
The pixel size must also be specified as the pixel size in the reconstructed field, not the pixel size in the original hologram.
Pixel size, wavelength and depth must be in the same units.
We can then refocus using:
refocusedImg = pyh.refocus(correctedField, propagator)
The numpy array refocusedField
is a 2D complex numpy array, to obtain the amplitude and phase as 2D numpy arrays, use:
amplitude = pyh.amplitude(refocusedField)
phase = pyh.phase(refocusedField)