scikit-image
103 строки · 3.9 Кб
1import numpy as np2from scipy.spatial.distance import cdist3
4
5def match_descriptors(6descriptors1,7descriptors2,8metric=None,9p=2,10max_distance=np.inf,11cross_check=True,12max_ratio=1.0,13):14"""Brute-force matching of descriptors.15
16For each descriptor in the first set this matcher finds the closest
17descriptor in the second set (and vice-versa in the case of enabled
18cross-checking).
19
20Parameters
21----------
22descriptors1 : (M, P) array
23Descriptors of size P about M keypoints in the first image.
24descriptors2 : (N, P) array
25Descriptors of size P about N keypoints in the second image.
26metric : {'euclidean', 'cityblock', 'minkowski', 'hamming', ...} , optional
27The metric to compute the distance between two descriptors. See
28`scipy.spatial.distance.cdist` for all possible types. The hamming
29distance should be used for binary descriptors. By default the L2-norm
30is used for all descriptors of dtype float or double and the Hamming
31distance is used for binary descriptors automatically.
32p : int, optional
33The p-norm to apply for ``metric='minkowski'``.
34max_distance : float, optional
35Maximum allowed distance between descriptors of two keypoints
36in separate images to be regarded as a match.
37cross_check : bool, optional
38If True, the matched keypoints are returned after cross checking i.e. a
39matched pair (keypoint1, keypoint2) is returned if keypoint2 is the
40best match for keypoint1 in second image and keypoint1 is the best
41match for keypoint2 in first image.
42max_ratio : float, optional
43Maximum ratio of distances between first and second closest descriptor
44in the second set of descriptors. This threshold is useful to filter
45ambiguous matches between the two descriptor sets. The choice of this
46value depends on the statistics of the chosen descriptor, e.g.,
47for SIFT descriptors a value of 0.8 is usually chosen, see
48D.G. Lowe, "Distinctive Image Features from Scale-Invariant Keypoints",
49International Journal of Computer Vision, 2004.
50
51Returns
52-------
53matches : (Q, 2) array
54Indices of corresponding matches in first and second set of
55descriptors, where ``matches[:, 0]`` denote the indices in the first
56and ``matches[:, 1]`` the indices in the second set of descriptors.
57
58"""
59
60if descriptors1.shape[1] != descriptors2.shape[1]:61raise ValueError("Descriptor length must equal.")62
63if metric is None:64if np.issubdtype(descriptors1.dtype, bool):65metric = 'hamming'66else:67metric = 'euclidean'68
69kwargs = {}70# Scipy raises an error if p is passed as an extra argument when it isn't71# necessary for the chosen metric.72if metric == 'minkowski':73kwargs['p'] = p74distances = cdist(descriptors1, descriptors2, metric=metric, **kwargs)75
76indices1 = np.arange(descriptors1.shape[0])77indices2 = np.argmin(distances, axis=1)78
79if cross_check:80matches1 = np.argmin(distances, axis=0)81mask = indices1 == matches1[indices2]82indices1 = indices1[mask]83indices2 = indices2[mask]84
85if max_distance < np.inf:86mask = distances[indices1, indices2] < max_distance87indices1 = indices1[mask]88indices2 = indices2[mask]89
90if max_ratio < 1.0:91best_distances = distances[indices1, indices2]92distances[indices1, indices2] = np.inf93second_best_indices2 = np.argmin(distances[indices1], axis=1)94second_best_distances = distances[indices1, second_best_indices2]95second_best_distances[second_best_distances == 0] = np.finfo(np.float64).eps96ratio = best_distances / second_best_distances97mask = ratio < max_ratio98indices1 = indices1[mask]99indices2 = indices2[mask]100
101matches = np.column_stack((indices1, indices2))102
103return matches104