Note
Go to the end to download the full example code.
Template Matching#
This example shows how the template matching is done in pyxem to find peaks in a diffraction pattern.
import numpy as np
import hyperspy.api as hs
import matplotlib.pyplot as plt
from skimage.morphology import disk
import pyxem as pxm
import pyxem.data.dummy_data.make_diffraction_test_data as mdtd
s = pxm.data.tilt_boundary_data()
How Template Matching Works#
Pyxem uses a window-normalized cross-correlation to find the peaks. This is much better for finding both strongly and weakly scattering peaks but sometimes if the window is too small, too large, or the wrong shape, the behavior can be unexpected.
template = disk(5)
padded_template = np.pad(template, 3) # padding a template increased the window size
padded_template_large = np.pad(
template, 20
) # padding a template increased the window size
template_normal = s.template_match(template)
template_padded = s.template_match(padded_template)
template_padded_large = s.template_match(padded_template_large)
ind = (5, 5)
hs.plot.plot_images(
[
s.inav[ind],
template_normal.inav[ind],
template_padded.inav[ind],
template_padded_large.inav[ind],
],
label=["Signal", "Normal Window", "Large Window", "Very Large Window"],
tight_layout=True,
per_row=2,
)

0%| | 0/33 [00:00<?, ?it/s]
58%|█████▊ | 19/33 [00:00<00:00, 180.21it/s]
100%|██████████| 33/33 [00:00<00:00, 170.70it/s]
0%| | 0/33 [00:00<?, ?it/s]
58%|█████▊ | 19/33 [00:00<00:00, 168.87it/s]
100%|██████████| 33/33 [00:00<00:00, 163.25it/s]
0%| | 0/33 [00:00<?, ?it/s]
45%|████▌ | 15/33 [00:00<00:00, 132.49it/s]
88%|████████▊ | 29/33 [00:00<00:00, 107.77it/s]
100%|██████████| 33/33 [00:00<00:00, 108.18it/s]
[<Axes: title={'center': 'Signal'}, xlabel='kx axis (px)', ylabel='ky axis (px)'>, <Axes: title={'center': 'Normal Window'}, xlabel='kx axis (px)', ylabel='ky axis (px)'>, <Axes: title={'center': 'Large Window'}, xlabel='kx axis (px)', ylabel='ky axis (px)'>, <Axes: title={'center': 'Very Large Window'}, xlabel='kx axis (px)', ylabel='ky axis (px)'>]
In the very large window case you can see that in the middle the strong zero beam is __included__ in the window and the intensity for those pixels is suppressed in the template matching. We also see this occurs in a square pattern because even though our template is a disk, the window is a square!
Template Matching with an Amorphous Halo#
Sometimes the template matching can be thrown off by an amorphous halo around the diffraction spots. This can be seen in the following example. In this case we can use a dilated (circular) window to reduce the effect of the imposed square window. This can be seen in the intensity of the diffraction vectors at +y,+x and -y,-x.
data = mdtd.generate_4d_data(
image_size_x=s.axes_manager.signal_axes[0].size,
image_size_y=s.axes_manager.signal_axes[1].size,
disk_x=s.axes_manager.signal_axes[0].size // 2,
disk_y=s.axes_manager.signal_axes[0].size // 2,
ring_r=45 / 128 * s.axes_manager.signal_axes[0].size // 2,
ring_x=s.axes_manager.signal_axes[0].size // 2,
ring_y=s.axes_manager.signal_axes[0].size // 2,
disk_I=10,
ring_lw=8,
ring_I=2,
)
amorphous_data = data + s
template_normal = amorphous_data.template_match_disk(disk_r=6, subtract_min=False)
template_circular = amorphous_data.template_match_disk(
disk_r=6, circular_background=True, template_dilation=5, subtract_min=False
)
mask = template_normal.get_direct_beam_mask(35)
mask2 = ~template_normal.get_direct_beam_mask(55)
template_normal.data[:, :, mask] = 0
template_circular.data[:, :, mask] = 0
template_normal.data[:, :, mask2] = 0
template_circular.data[:, :, mask2] = 0
f = plt.figure(figsize=(15, 5))
ind = (5, 5)
hs.plot.plot_images(
[amorphous_data.inav[ind], template_normal.inav[ind], template_circular.inav[ind]],
label=["Signal", "Square Window", "Circular Window"],
tight_layout=True,
per_row=3,
vmin=[0, 0.7, 0.7],
fig=f,
)

