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).
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 57 | 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):
print("Downloading {} ...".format(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_mask=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.
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 | 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_next_major/" \
+ "hyperspy/misc/holography/example_signals/"
dl_name = "01_holo_Vbp_130V_0V_bin2_crop.hdf5"
if not os.path.exists(dl_name):
print("Downloading {} ...".format(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/
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 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/
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)
|