Correlation-based peak finding and strain mapping reference

Blobfinder

Deprecated since version 0.4.0: Blobfinder has moved to its own package LiberTEM-blobfinder with a new structure. Please see https://libertem.github.io/LiberTEM-blobfinder/index.html for installation instructions and documentation of the new structure. Imports from libertem.udf.blobfinder trigger a FutureWarning starting from 0.4.0 and are supported until LiberTEM release 0.6.0.

Matching

These modules contain classes and helper functions that extract and manipulate lattices from correlation results.

class libertem.analysis.gridmatching.CorrelationResult(centers, refineds=None, peak_values=None, peak_elevations=None)[source]

Bases: object

Container class for the result of correlation-based refinement of peak positions within a frame.

class libertem.analysis.gridmatching.Match(correlation_result: CorrelationResult, selector, zero, a, b, indices)[source]

Bases: PointSelection

Class that represents a lattice match to a subset of a correlation result

The attributes are not guaranteed to be correct or sensible for the given lattice. The methods weighted_optimize() and optimize() calculate a derived Match with a best fit of zero, a and b based on the points and the indices.

zero

Declared zero point (y, x) of the lattice

Type:

numpy.ndarray

a

Declared “a” vector (y, x) of the lattice

Type:

numpy.ndarray

b

Declared “b” vector (y, x) of the lattice

Type:

numpy.ndarray

indices

List of indices (i, j) that are declared to express the matched points as linear combination of vectors a and b with reference to zero. The indices can be integers or floats, and they can be precise or approximate, depending on the matching method.

Type:

numpy.ndarray

calc_coords(indices=None, drop_zero=False, frame_shape=None, r=0)[source]

Shorthand to calculate peak coordinates.

Parameters:
  • indices (numpy.ndarray) – Indices to calculate coordinates for. Both an array of (y, x) pairs and the output of np.mgrid are supported.

  • drop_zero (bool) – Drop the zero order peak. This is important for virtual darkfield imaging.

  • frame_shape (Tuple[int, int]) – If set, the peaks are filtered with within_frame()

  • r (float) – Radius for within_frame()

Returns:

A list of (y, x) coordinate pairs for peaks

Return type:

numpy.ndarray

Raises:

ValueError – If the shape of indices is not as expected.

property calculated_refineds

Calculated peak positions based on lattice parameters and indices.

Type:

numpy.ndarray

property error

Weighted average distance between calculated and given peak position. numpy.float(‘inf’) if match of length zero.

Type:

float

classmethod invalid(correlation_result)[source]
Match

A Match instance with empty selector and all-‘nan’ attributes

optimize()[source]

Least square optimization of zero, a and b

Optimization to match the given points and indices.

Returns:

A new Match instance with optimized zero, a and b

Return type:

Match

Raises:

np.linalg.LinAlgError – If the solver didn’t find a solution.

weighted_optimize()[source]

Weighted least square optimization of zero, a and b

Optimization to match the given points and indices using peak_elevation as weight.

Returns:

A new Match instance with optimized zero, a and b

Return type:

Match

Raises:

np.linalg.LinAlgError – If the solver didn’t find a solution.

class libertem.analysis.gridmatching.Matcher(tolerance=3, min_weight=0.1, min_match=3)[source]

Bases: object

The main job of the Matcher object is managing the matching parameters and making them available for the various matching routines.

Parameters:
  • tolerance (float) – Position tolerance in px for peaks to be considered matches

  • min_weight (float) – Minimum peak elevation of a peak to be considered for matching

  • min_match (int) – Minimum number of matching peaks to be considered a match.

affinematch(centers, indices, refineds=None, peak_values=None, peak_elevations=None)[source]

This function creates a Match object from correlation_result and indices for all points. The indices can be non-integer and relative to any base vectors zero, a, b, including virtual ones like zero=(0, 0), a=(1, 0), b=(0, 1).

Refined values for zero, a and b that match the correlated peaks are then derived.

This match method is very fast, can be robust against a distorted field of view and works without determining a lattice. It matches the full CorrelationResult and does not reject random points or other outliers.

It is mathematically equivalent to calculating an affine transformation, as inspired by Giulio Guzzinati https://arxiv.org/abs/1902.06979

