Improved match_binary_descriptors function

This commit is contained in:
Ankit Agrawal
2013-09-21 03:13:30 +05:30
committed by Johannes Schönberger
parent 3ec1d35065
commit a53d93e0f7
6 changed files with 116 additions and 51 deletions
+3
View File
@@ -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
-50
View File
@@ -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
+88
View File
@@ -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
+21
View File
@@ -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, :])
+1 -1
View File
@@ -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:])
+3
View File
@@ -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'],