diff --git a/skimage/feature/corner.py b/skimage/feature/corner.py index 6081e1a2..e8d31abe 100644 --- a/skimage/feature/corner.py +++ b/skimage/feature/corner.py @@ -799,7 +799,7 @@ def corner_subpix(image, corners, window_size=11, alpha=0.99): return corners_subpix -def corner_peaks(image, min_distance=10, threshold_abs=0, threshold_rel=0.1, +def corner_peaks(image, min_distance=1, threshold_abs=None, threshold_rel=None, exclude_border=True, indices=True, num_peaks=np.inf, footprint=None, labels=None): """Find corners in corner measure response image. diff --git a/skimage/feature/peak.py b/skimage/feature/peak.py index fd2c7047..8bac92bf 100644 --- a/skimage/feature/peak.py +++ b/skimage/feature/peak.py @@ -3,7 +3,7 @@ import scipy.ndimage as ndi from ..filters import rank_order -def peak_local_max(image, min_distance=1, threshold_abs=-np.inf, +def peak_local_max(image, min_distance=1, threshold_abs=None, threshold_rel=None, exclude_border=True, indices=True, num_peaks=np.inf, footprint=None, labels=None): """ @@ -28,8 +28,7 @@ def peak_local_max(image, min_distance=1, threshold_abs=-np.inf, threshold_abs : float, optional Minimum intensity of peaks. threshold_rel : float, optional - Minimum intensity of peaks calculated as `max(image) * threshold_rel`; - not used if set to None (the default). + Minimum intensity of peaks, calculated as `max(image) * threshold_rel`. exclude_border : bool, optional If True, `min_distance` excludes peaks from the border of the image as well as from each other. @@ -124,7 +123,6 @@ def peak_local_max(image, min_distance=1, threshold_abs=-np.inf, else: return out - image = image.copy() # Non maximum filter if footprint is not None: image_max = ndi.maximum_filter(image, footprint=footprint, @@ -133,22 +131,24 @@ def peak_local_max(image, min_distance=1, threshold_abs=-np.inf, size = 2 * min_distance + 1 image_max = ndi.maximum_filter(image, size=size, mode='constant') mask = (image == image_max) - image *= mask if exclude_border: # zero out the image borders - for i in range(image.ndim): - image = image.swapaxes(0, i) + for i in range(mask.ndim): + mask = mask.swapaxes(0, i) remove = (footprint.shape[i] if footprint is not None else 2 * min_distance) - image[:remove // 2] = 0 - image[-remove // 2:] = 0 - image = image.swapaxes(0, i) + mask[:remove // 2] = mask[-remove // 2:] = False + mask = mask.swapaxes(0, i) # find top peak candidates above a threshold - peak_threshold = threshold_abs + thresholds = [] + if threshold_abs is not None: + thresholds.append(threshold_abs) if threshold_rel is not None: - peak_threshold = max(peak_threshold, image.max()) + thresholds.append(threshold_rel * image.max()) + if thresholds: + mask &= image > max(thresholds) # get coordinates of peaks coordinates = np.argwhere(image > peak_threshold) diff --git a/skimage/feature/tests/test_corner.py b/skimage/feature/tests/test_corner.py index 953e47e3..e8db0b46 100644 --- a/skimage/feature/tests/test_corner.py +++ b/skimage/feature/tests/test_corner.py @@ -107,21 +107,25 @@ def test_square_image(): im[:25, :25] = 1. # Moravec - results = peak_local_max(corner_moravec(im)) + results = peak_local_max(corner_moravec(im), + min_distance=10, threshold_rel=0) # interest points along edge assert len(results) == 57 # Harris - results = peak_local_max(corner_harris(im, method='k')) + results = peak_local_max(corner_harris(im, method='k'), + min_distance=10, threshold_rel=0) # interest at corner assert len(results) == 1 - results = peak_local_max(corner_harris(im, method='eps')) + results = peak_local_max(corner_harris(im, method='eps'), + min_distance=10, threshold_rel=0) # interest at corner assert len(results) == 1 # Shi-Tomasi - results = peak_local_max(corner_shi_tomasi(im)) + results = peak_local_max(corner_shi_tomasi(im), + min_distance=10, threshold_rel=0) # interest at corner assert len(results) == 1 @@ -133,18 +137,22 @@ def test_noisy_square_image(): im = im + np.random.uniform(size=im.shape) * .2 # Moravec - results = peak_local_max(corner_moravec(im)) + results = peak_local_max(corner_moravec(im), + min_distance=10, threshold_rel=0) # undefined number of interest points assert results.any() # Harris - results = peak_local_max(corner_harris(im, sigma=1.5, method='k')) + results = peak_local_max(corner_harris(im, method='k'), + min_distance=10, threshold_rel=0) assert len(results) == 1 - results = peak_local_max(corner_harris(im, sigma=1.5, method='eps')) + results = peak_local_max(corner_harris(im, method='eps'), + min_distance=10, threshold_rel=0) assert len(results) == 1 # Shi-Tomasi - results = peak_local_max(corner_shi_tomasi(im, sigma=1.5)) + results = peak_local_max(corner_shi_tomasi(im, sigma=1.5), + min_distance=10, threshold_rel=0) assert len(results) == 1 @@ -156,11 +164,13 @@ def test_squared_dot(): # Moravec fails # Harris - results = peak_local_max(corner_harris(im)) + results = peak_local_max(corner_harris(im), + min_distance=10, threshold_rel=0) assert (results == np.array([[6, 6]])).all() # Shi-Tomasi - results = peak_local_max(corner_shi_tomasi(im)) + results = peak_local_max(corner_shi_tomasi(im), + min_distance=10, threshold_rel=0) assert (results == np.array([[6, 6]])).all() @@ -173,20 +183,26 @@ def test_rotated_img(): im_rotated = im.T # Moravec - results = peak_local_max(corner_moravec(im)) - results_rotated = peak_local_max(corner_moravec(im_rotated)) + results = peak_local_max(corner_moravec(im), + min_distance=10, threshold_rel=0) + results_rotated = peak_local_max(corner_moravec(im_rotated), + min_distance=10, threshold_rel=0) assert (np.sort(results[:, 0]) == np.sort(results_rotated[:, 1])).all() assert (np.sort(results[:, 1]) == np.sort(results_rotated[:, 0])).all() # Harris - results = peak_local_max(corner_harris(im)) - results_rotated = peak_local_max(corner_harris(im_rotated)) + results = peak_local_max(corner_harris(im), + min_distance=10, threshold_rel=0) + results_rotated = peak_local_max(corner_harris(im_rotated), + min_distance=10, threshold_rel=0) assert (np.sort(results[:, 0]) == np.sort(results_rotated[:, 1])).all() assert (np.sort(results[:, 1]) == np.sort(results_rotated[:, 0])).all() # Shi-Tomasi - results = peak_local_max(corner_shi_tomasi(im)) - results_rotated = peak_local_max(corner_shi_tomasi(im_rotated)) + results = peak_local_max(corner_shi_tomasi(im), + min_distance=10, threshold_rel=0) + results_rotated = peak_local_max(corner_shi_tomasi(im_rotated), + min_distance=10, threshold_rel=0) assert (np.sort(results[:, 0]) == np.sort(results_rotated[:, 1])).all() assert (np.sort(results[:, 1]) == np.sort(results_rotated[:, 0])).all() @@ -195,7 +211,8 @@ def test_subpix_edge(): img = np.zeros((50, 50)) img[:25, :25] = 255 img[25:, 25:] = 255 - corner = peak_local_max(corner_harris(img), num_peaks=1) + corner = peak_local_max(corner_harris(img), + min_distance=10, threshold_rel=0, num_peaks=1) subpix = corner_subpix(img, corner) assert_array_equal(subpix[0], (24.5, 24.5)) @@ -203,7 +220,8 @@ def test_subpix_edge(): def test_subpix_dot(): img = np.zeros((50, 50)) img[25, 25] = 255 - corner = peak_local_max(corner_harris(img), num_peaks=1) + corner = peak_local_max(corner_harris(img), + min_distance=10, threshold_rel=0, num_peaks=1) subpix = corner_subpix(img, corner) assert_array_equal(subpix[0], (25, 25)) @@ -214,7 +232,8 @@ def test_subpix_no_class(): assert_array_equal(subpix[0], (np.nan, np.nan)) img[25, 25] = 1e-10 - corner = peak_local_max(corner_harris(img), num_peaks=1) + corner = peak_local_max(corner_harris(img), + min_distance=10, threshold_rel=0, num_peaks=1) subpix = corner_subpix(img, np.array([[25, 25]])) assert_array_equal(subpix[0], (np.nan, np.nan)) @@ -223,7 +242,7 @@ def test_subpix_border(): img = np.zeros((50, 50)) img[1:25,1:25] = 255 img[25:-1,25:-1] = 255 - corner = corner_peaks(corner_harris(img), min_distance=1) + corner = corner_peaks(corner_harris(img), threshold_rel=0) subpix = corner_subpix(img, corner, window_size=11) ref = np.array([[ 0.52040816, 0.52040816], [ 0.52040816, 24.47959184], @@ -244,7 +263,8 @@ def test_num_peaks(): for i in range(20): n = np.random.random_integers(20) - results = peak_local_max(img_corners, num_peaks=n) + results = peak_local_max(img_corners, + min_distance=10, threshold_rel=0, num_peaks=n) assert (results.shape[0] == n) @@ -252,14 +272,16 @@ def test_corner_peaks(): response = np.zeros((5, 5)) response[2:4, 2:4] = 1 - corners = corner_peaks(response, exclude_border=False) + corners = corner_peaks(response, exclude_border=False, min_distance=10, + threshold_rel=0) assert len(corners) == 1 - corners = corner_peaks(response, exclude_border=False, min_distance=0) + corners = corner_peaks(response, exclude_border=False, min_distance=0, + threshold_rel=0) assert len(corners) == 4 corners = corner_peaks(response, exclude_border=False, min_distance=0, - indices=False) + threshold_rel=0, indices=False) assert np.sum(corners) == 4 @@ -323,7 +345,8 @@ def test_corner_fast_lena(): [492, 139], [494, 169], [496, 266]]) - actual = corner_peaks(corner_fast(img, 12, 0.3)) + actual = corner_peaks(corner_fast(img, 12, 0.3), + min_distance=10, threshold_rel=0) assert_array_equal(actual, expected) @@ -355,7 +378,6 @@ def test_corner_orientations_astronaut(): -4.40598471e-01, 3.14918803e-01, -1.76069982e+00, 3.05330950e+00, 2.39291733e+00, -1.22091334e-01, -3.09279990e-01, 1.45931342e+00]) - actual = corner_orientations(img, corners, octagon(3, 2)) assert_almost_equal(actual, expected) @@ -363,7 +385,8 @@ def test_corner_orientations_astronaut(): def test_corner_orientations_square(): square = np.zeros((12, 12)) square[3:9, 3:9] = 1 - corners = corner_peaks(corner_fast(square, 9), min_distance=1) + corners = corner_peaks(corner_fast(square, 9), + min_distance=1, threshold_rel=0) actual_orientations = corner_orientations(square, corners, octagon(3, 2)) actual_orientations_degrees = np.rad2deg(actual_orientations) expected_orientations_degree = np.array([ 45., 135., -45., -135.]) diff --git a/skimage/feature/tests/test_peak.py b/skimage/feature/tests/test_peak.py index e6256208..43a87369 100644 --- a/skimage/feature/tests/test_peak.py +++ b/skimage/feature/tests/test_peak.py @@ -70,12 +70,14 @@ def test_num_peaks(): image[1, 5] = 12 image[3, 5] = 8 image[5, 3] = 7 - assert len(peak.peak_local_max(image, min_distance=1)) == 5 - peaks_limited = peak.peak_local_max(image, min_distance=1, num_peaks=2) + assert len(peak.peak_local_max(image, min_distance=1, threshold_abs=0)) == 5 + peaks_limited = peak.peak_local_max( + image, min_distance=1, threshold_abs=0, num_peaks=2) assert len(peaks_limited) == 2 assert (1, 3) in peaks_limited assert (1, 5) in peaks_limited - peaks_limited = peak.peak_local_max(image, min_distance=1, num_peaks=4) + peaks_limited = peak.peak_local_max( + image, min_distance=1, threshold_abs=0, num_peaks=4) assert len(peaks_limited) == 4 assert (1, 3) in peaks_limited assert (1, 5) in peaks_limited @@ -272,7 +274,8 @@ def test_disk(): min_distance=1, threshold_rel=0, indices=False, exclude_border=False) assert np.all(result) - result = peak.peak_local_max(image, footprint=footprint) + result = peak.peak_local_max(image, footprint=footprint, indices=False, + exclude_border=False) assert np.all(result) @@ -280,11 +283,14 @@ def test_3D(): image = np.zeros((30, 30, 30)) image[15, 15, 15] = 1 image[5, 5, 5] = 1 - assert_equal(peak.peak_local_max(image), [[15, 15, 15]]) - assert_equal(peak.peak_local_max(image, min_distance=6), [[15, 15, 15]]) - assert_equal(peak.peak_local_max(image, exclude_border=False), + assert_equal(peak.peak_local_max(image, min_distance=10, threshold_rel=0), + [[15, 15, 15]]) + assert_equal(peak.peak_local_max(image, min_distance=6, threshold_rel=0), + [[15, 15, 15]]) + assert_equal(peak.peak_local_max(image, min_distance=10, threshold_rel=0, + exclude_border=False), [[5, 5, 5], [15, 15, 15]]) - assert_equal(peak.peak_local_max(image, min_distance=5), + assert_equal(peak.peak_local_max(image, min_distance=5, threshold_rel=0), [[5, 5, 5], [15, 15, 15]]) @@ -292,11 +298,14 @@ def test_4D(): image = np.zeros((30, 30, 30, 30)) image[15, 15, 15, 15] = 1 image[5, 5, 5, 5] = 1 - assert_equal(peak.peak_local_max(image), [[15, 15, 15, 15]]) - assert_equal(peak.peak_local_max(image, min_distance=6), [[15, 15, 15, 15]]) - assert_equal(peak.peak_local_max(image, exclude_border=False), + assert_equal(peak.peak_local_max(image, min_distance=10, threshold_rel=0), + [[15, 15, 15, 15]]) + assert_equal(peak.peak_local_max(image, min_distance=6, threshold_rel=0), + [[15, 15, 15, 15]]) + assert_equal(peak.peak_local_max(image, min_distance=10, threshold_rel=0, + exclude_border=False), [[5, 5, 5, 5], [15, 15, 15, 15]]) - assert_equal(peak.peak_local_max(image, min_distance=5), + assert_equal(peak.peak_local_max(image, min_distance=5, threshold_rel=0), [[5, 5, 5, 5], [15, 15, 15, 15]])