Parameters:
  • centers (numpy.ndarray) – numpy.ndarray of shape (n, 2) with integer centers (y, x) of peaks

  • refineds (numpy.ndarray) – numpy.ndarray of shape (n, 2) with float centers (y, x) of peaks (subpixel refinement)

  • peak_values (numpy.ndarray) – numpy.ndarray of shape (n,) with float maxima of correlation map of peaks

  • peak_values – numpy.ndarray of shape (n,) with float elevation of correlation map of peaks. See libertem_blobfinder.base.correlation.peak_elevation() for details.

  • indices (numpy.ndarray) – The indices assigned to each point of the CorrelationResult.

Returns:

Match

Return type:

Match

fastmatch(centers, zero, a, b, refineds=None, peak_values=None, peak_elevations=None)[source]

This function creates a Match object from correlation_result and approximates for zero point and lattice vectors a and b. This function is much, much faster than the full match. It works well to match a large number of point sets that share the same lattice vectors, for example from a larger grain or monocrystalline material. It rejects random points or other lattices in the CorrelationResult, provided they are not on near-integer positions of zero, a, b.

Parameters:
  • centers (numpy.ndarray) – numpy.ndarray of shape (n, 2) with integer centers (y, x) of peaks

  • refineds (numpy.ndarray) – numpy.ndarray of shape (n, 2) with float centers (y, x) of peaks (subpixel refinement)

  • peak_values (numpy.ndarray) – numpy.ndarray of shape (n,) with float maxima of correlation map of peaks

  • peak_elevations (numpy.ndarray) – numpy.ndarray of shape (n,) with float elevation of correlation map of peaks. See libertem_blobfinder.base.correlation.peak_elevation() for details.

  • zero (numpy.ndarray) – The near approximate zero point as numpy array (y, x).

  • a (numpy.ndarray) – The near approximate vectors a, b to match the grid as numpy arrays (y, x).

  • b (numpy.ndarray) – The near approximate vectors a, b to match the grid as numpy arrays (y, x).

Returns:

Match object with the optimized matching result.

Return type:

Match

class libertem.analysis.gridmatching.PointSelection(correlation_result: CorrelationResult, selector=None)[source]

Bases: object

Class that represents a subset of a correlation result.

selector

Boolean mask for all points in the correlation result, True indicating selected points.

Type:

numpy.ndarray

property centers

Integer centers (y, x) of correlation result masked with selector

Type:

numpy.ndarray

property peak_elevations

Peak elevations of correlation result masked with selector

Type:

numpy.ndarray

property peak_values

Peak heights of correlation result masked with selector

Type:

numpy.ndarray

property refineds

Refined float centers (y, x) of correlation result masked with selector

Type:

numpy.ndarray

libertem.analysis.gridmatching.get_indices(points, zero, a, b)[source]

Find indices to express each point as sum of lattice vectors from zero point

This could solve for arbitrarily many points, i.e. frame stacks instead of frame by frame With that the algorithm could actually match entire frame collections at once.

libertem.analysis.gridmatching.get_transformation(ref, peaks, center=None, weighs=None)[source]

Inspired by Giulio Guzzinati https://arxiv.org/abs/1902.06979

class libertem.analysis.fullmatch.FullMatcher(tolerance=3, min_weight=0.1, min_match=3, min_angle=0.3141592653589793, min_points=10, min_delta=0, max_delta=inf, min_candidates=3, max_candidates=7, clusterer=None, min_cluster_size_fraction=4, min_samples_fraction=20)[source]

Bases: Matcher

Extension of Matcher will full matching

Include the ability to guess grid parameters from a point cloud. This is separated from the other code since it currently only works with HDBSCAN, which can be problematic to install on some platforms. For that reason it is an optional dependency.

