Examples

Hologram from tif file

This example illustrates how to retrieve phase and amplitude from a hologram stored as a tif file. The experimental hologram is a U.S. Air Force test target downloaded from the Submersible Holographic Astrobiology Microscope with Ultraresolution (SHAMU) project [BBL+17]. The values for pixel resolution, wavelength, and reconstruction distance are taken from the corresponding Python example.

The object returned by the get_qpimage <qpformat.file_formats.dataset.SingleData.get_qpimage() function is an instance of qpimage.QPImage which allows for field refocusing. The refocused QPImage is background-corrected using a polynomial fit to the phase data at locations where the amplitude data is not attenuated (bright regions in the amplitude image).

_images/tif_hologram.jpg

tif_hologram.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import urllib.request
import os

import matplotlib.pylab as plt
import qpformat


# load the experimental data
dl_loc = "https://github.com/bmorris3/shampoo/raw/master/data/"
dl_name = "USAF_test.tif"
if not os.path.exists(dl_name):
    urllib.request.urlretrieve(dl_loc + dl_name, dl_name)


ds = qpformat.load_data(dl_name,
                        # manually set meta data
                        meta_data={"pixel size": 3.45e-6,
                                   "wavelength": 405e-9,
                                   "medium index": 1},
                        # set filter size to 1/2 (defaults to 1/3)
                        # which increases the image resolution
                        holo_kw={"filter_size": .5})

# retrieve the qpimage.QPImage instance
qpi = ds.get_qpimage()
# refocus `qpi` to 0.03685m
qpi_foc = qpi.refocus(0.03685)
# perform an offset-based amplitude correction
qpi_foc.compute_bg(which_data="amplitude",
                   fit_profile="offset",
                   fit_offset="mode",
                   border_px=10,
                   )
# perform a phase correction using
# - those pixels that are not dark in the amplitude image (amp_bin) and
# - a 2D second order polynomial fit to the phase data
amp_bin = qpi_foc.amp > 1  # bright regions
qpi_foc.compute_bg(which_data="phase",
                   fit_profile="poly2o",
                   from_binary=amp_bin,
                   )

# plot results
plt.figure(figsize=(8, 3.5))
# ampltitude
ax1 = plt.subplot(121, title="amplitude")
map1 = plt.imshow(qpi_foc.amp, cmap="gray")
plt.colorbar(map1, ax=ax1, fraction=.0455, pad=0.04)
# phase in interval [-1rad, 1rad]
ax2 = plt.subplot(122, title="phase [rad]")
map2 = plt.imshow(qpi_foc.pha, vmin=-1, vmax=1)
plt.colorbar(map2, ax=ax2, fraction=.0455, pad=0.04)
# disable axes
[ax.axis("off") for ax in [ax1, ax2]]
plt.tight_layout()
plt.show()

HyperSpy hologram file format

This example demonstrates the import of hologram images in the HyperSpy hdf5 file format. The off-axis electron hologram shows an electrically biased Fe needle [MLFDB15]. The corresponding HyperSpy demo can be found here.

_images/hyperspy_hologram.jpg

hyperspy_hologram.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import urllib.request
import os

import matplotlib.pylab as plt
import qpformat

# load the experimental data
dl_loc = "https://github.com/hyperspy/hyperspy/raw/RELEASE_v1.3/" \
         + "hyperspy/misc/holography/example_signals/"
dl_name = "01_holo_Vbp_130V_0V_bin2_crop.hdf5"
if not os.path.exists(dl_name):
    urllib.request.urlretrieve(dl_loc + dl_name, dl_name)

ds = qpformat.load_data(dl_name,
                        holo_kw={
                            # reduces ringing artifacts in the amplitude image
                            "filter_name": "smooth disk",
                            # select correct sideband
                            "sideband": -1,
                            })

# retrieve the qpimage.QPImage instance
qpi = ds.get_qpimage(0)

# plot results
plt.figure(figsize=(8, 3.5))
# ampltitude
ax1 = plt.subplot(121, title="amplitude")
map1 = plt.imshow(qpi.amp, cmap="gray")
plt.colorbar(map1, ax=ax1, fraction=.0455, pad=0.04)
# phase in interval [-1rad, 1rad]
ax2 = plt.subplot(122, title="phase [rad]")
map2 = plt.imshow(qpi.pha)
plt.colorbar(map2, ax=ax2, fraction=.0455, pad=0.04)
# disable axes
[ax.axis("off") for ax in [ax1, ax2]]
plt.tight_layout()
plt.show()

