From c3b6ce2c8270abd5801afcd1633f7600f3b2f071 Mon Sep 17 00:00:00 2001 From: Ankit Agrawal Date: Mon, 12 Aug 2013 23:51:19 +0530 Subject: [PATCH] Including min_scale as another input parameter --- skimage/feature/censure.py | 55 +++++++++++++++------------ skimage/feature/censure_cy.pyx | 42 +++++++++++++++++++- skimage/feature/tests/test_censure.py | 10 ++--- 3 files changed, 76 insertions(+), 31 deletions(-) diff --git a/skimage/feature/censure.py b/skimage/feature/censure.py index 18313eaf..996f7e16 100644 --- a/skimage/feature/censure.py +++ b/skimage/feature/censure.py @@ -19,10 +19,10 @@ STAR_FILTER_SHAPE = [(1, 0), (3, 1), (4, 2), (5, 3), (7, 4), (8, 5), (9, 6),(11, 8), (13, 10), (14, 11), (15, 12), (16, 14)] -def _get_filtered_image(image, max_scale, mode): +def _get_filtered_image(image, min_scale, max_scale, mode): - scales = np.zeros((image.shape[0], image.shape[1], max_scale), - dtype=np.double) + scales = np.zeros((image.shape[0], image.shape[1], + max_scale - min_scale +1), dtype=np.double) if mode == 'dob': @@ -34,8 +34,8 @@ def _get_filtered_image(image, max_scale, mode): integral_img = integral_image(image) - for i in range(max_scale): - n = i + 1 + for i in range(max_scale - min_scale + 1): + n = min_scale + i # Constant multipliers for the outer region and the inner region # of the bilevel filters with the constraint of keeping the @@ -54,16 +54,16 @@ def _get_filtered_image(image, max_scale, mode): elif mode == 'octagon': # TODO : Decide the shapes of Octagon filters for scales > 7 - for i in range(max_scale): - mo, no = OCTAGON_OUTER_SHAPE[i] - mi, ni = OCTAGON_INNER_SHAPE[i] + for i in range(max_scale - min_scale + 1): + mo, no = OCTAGON_OUTER_SHAPE[min_scale + i - 1] + mi, ni = OCTAGON_INNER_SHAPE[min_scale + i - 1] scales[:, :, i] = convolve(image, _octagon_filter_kernel(mo, no, mi, ni)) elif mode == 'star': - for i in range(max_scale): - m = STAR_SHAPE[STAR_FILTER_SHAPE[i][0]] - n = STAR_SHAPE[STAR_FILTER_SHAPE[i][1]] + for i in range(max_scale - min_scale + 1): + m = STAR_SHAPE[STAR_FILTER_SHAPE[min_scale + i - 1][0]] + n = STAR_SHAPE[STAR_FILTER_SHAPE[min_scale + i - 1][1]] scales[:, :, i] = convolve(image, _star_filter_kernel(m, n)) @@ -135,8 +135,8 @@ def _suppress_lines(feature_mask, image, sigma, line_threshold): > line_threshold * (Axx * Ayy - Axy * Axy)] = False -def keypoints_censure(image, max_scale=7, mode='DoB', non_max_threshold=0.15, - line_threshold=10): +def keypoints_censure(image, min_scale=1, max_scale=7, mode='DoB', + non_max_threshold=0.15, line_threshold=10): """ Extracts Censure keypoints along with the corresponding scale using either Difference of Boxes, Octagon or STAR bilevel filter. @@ -145,9 +145,12 @@ def keypoints_censure(image, max_scale=7, mode='DoB', non_max_threshold=0.15, ---------- image : 2D ndarray Input image. + min_scale : positive integer + Minimum scale to extract keypoints from. max_scale : positive integer - Number of scales to extract keypoints from. The keypoints will be - extracted from all the scales except the first and the last. + Maximum scale to extract keypoints from. The keypoints will be + extracted from all the scales except the first and the last i.e. + from the scales in the range [min_scale + 1, max_scale - 1]. mode : ('DoB', 'Octagon', 'STAR') Type of bilevel filter used to get the scales of the input image. Possible values are 'DoB', 'Octagon' and 'STAR'. The three modes @@ -197,8 +200,12 @@ def keypoints_censure(image, max_scale=7, mode='DoB', non_max_threshold=0.15, if mode not in ('dob', 'octagon', 'star'): raise ValueError('Mode must be one of "DoB", "Octagon", "STAR".') + if max_scale - min_scale < 2: + raise ValueError('The number of scales should be greater than or' + 'equal to 3.') + # Generating all the scales - filter_response = _get_filtered_image(image, max_scale, mode) + filter_response = _get_filtered_image(image, min_scale, max_scale, mode) # Suppressing points that are neither minima or maxima in their 3 x 3 x 3 # neighbourhood to zero @@ -208,17 +215,17 @@ def keypoints_censure(image, max_scale=7, mode='DoB', non_max_threshold=0.15, feature_mask = minimas | maximas feature_mask[filter_response < non_max_threshold] = False - for i in range(1, max_scale - 1): + for i in range(1, max_scale - min_scale): # sigma = (window_size - 1) / 6.0, so the window covers > 99% of the # kernel's distribution - # window_size = 7 + 2 * i - # Hence sigma = 1 + i / 3.0 + # window_size = 7 + 2 * (min_scale - 1 + i) + # Hence sigma = 1 + (min_scale - 1 + i)/ 3.0 _suppress_lines(feature_mask[:, :, i], image, - (1 + i / 3.0), line_threshold) + (1 + (min_scale + i - 1) / 3.0), line_threshold) - rows, cols, scales = np.nonzero(feature_mask[..., 1:max_scale - 1]) + rows, cols, scales = np.nonzero(feature_mask[..., 1:max_scale - min_scale]) keypoints = np.column_stack([rows, cols]) - scales = scales + 2 + scales = scales + min_scale + 1 if mode == 'dob': return keypoints, scales @@ -226,13 +233,13 @@ def keypoints_censure(image, max_scale=7, mode='DoB', non_max_threshold=0.15, cumulative_mask = np.zeros(keypoints.shape[0], dtype=np.bool) if mode == 'octagon': - for i in range(2, max_scale): + for i in range(min_scale + 1, max_scale): c = (OCTAGON_OUTER_SHAPE[i - 1][0] - 1) // 2 \ + OCTAGON_OUTER_SHAPE[i - 1][1] cumulative_mask |= _mask_border_keypoints(image, keypoints, c) \ & (scales == i) elif mode == 'star': - for i in range(2, max_scale): + for i in range(min_scale + 1, max_scale): c = STAR_SHAPE[STAR_FILTER_SHAPE[i - 1][0]] \ + STAR_SHAPE[STAR_FILTER_SHAPE[i - 1][0]] // 2 cumulative_mask |= _mask_border_keypoints(image, keypoints, c) \ diff --git a/skimage/feature/censure_cy.pyx b/skimage/feature/censure_cy.pyx index a9980071..1c352fde 100644 --- a/skimage/feature/censure_cy.pyx +++ b/skimage/feature/censure_cy.pyx @@ -18,8 +18,46 @@ def _censure_dob_loop(Py_ssize_t n, cdef Py_ssize_t n2 = 2 * n cdef double total_weight = inner_weight + outer_weight - for i in range(n2, integral_img.shape[0] - n2): - for j in range(n2, integral_img.shape[1] - n2): + # top-left pixel + inner = (integral_img[n2 + n, n2 + n] + + integral_img[n2 - n - 1, n2 - n - 1] + - integral_img[n2 + n, n2 - n - 1] + - integral_img[n2 - n - 1, n2 + n]) + + outer = integral_img[2 * n2, 2 * n2] + + filtered_image[n2, n2] = (outer_weight * outer + - total_weight * inner) + + # left column + for i in range(n2 + 1, integral_img.shape[0] - n2): + inner = (integral_img[i + n, n2 + n] + + integral_img[i - n - 1, n2 - n - 1] + - integral_img[i + n, n2 - n - 1] + - integral_img[i - n - 1, n2 + n]) + + outer = (integral_img[i + n2, 2 * n2] + - integral_img[i - n2 - 1, 2 * n2]) + + filtered_image[i, n2] = (outer_weight * outer + - total_weight * inner) + + # top row + for j in range(n2 + 1, integral_img.shape[1] - n2): + inner = (integral_img[n2 + n, j + n] + + integral_img[n2 - n - 1, j - n - 1] + - integral_img[n2 + n, j - n - 1] + - integral_img[n2 - n - 1, j + n]) + + outer = (integral_img[2 * n2, j + n2] + - integral_img[2 * n2, j - n2 - 1]) + + filtered_image[n2, j] = (outer_weight * outer + - total_weight * inner) + + # remaining block + for i in range(n2 + 1, integral_img.shape[0] - n2): + for j in range(n2 + 1, integral_img.shape[1] - n2): inner = (integral_img[i + n, j + n] + integral_img[i - n - 1, j - n - 1] - integral_img[i + n, j - n - 1] diff --git a/skimage/feature/tests/test_censure.py b/skimage/feature/tests/test_censure.py index 5401eed1..26555697 100644 --- a/skimage/feature/tests/test_censure.py +++ b/skimage/feature/tests/test_censure.py @@ -14,7 +14,7 @@ def test_keypoints_censure_moon_image_dob(): """Verify the actual Censure keypoints and their corresponding scale with the expected values for DoB filter.""" img = moon() - actual_kp_dob, actual_scale = keypoints_censure(img, 7, 'DoB', 0.15) + actual_kp_dob, actual_scale = keypoints_censure(img, 1, 7, 'DoB', 0.15) expected_kp_dob = np.array([[ 21, 497], [ 36, 46], [119, 350], @@ -30,11 +30,11 @@ def test_keypoints_censure_moon_image_dob(): assert_array_equal(expected_scale, actual_scale) -def test_keypoints_censure_moon_image_Octagon(): +def test_keypoints_censure_moon_image_octagon(): """Verify the actual Censure keypoints and their corresponding scale with the expected values for Octagon filter.""" img = moon() - actual_kp_octagon, actual_scale = keypoints_censure(img, 7, 'Octagon', + actual_kp_octagon, actual_scale = keypoints_censure(img, 1, 7, 'Octagon', 0.15) expected_kp_octagon = np.array([[ 21, 496], [ 35, 46], @@ -48,11 +48,11 @@ def test_keypoints_censure_moon_image_Octagon(): assert_array_equal(expected_scale, actual_scale) -def test_keypoints_censure_moon_image_STAR(): +def test_keypoints_censure_moon_image_star(): """Verify the actual Censure keypoints and their corresponding scale with the expected values for STAR filter.""" img = moon() - actual_kp_star, actual_scale = keypoints_censure(img, 7, 'STAR', 0.15) + actual_kp_star, actual_scale = keypoints_censure(img, 1, 7, 'STAR', 0.15) expected_kp_star = np.array([[ 21, 497], [ 36, 46], [117, 356],