mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-07 18:53:42 +08:00
Improved match_binary_descriptors function
This commit is contained in:
committed by
Johannes Schönberger
parent
3ec1d35065
commit
a53d93e0f7
@@ -96,6 +96,9 @@ Library:
|
||||
Extension: skimage.feature.censure_cy
|
||||
Sources:
|
||||
skimage/feature/censure_cy.pyx
|
||||
Extension: skimage.feature.match_cy
|
||||
Sources:
|
||||
skimage/feature/match_cy.pyx
|
||||
Extension: skimage.feature.orb_cy
|
||||
Sources:
|
||||
skimage/feature/orb_cy.pyx
|
||||
|
||||
@@ -173,53 +173,3 @@ def brief(image, keypoints, descriptor_size=256, mode='normal', patch_size=49,
|
||||
_brief_loop(image, descriptors.view(np.uint8), keypoints, pos1, pos2)
|
||||
|
||||
return descriptors, keypoints
|
||||
|
||||
|
||||
def match_keypoints_brief(keypoints1, descriptors1, keypoints2,
|
||||
descriptors2, threshold=0.15):
|
||||
"""**Experimental function**.
|
||||
|
||||
Match keypoints described using BRIEF descriptors in one image to
|
||||
those in second image.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
keypoints1 : (M, 2) ndarray
|
||||
M Keypoints from the first image described using skimage.feature.brief
|
||||
descriptors1 : (M, P) ndarray
|
||||
BRIEF descriptors of size P about M keypoints in the first image.
|
||||
keypoints2 : (N, 2) ndarray
|
||||
N Keypoints from the second image described using skimage.feature.brief
|
||||
descriptors2 : (N, P) ndarray
|
||||
BRIEF descriptors of size P about N keypoints in the second image.
|
||||
threshold : float in range [0, 1]
|
||||
Maximum allowable hamming distance between descriptors of two keypoints
|
||||
in separate images to be regarded as a match. Default is 0.15.
|
||||
|
||||
Returns
|
||||
-------
|
||||
match_keypoints_brief : (Q, 2, 2) ndarray
|
||||
Location of Q matched keypoint pairs from two images.
|
||||
|
||||
"""
|
||||
if (keypoints1.shape[0] != descriptors1.shape[0]
|
||||
or keypoints2.shape[0] != descriptors2.shape[0]):
|
||||
raise ValueError("The number of keypoints and number of described "
|
||||
"keypoints do not match. Make the optional parameter "
|
||||
"return_keypoints True to get described keypoints.")
|
||||
|
||||
if descriptors1.shape[1] != descriptors2.shape[1]:
|
||||
raise ValueError("Descriptor sizes for matching keypoints in both "
|
||||
"the images should be equal.")
|
||||
|
||||
# Get hamming distances between keeypoints1 and keypoints2
|
||||
distance = pairwise_hamming_distance(descriptors1, descriptors2)
|
||||
|
||||
temp = distance > threshold
|
||||
row_check = np.any(~temp, axis=1)
|
||||
matched_keypoints2 = keypoints2[np.argmin(distance, axis=1)]
|
||||
matched_keypoint_pairs = np.zeros((np.sum(row_check), 2, 2), dtype=np.intp)
|
||||
matched_keypoint_pairs[:, 0, :] = keypoints1[row_check]
|
||||
matched_keypoint_pairs[:, 1, :] = matched_keypoints2[row_check]
|
||||
|
||||
return matched_keypoint_pairs
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import numpy as np
|
||||
|
||||
from .util import pairwise_hamming_distance
|
||||
from .match_cy import _binary_cross_check_loop
|
||||
|
||||
|
||||
def match_binary_descriptors(keypoints1, descriptors1, keypoints2,
|
||||
descriptors2, threshold=0.40, cross_check=True,
|
||||
return_mask=True):
|
||||
"""Match keypoints described using binary descriptors in one image to
|
||||
those in second image.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
keypoints1 : (M, 2) ndarray
|
||||
M Keypoints from the first image described using skimage.feature.brief
|
||||
descriptors1 : (M, P) ndarray
|
||||
BRIEF descriptors of size P about M keypoints in the first image.
|
||||
keypoints2 : (N, 2) ndarray
|
||||
N Keypoints from the second image described using skimage.feature.brief
|
||||
descriptors2 : (N, P) ndarray
|
||||
BRIEF descriptors of size P about N keypoints in the second image.
|
||||
threshold : float in range [0, 1]
|
||||
Maximum allowable hamming distance between descriptors of two keypoints
|
||||
in separate images to be regarded as a match.
|
||||
cross_check : bool
|
||||
Cross check if True.
|
||||
return_mask : bool
|
||||
Return index masks mask1 and mask2 for matched keypoints from
|
||||
keypoints1 and keypoints2 respectively.
|
||||
|
||||
Returns
|
||||
-------
|
||||
match_keypoints_pairs : (Q, 2, 2) ndarray
|
||||
Location of Q matched keypoint pairs from two images.
|
||||
mask1 : (Q,) ndarray
|
||||
Indices of keypoints in keypoints1 that have been matched. Returned
|
||||
only when return_mask is True.
|
||||
mask2 : (Q,) ndarray
|
||||
Indices of keypoints in keypoints2 that have been matched. Returned
|
||||
only when return_mask is True.
|
||||
|
||||
"""
|
||||
if (keypoints1.shape[0] != descriptors1.shape[0]
|
||||
or keypoints2.shape[0] != descriptors2.shape[0]):
|
||||
raise ValueError("The number of keypoints and number of described "
|
||||
"keypoints do not match.")
|
||||
|
||||
if descriptors1.shape[1] != descriptors2.shape[1]:
|
||||
raise ValueError("Descriptor sizes for matching keypoints in both "
|
||||
"the images should be equal.")
|
||||
|
||||
# Get hamming distances between keypoints1 and keypoints2
|
||||
distance = pairwise_hamming_distance(descriptors1, descriptors2)
|
||||
|
||||
if cross_check:
|
||||
matched_keypoints1_index = np.argmin(distance, axis=1)
|
||||
matched_keypoints2_index = np.argmin(distance, axis=0)
|
||||
|
||||
matched_index = _binary_cross_check_loop(matched_keypoints1_index,
|
||||
matched_keypoints2_index,
|
||||
distance, threshold)
|
||||
|
||||
matched_keypoint_pairs = np.zeros((matched_index.shape[0], 2, 2),
|
||||
dtype=np.intp)
|
||||
mask1 = matched_index[:, 0]
|
||||
mask2 = matched_index[:, 1]
|
||||
matched_keypoint_pairs[:, 0, :] = keypoints1[mask1]
|
||||
matched_keypoint_pairs[:, 1, :] = keypoints2[mask2]
|
||||
if return_mask:
|
||||
return (matched_keypoint_pairs, mask1, mask2)
|
||||
else:
|
||||
return matched_keypoint_pairs
|
||||
|
||||
else:
|
||||
temp = distance > threshold
|
||||
row_check = np.any(~temp, axis=1)
|
||||
matched_keypoints2 = keypoints2[np.argmin(distance, axis=1)]
|
||||
matched_keypoint_pairs = np.zeros((np.sum(row_check), 2, 2),
|
||||
dtype=np.intp)
|
||||
matched_keypoint_pairs[:, 0, :] = keypoints1[row_check]
|
||||
matched_keypoint_pairs[:, 1, :] = matched_keypoints2[row_check]
|
||||
mask1 = np.where(row_check == True)
|
||||
mask2 = np.argmin(distance, axis=1)[row_check]
|
||||
if return_mask:
|
||||
return (matched_keypoint_pairs, mask1, mask2)
|
||||
else:
|
||||
return matched_keypoint_pairs
|
||||
@@ -0,0 +1,21 @@
|
||||
import numpy as np
|
||||
|
||||
|
||||
def _binary_cross_check_loop(Py_ssize_t[:] matched_keypoints1_index,
|
||||
Py_ssize_t[:] matched_keypoints2_index,
|
||||
double[:, ::1] distance, double threshold):
|
||||
cdef Py_ssize_t i
|
||||
#matched_index = []
|
||||
|
||||
cdef Py_ssize_t count = 0
|
||||
cdef Py_ssize_t[:, ::1] matched_index = np.zeros((len(matched_keypoints1_index), 2), dtype=np.intp)
|
||||
|
||||
for i in range(len(matched_keypoints1_index)):
|
||||
if (matched_keypoints2_index[matched_keypoints1_index[i]] == i and
|
||||
distance[i, matched_keypoints1_index[i]] < threshold):
|
||||
#matched_index.append([i, matched_keypoints1_index[i]])
|
||||
matched_index[count, 0] = i
|
||||
matched_index[count, 1] = matched_keypoints1_index[i]
|
||||
count += 1
|
||||
|
||||
return np.asarray(matched_index[:count, :])
|
||||
@@ -9,7 +9,7 @@ import numpy as np
|
||||
from libc.math cimport sin, cos, M_PI, round
|
||||
|
||||
|
||||
pos = np.loadtxt('orb_descriptor_positions.txt', dtype=np.int8)
|
||||
pos = np.loadtxt("orb_descriptor_positions.txt", dtype=np.int8)
|
||||
pos0 = np.ascontiguousarray(pos[:, :2])
|
||||
pos1 = np.ascontiguousarray(pos[:, 2:])
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ def configuration(parent_package='', top_path=None):
|
||||
cython(['censure_cy.pyx'], working_path=base_path)
|
||||
cython(['orb_cy.pyx'], working_path=base_path)
|
||||
cython(['_brief_cy.pyx'], working_path=base_path)
|
||||
cython(['match_cy.pyx'], working_path=base_path)
|
||||
cython(['_texture.pyx'], working_path=base_path)
|
||||
cython(['_template.pyx'], working_path=base_path)
|
||||
|
||||
@@ -27,6 +28,8 @@ def configuration(parent_package='', top_path=None):
|
||||
include_dirs=[get_numpy_include_dirs()])
|
||||
config.add_extension('_brief_cy', sources=['_brief_cy.c'],
|
||||
include_dirs=[get_numpy_include_dirs()])
|
||||
config.add_extension('match_cy', sources=['match_cy.c'],
|
||||
include_dirs=[get_numpy_include_dirs()])
|
||||
config.add_extension('_texture', sources=['_texture.c'],
|
||||
include_dirs=[get_numpy_include_dirs(), '../_shared'])
|
||||
config.add_extension('_template', sources=['_template.c'],
|
||||
|
||||
Reference in New Issue
Block a user