Make test data: 0%| | 0/100 [00:00<?, ?it/s]
Make test data: 3%|▎ | 3/100 [00:00<00:03, 25.85it/s]
Make test data: 6%|▌ | 6/100 [00:00<00:03, 25.84it/s]
Make test data: 9%|▉ | 9/100 [00:00<00:03, 25.86it/s]
Make test data: 12%|█▏ | 12/100 [00:00<00:03, 25.80it/s]
Make test data: 15%|█▌ | 15/100 [00:00<00:03, 26.04it/s]
Make test data: 18%|█▊ | 18/100 [00:00<00:03, 25.90it/s]
Make test data: 21%|██ | 21/100 [00:00<00:03, 25.86it/s]
Make test data: 24%|██▍ | 24/100 [00:00<00:02, 26.00it/s]
Make test data: 27%|██▋ | 27/100 [00:01<00:02, 25.90it/s]
Make test data: 30%|███ | 30/100 [00:01<00:02, 25.82it/s]
Make test data: 33%|███▎ | 33/100 [00:01<00:02, 25.76it/s]
Make test data: 36%|███▌ | 36/100 [00:01<00:02, 25.92it/s]
Make test data: 39%|███▉ | 39/100 [00:01<00:02, 25.82it/s]
Make test data: 42%|████▏ | 42/100 [00:01<00:02, 25.76it/s]
Make test data: 45%|████▌ | 45/100 [00:01<00:02, 25.72it/s]
Make test data: 48%|████▊ | 48/100 [00:01<00:02, 25.88it/s]
Make test data: 51%|█████ | 51/100 [00:01<00:01, 25.78it/s]
Make test data: 54%|█████▍ | 54/100 [00:02<00:01, 25.70it/s]
Make test data: 57%|█████▋ | 57/100 [00:02<00:01, 25.84it/s]
Make test data: 60%|██████ | 60/100 [00:02<00:01, 25.81it/s]
Make test data: 63%|██████▎ | 63/100 [00:02<00:01, 25.76it/s]
Make test data: 66%|██████▌ | 66/100 [00:02<00:01, 25.69it/s]
Make test data: 69%|██████▉ | 69/100 [00:02<00:01, 25.83it/s]
Make test data: 72%|███████▏ | 72/100 [00:02<00:01, 25.83it/s]
Make test data: 75%|███████▌ | 75/100 [00:02<00:00, 25.78it/s]
Make test data: 78%|███████▊ | 78/100 [00:03<00:00, 25.72it/s]
Make test data: 81%|████████ | 81/100 [00:03<00:00, 25.84it/s]
Make test data: 84%|████████▍ | 84/100 [00:03<00:00, 25.72it/s]
Make test data: 87%|████████▋ | 87/100 [00:03<00:00, 25.71it/s]
Make test data: 90%|█████████ | 90/100 [00:03<00:00, 25.86it/s]
Make test data: 93%|█████████▎| 93/100 [00:03<00:00, 25.73it/s]
Make test data: 96%|█████████▌| 96/100 [00:03<00:00, 25.72it/s]
Make test data: 99%|█████████▉| 99/100 [00:03<00:00, 25.70it/s]
Make test data: 100%|██████████| 100/100 [00:03<00:00, 25.80it/s]
0%| | 0/33 [00:00<?, ?it/s]
58%|█████▊ | 19/33 [00:00<00:00, 164.24it/s]
100%|██████████| 33/33 [00:00<00:00, 150.58it/s]
0%| | 0/33 [00:00<?, ?it/s]
45%|████▌ | 15/33 [00:00<00:00, 136.28it/s]
88%|████████▊ | 29/33 [00:00<00:00, 95.90it/s]
100%|██████████| 33/33 [00:00<00:00, 100.15it/s]
[<Axes: title={'center': 'Signal'}, xlabel='kx axis (px)', ylabel='ky axis (px)'>, <Axes: title={'center': 'Square Window'}, xlabel='kx axis (px)', ylabel='ky axis (px)'>, <Axes: title={'center': 'Circular Window'}, xlabel='kx axis (px)', ylabel='ky axis (px)'>]
Total running time of the script: (0 minutes 6.087 seconds)