HoloPy can work with any kind of image data, but we use it for digital holograms, so our tutorials will focus mostly on hologram data.

We include a couple of example holograms with HoloPy. Lets start by loading and viewing one of them

import holopy as hp
from holopy.core.io import get_example_data_path
imagepath = get_example_data_path('image01.jpg')
raw_holo = hp.load_image(imagepath, spacing = 0.0851)
hp.show(raw_holo)


The first few lines just specify where to look for an image. The most important line actually loads the image so that you can work with it:

raw_holo = hp.load_image(imagepath, spacing = 0.0851)


HoloPy can import any image format that can be handled by Pillow.

The spacing argument tells holopy about the scale of your image. Here, we had previously measured that each pixel is a square with side length 0.0851 microns. In general, you should specify spacing as the distance between adjacent pixel centres. You can also load an image without specifying a spacing value if you just want to look at it, but most holopy calculations will give erroneous results on such an image.

The final line simply displays the loaded image on your screen with the built-in HoloPy show() function. If you don’t see anything, you may need to set your matplotlib backend. Refer to Using HoloPy for instructions.

## Correcting Noisy Images¶

The raw hologram has some non-uniform illumination and an artifact in the upper right hand corner from dust somewhere in the optics. These types of things can be removed if you are able to take a background image with the same optical setup but without the object of interest. Dividing the raw hologram by the background using bg_correct() can usually improve the image a lot.

from holopy.core.process import bg_correct
bgpath = get_example_data_path('bg01.jpg')
bg = hp.load_image(bgpath, spacing = 0.0851)
holo = bg_correct(raw_holo, bg)
hp.show(holo)


Often, it is beneficial to record multiple background images. In this case, we want an average image to pass into bg_correct() as our background.

bgpath = get_example_data_path(['bg01.jpg', 'bg02.jpg', 'bg03.jpg'])
bg = hp.core.io.load_average(bgpath, refimg = raw_holo)
holo = bg_correct(raw_holo, bg)
hp.show(holo)


Here, we have used load_average() to construct an average of the three background images specified in bgpath. The refimg argument allows us to specify a reference image that is used to provide spacing and other metadata to the new, averaged image.

If you are worried about stray light in your optical train, you should also capture a dark-field image of your sample, recorded with no laser illumination. A dark-field image is specified as an optional third argument to bg_correct().

dfpath = get_example_data_path('df01.jpg')
df = hp.load_image(dfpath, spacing = 0.0851)
holo = bg_correct(raw_holo, bg, df)
hp.show(holo)


Some convenient tools for manipulating image data are included within HoloPy. See the HoloPy Tools page for details.

Recorded holograms are a product of the specific experimental setup that produced them. The image only makes sense when considered with information about the experimental conditions in mind. When you load an image, you have the option to specify some of this information in the form of metadata that is associated with the image. In fact, we already saw an example of this when we specified image spacing earlier. The sample in our image was immersed in water, which has a refractive index of 1.33. It was illuminated by a red laser with wavelength of 660 nm and polarization in the x-direction. We can tell HoloPy all of this information when loading the image:

raw_holo = hp.load_image(imagepath, spacing=0.0851, medium_index=1.33, illum_wavelen=0.660, illum_polarization=(1,0))


You can then view these metadata values as attributes of raw_holo, as in raw_holo.medium_index. However, you must use a special function update_metadata() to edit them. If we forgot to specify metadata when loading the image, we can use update_metadata() to add it later:

holo = hp.core.update_metadata(holo, medium_index=1.33, illum_wavelen=0.660, illum_polarization=(1,0))


Note

Spacing and wavelength must both be written in the same units - microns in the example above. Holopy has no built-in length scale and requires only that you be consistent. For example, we could have specified both parameters in terms of nanometers or meters instead.

HoloPy images are stored as xarray DataArray objects. xarray is a powerful tool that makes it easy to keep track of metadata and extra image dimensions, distinguishing between a time slice and a volume slice, for example. While you do not need any knowledge of xarray to use HoloPy, some familiarity will make certain tasks easier. This is especially true if you want to directly manipulate data before or after applying HoloPy’s built-in functions.

Once you have background-divided a hologram and associated it with metadata, you might want to save it so that you can skip those steps next time you are working with the same image:

hp.save('outfilename', holo)


saves your processed image to a compact HDF5 file. In fact, you can use save() on any holopy object. To reload your same hologram with metadata you would write:

holo = hp.load('outfilename')


If you would like to save your hologram to an image format for easy visualization, use:

hp.save_image('outfilename', holo)


Additional options of save_image() allow you to control how image intensity is scaled. Images saved as .tif (the default) will still contain metadata, which will be retrieved if you reload with load(), but not load_image()

Note

Although HoloPy stores metadata even when writing to .tif image files, it is still recommended that holograms be saved in HDF5 format using save(). Floating point intensity values are rounded to 8-bit integers when using save_image(), resulting in information loss.

## Non-Square Pixels¶

The holograms above make use of several default assumptions. When you load an image like:

raw_holo = hp.load_image(imagepath, spacing = 0.0851)


you are making HoloPy assume a square array of evenly spaced grid points. If your pixels are not square, you can provide pixel spacing values in each direction:

raw_holo = hp.load_image(imagepath, spacing = (0.0851, 0.0426))


Most displays will default to displaying square pixels but if you use HoloPy’s built-in show() function to display the image, your hologram will display with pixels of the correct aspect ratio.