Conversion of external file formats to .npy files

Sometimes the data recorded are not in a file format supported by qpformat or it is not feasible to implement a reader class for a very unique data set. In this example, QPI data, stored as a tuple of files (“*_intensity.txt” and “*_phase.txt”) with commas as decimal separators, are converted to the numpy file format which is supported by qpformat.

This example must be executed with a directory as an command line argument, i.e. python convert_txt2npy.py /path/to/folder/

convert_txt2npy.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import pathlib
import sys

import numpy as np


def get_paths(folder):
    '''Return *_phase.txt files in `folder`'''
    folder = pathlib.Path(folder).resolve()
    files = folder.rglob("*_phase.txt")
    return sorted(files)


def load_file(path):
    '''Load a txt data file'''
    path = pathlib.Path(path)
    data = path.open().readlines()
    # remove comments and empty lines
    data = [l for l in data if len(l.strip()) and not l.startswith("#")]
    # determine data shape
    n = len(data)
    m = len(data[0].strip().split())
    res = np.zeros((n, m), dtype=np.dtype(float))
    # write data to array, replacing comma with point decimal separator
    for ii in range(n):
        res[ii] = np.array(data[ii].strip().replace(",", ".").split(),
                           dtype=float)
    return res


def load_field(path):
    '''Load QPI data using *_phase.txt files'''
    path = pathlib.Path(path)
    phase = load_file(path)
    inten = load_file(path.parent / (path.name[:-10] + "_intensity.txt"))
    ampli = np.sqrt(inten)
    return ampli * np.exp(1j * phase)


if __name__ == "__main__":
    path = pathlib.Path(sys.argv[-1])
    if not path.is_dir():
        raise ValueError("Command line argument must be directory!")
    # output directory
    pout = path.parent / (path.name + "_npy")
    pout.mkdir(exist_ok=True)
    # get input *_phase.txt files
    files = get_paths(path)
    # conversion
    for ff in files:
        field = load_field(ff)
        np.save(str(pout / (ff.name[:-10] + ".npy")), field)

Conversion of external holograms to .tif files

Qpformat can load hologram data from .tif image files. If your experimental hologram data are stored in a different file format, you can either request its implementation in qpformat by `creating an issue<https://github.com/RI-imaging/qpformat/issues/new>`_ or you can modify this example script to your needs.

This example must be executed with a directory as an command line argument, i.e. python convert_txt2tif.py /path/to/folder/

convert_txt2tif.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import pathlib
import sys

import numpy as np
from skimage.external import tifffile

# File names ending with these strings are ignored
ignore_endswith = ['.bmp', '.npy', '.opj', '.png', '.pptx', '.py', '.svg',
                   '.tif', '.txt', '_RIdist', '_parameter', '_parameter_old',
                   '_phase', 'n_array', 'n_array_real', '~']
# uncomment this line to keep background hologram files
ignore_endswith += ['_bg']


def get_paths(folder, ignore_endswith=ignore_endswith):
    '''Return hologram file paths

    Parameters
    ----------
    folder: str or pathlib.Path
        Path to search folder
    ignore_endswith: list
        List of filename ending strings indicating which
        files should be ignored.
    '''
    folder = pathlib.Path(folder).resolve()
    files = folder.rglob("*")
    for ie in ignore_endswith:
        files = [ff for ff in files if not ff.name.endswith(ie)]
    return sorted(files)


if __name__ == "__main__":
    path = pathlib.Path(sys.argv[-1])
    if not path.is_dir():
        raise ValueError("Command line argument must be directory!")
    # output directory
    pout = path.parent / (path.name + "_tif")
    pout.mkdir(exist_ok=True)
    # get input hologram files
    files = get_paths(path)
    # conversion
    for ff in files:
        # convert image data to uint8 (most image sensors)
        hol = np.loadtxt(str(ff), dtype=np.uint8)
        tifout = str(pout / (ff.name + ".tif"))
        # compress image data
        tifffile.imsave(tifout, hol, compress=9)