Files
scikit-image/skimage/feature/_brief.py
T

157 lines
6.2 KiB
Python

import numpy as np
from scipy.ndimage.filters import gaussian_filter
from ..util import img_as_float
from .util import _remove_border_keypoints
from ._brief_cy import _brief_loop
def brief(image, keypoints, descriptor_size=256, mode='normal', patch_size=49,
sample_seed=1, variance=2, return_keypoints=False):
"""Extract BRIEF Descriptor about given keypoints for a given image.
Parameters
----------
image : 2D ndarray
Input image.
keypoints : (P, 2) ndarray
Array of keypoint locations.
descriptor_size : int
Size of BRIEF descriptor about each keypoint. Sizes 128, 256 and 512
preferred by the authors. Default is 256.
mode : string
Probability distribution for sampling location of decision pixel-pairs
around keypoints. Default is 'normal' otherwise uniform.
patch_size : int
Length of the two dimensional square patch sampling region around
the keypoints. Default is 49.
sample_seed : int
Seed for sampling the decision pixel-pairs. Default is 1.
return_keypoints : bool
If True, return the Q keypoints (after filtering out the border
keypoints) about which the descriptors are extracted. Default is False.
Returns
-------
descriptors : (Q, descriptor_size) ndarray of dtype bool
2D ndarray of binary descriptors of size descriptor_size about Q
keypoints after filtering out border keypoints with value at an index
(i, j) either being True or False representing the outcome
of Intensity comparison about ith keypoint on jth decision pixel-pair.
keypoints : (Q, 2) ndarray
Keypoints after removing out those that are near border.
Returned only if return_keypoints is True.
References
----------
.. [1] Michael Calonder, Vincent Lepetit, Christoph Strecha and Pascal Fua
"BRIEF : Binary robust independent elementary features",
http://cvlabwww.epfl.ch/~lepetit/papers/calonder_eccv10.pdf
Examples
--------
>>> from skimage.feature.corner import *
>>> from skimage.feature import brief, hamming_distance
>>> square1 = np.zeros([10, 10])
>>> square1[2:8, 2:8] = 1
>>> square1
array([[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 1., 1., 1., 1., 1., 1., 0., 0.],
[ 0., 0., 1., 1., 1., 1., 1., 1., 0., 0.],
[ 0., 0., 1., 1., 1., 1., 1., 1., 0., 0.],
[ 0., 0., 1., 1., 1., 1., 1., 1., 0., 0.],
[ 0., 0., 1., 1., 1., 1., 1., 1., 0., 0.],
[ 0., 0., 1., 1., 1., 1., 1., 1., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
>>> keypoints1 = corner_peaks(corner_harris(square1), min_distance=1)
>>> keypoints1
array([[2, 2],
[2, 7],
[7, 2],
[7, 7]])
>>> descriptors1 = brief(square1, keypoints1, patch_size = 5)
>>> square2 = np.zeros([12, 12])
>>> square2[3:9, 3:9] = 1
>>> square2
array([[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 1., 1., 1., 1., 1., 1., 0., 0., 0.],
[ 0., 0., 0., 1., 1., 1., 1., 1., 1., 0., 0., 0.],
[ 0., 0., 0., 1., 1., 1., 1., 1., 1., 0., 0., 0.],
[ 0., 0., 0., 1., 1., 1., 1., 1., 1., 0., 0., 0.],
[ 0., 0., 0., 1., 1., 1., 1., 1., 1., 0., 0., 0.],
[ 0., 0., 0., 1., 1., 1., 1., 1., 1., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
>>> keypoints2 = corner_peaks(corner_harris(square2), min_distance=1)
>>> keypoints2
array([[3, 3],
[3, 8],
[8, 3],
[8, 8]])
>>> descriptors2 = brief(square2, keypoints1, patch_size = 5)
>>> hamming_distance(descriptors1, descriptors2)
array([[ 0.02734375, 0.2890625 , 0.32421875, 0.6171875 ],
[ 0.3359375 , 0.05078125, 0.6640625 , 0.37109375],
[ 0.359375 , 0.64453125, 0.03125 , 0.33203125],
[ 0.640625 , 0.40234375, 0.3828125 , 0.01953125]])
"""
np.random.seed(sample_seed)
image = np.squeeze(image)
if image.ndim != 2:
raise ValueError("Only 2-D gray-scale images supported.")
image = img_as_float(image)
# Gaussian Low pass filtering to alleviate noise
# sensitivity
image = gaussian_filter(image, variance)
image = np.ascontiguousarray(image)
keypoints = np.array(keypoints + 0.5, dtype=np.intp, order='C')
# Removing keypoints that are (patch_size / 2) distance from the image
# border
keypoints = _remove_border_keypoints(image, keypoints, patch_size / 2)
descriptors = np.zeros((keypoints.shape[0], descriptor_size),
dtype=bool, order='C')
# Sampling pairs of decision pixels in patch_size x patch_size window
if mode == 'normal':
samples = (patch_size / 5) * np.random.randn(descriptor_size * 8)
samples = np.array(samples, dtype=np.int32)
samples = samples[(samples < (patch_size / 2))
& (samples > - (patch_size - 1) / 2)]
pos1 = samples[:descriptor_size * 2]
pos1 = pos1.reshape(descriptor_size, 2)
pos2 = samples[descriptor_size * 2:descriptor_size * 4]
pos2 = pos2.reshape(descriptor_size, 2)
else:
samples = np.random.randint(-patch_size / 2, (patch_size / 2) + 1,
(descriptor_size * 2, 2))
pos1, pos2 = np.split(samples, 2)
pos1 = np.ascontiguousarray(pos1)
pos2 = np.ascontiguousarray(pos2)
_brief_loop(image, descriptors.view(np.uint8), keypoints, pos1, pos2)
if return_keypoints:
return descriptors, keypoints
else:
return descriptors