Parameters:
  • tolerance (float) – Position tolerance in px for peaks to be considered matches

  • min_weight (float) – Minimum peak elevation of a peak to be considered for matching

  • min_match (int) – Minimum number of matching peaks to be considered a match.

  • min_angle (float) – Minimum angle in radians between two vectors to be considered candidates

  • min_points (int) – Minimum points to try clustering matching. Otherwise match directly

  • min_delta (float) – Minimum length of a potential grid vector

  • max_delta (float) – Maximum length of a potential grid vector

  • min_candidates (int) – Minimum number of candidates to consider clustering matching successful. If not enough are found, the algorithm uses a brute-force search with all pairwise vectors between points

  • max_candidates (int) – Maximum number of candidates to return from clustering matching

  • clusterer – Instance of sklearn.cluster compatible clusterer. Default is HDBSCAN.

  • min_cluster_size_fraction (float) – Tuning parameter for clustering matching with HDBSCAN. Larger values allow smaller or fuzzier clusters. This is used to adapt the min_cluster_size parameter of HDBSCAN dynamically to the number of points to be matched. Set this to None to disable dynamic adjustment of min_cluster_size. If you like to set min_cluster_size to a constant value, you can set this to None and additionally set the clusterer parameter with your own clusterer object to have direct control over all parameters.

  • min_samples_fraction (float) – Tuning parameter for clustering matching with HDBSCAN. Larger values allow smaller or fuzzier clusters. This is used to adapt the min_samples parameter of HDBSCAN dynamically to the number of points to be matched. Set this to None to disable dynamic adjustment of min_samples. If you like to set min_samples to a constant value, you can set this to None and additionally set the clusterer parameter with your own clusterer object to have direct control over all parameters.

full_match(centers, zero=None, cand=None, refineds=None, peak_values=None, peak_elevations=None)[source]

This function extracts a list of Match objects as well two PointSelection objects for unmatched and weak points from correlation_result and zero point. The zero point is included in each of the matches because it is shared between all grids.

Parameters:
  • centers (numpy.ndarray) – numpy.ndarray of shape (n, 2) with integer centers (y, x) of peaks. This would typically be extracted with libertem_blobfinder.common.correlation.get_peaks()

  • zero (numpy.ndarray) – Zero point as numpy array (y, x).

  • cand (list or numpy.ndarray) – Optional list of candidate vectors (y, x) to use in a first matching round before guessing.

  • refineds (numpy.ndarray) – numpy.ndarray of shape (n, 2) with float centers (y, x) of peaks (subpixel refinement)

  • peak_values (numpy.ndarray) – numpy.ndarray of shape (n,) with float maxima of correlation map of peaks

  • peak_elevations (numpy.ndarray) – numpy.ndarray of shape (n,) with float elevation of correlation map of peaks. See libertem_blobfinder.base.correlation.peak_elevation() for details.

Returns:

matches: list of Match instances,

unmatched: instance of PointSelection,

weak: instance of PointSelection

Return type:

Tuple[List[libertem.analysis.gridmatching.Match, …], libertem.analysis.gridmatching.PointSelection, libertem.analysis.gridmatching.PointSelection]

Example

>>> peaks = np.array([
...     # First peak is zero if not specified otherwise
...     # Base lattice vectors (32, 0) and (0, 32)
...     (64, 64),
...     (32, 32), (32, 64), (32, 96),
...     (64, 32), (64, 96),
...     (96, 32), (96, 64), (96, 96),
... ])
>>> matcher = FullMatcher()
>>> (matches, unmatched, weak) = matcher.full_match(peaks)
>>> m = matches[0]
>>> assert np.allclose(m.zero, (64, 64))
>>> assert np.allclose(m.a, (32, 0))
>>> assert np.allclose(m.b, (0, 32))
make_polar_vectors(coords)[source]

Calculate all unique pairwise connecting polar vectors between points in coords.

The pairwise connecting vectors are converted to polar coordinates and filtered with parameters min_delta and max_delta to avoid calculating for unwanted higher order or random smaller vectors.

All calculated vectors have a positive or zero x direction.

exception libertem.analysis.fullmatch.NotFoundException[source]

Bases: Exception

libertem.analysis.fullmatch.angle_check(p1, p2, limit)[source]

Check if p1 and p2 have an angle difference of at least limit, both parallel or antiparallel

libertem.analysis.fullmatch.size_filter(polar, min_delta, max_delta)[source]

Accept a list of polar vectors Return a list of polar vectors with length between min_delta and max_delta