diff --git a/skimage/feature/fast.py b/skimage/feature/fast.py index 8194093e..36a4c7e1 100644 --- a/skimage/feature/fast.py +++ b/skimage/feature/fast.py @@ -6,17 +6,45 @@ from fast_cy import _corner_fast def corner_fast(image, n=12, threshold=0.15): + """Extract FAST corners for a given image. + + Parameters + ---------- + image : 2D ndarray + Input image. + n : integer + Number of consecutive pixels out of 16 pixels on the circle that + should be brighter or darker with respect to test pixel above the + `threshold` so as to classify the test pixel as a FAST corner. Also + stands for the n in `FAST-n` corner detector. + threshold : float + Threshold used in deciding whether the pixels on the circle are + brighter, darker or similar to the test pixel. Decrease the threshold + when more corners are desired and vice-versa. + + Returns + ------- + corners : (N, 2) ndarray + Location i.e. (row, col) of extracted FAST corners. + + References + ---------- + .. [1] Edward Rosten and Tom Drummond + "Machine Learning for high-speed corner detection", + http://www.edwardrosten.com/work/rosten_2006_machine.pdf + + """ image = np.squeeze(image) if image.ndim != 2: raise ValueError("Only 2-D gray-scale images supported.") image = np.ascontiguousarray(image, dtype=np.double) - corner = _corner_fast(image, n, threshold) + corner_response = _corner_fast(image, n, threshold) - corner_zero_mask = corner != 0 - c, d = np.nonzero(corner) - - maximas = (maximum_filter(corner, (3, 3)) == corner) & corner_zero_mask + # Non-maximal Suppression + corner_zero_mask = corner_response != 0 + maximas = (maximum_filter(corner_response, (3, 3)) == corner_response) & corner_zero_mask x, y = np.where(maximas == True) - return np.squeeze(np.dstack((x, y))) + corners = np.squeeze(np.dstack((x, y))) + return corners diff --git a/skimage/feature/fast_cy.pyx b/skimage/feature/fast_cy.pyx index a7af63c2..d80aa318 100644 --- a/skimage/feature/fast_cy.pyx +++ b/skimage/feature/fast_cy.pyx @@ -8,7 +8,7 @@ import numpy as np from ..util import img_as_float -def _corner_fast(double[:, ::1] image, int n, double threshold): +def _corner_response_fast(double[:, ::1] image, int n, double threshold): cdef int[:] rp = (np.round(3 * np.sin(2 * np.pi * np.arange(16, dtype=np.double) / 16))).astype(np.int32) cdef int[:] cp = (np.round(3 * np.cos(2 * np.pi * np.arange(16, dtype=np.double) / 16))).astype(np.int32) @@ -22,7 +22,7 @@ def _corner_fast(double[:, ::1] image, int n, double threshold): cdef int consecutive_count = 0 cdef double sum_b cdef double sum_d - cdef double[:, ::1] corner = np.zeros((rows, cols), dtype=np.double) + cdef double[:, ::1] corner_response = np.zeros((rows, cols), dtype=np.double) cdef double circle_intensity @@ -36,10 +36,13 @@ def _corner_fast(double[:, ::1] image, int n, double threshold): for k in range(16): circle_intensity = image[i + rp[k], j + cp[k]] if circle_intensity > image[i, j] + threshold: + # Brighter pixel bins[k] = 'b' elif circle_intensity < image[i, j] - threshold: + # Darker pixel bins[k] = 'd' else: + # Similar pixel bins[k] = 's' consecutive_count = 0 @@ -52,15 +55,16 @@ def _corner_fast(double[:, ::1] image, int n, double threshold): sum_b += image[i + rp[m], j + cp[m]] - image[i, j] - threshold elif bins[m] == 'd': sum_d += image[i, j] - image[i + rp[m], j + cp[m]] - threshold + # Finding the response of the corner if sum_d > sum_b: - corner[i, j] = sum_d + corner_response[i, j] = sum_d else: - corner[i, j] = sum_b + corner_response[i, j] = sum_b break else: consecutive_count = 0 - if corner[i, j] == 0: + if corner_response[i, j] == 0: consecutive_count = 0 for l in range(15 + n): if bins[l % 16] == 'd': @@ -71,12 +75,13 @@ def _corner_fast(double[:, ::1] image, int n, double threshold): sum_b += image[i + rp[m], j + cp[m]] - image[i, j] - threshold elif bins[m] == 'd': sum_d += image[i, j] - image[i + rp[m], j + cp[m]] - threshold + # Finding the response of the corner if sum_d > sum_b: - corner[i, j] = sum_d + corner_response[i, j] = sum_d else: - corner[i, j] = sum_b + corner_response[i, j] = sum_b break else: consecutive_count = 0 - return np.asarray(corner) + return np.asarray(corner_response)