def test_trivial_case(self): trivial = np.zeros((25, 25)) peak_indices = peak.peak_local_max(trivial, min_distance=1, indices=True) assert type(peak_indices) is np.ndarray assert not peak_indices # inherent boolean-ness of empty list peaks = peak.peak_local_max(trivial, min_distance=1, indices=False) assert (peaks.astype(np.bool) == trivial).all()
def test_trivial_case(self): trivial = np.zeros((25, 25)) peak_indices = peak.peak_local_max(trivial, min_distance=1, indices=True) assert type(peak_indices) is np.ndarray assert peak_indices.size == 0 peaks = peak.peak_local_max(trivial, min_distance=1, indices=False) assert (peaks.astype(np.bool) == trivial).all()
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), [[5, 5, 5, 5], [15, 15, 15, 15]]) assert_equal(peak.peak_local_max(image, min_distance=5), [[5, 5, 5, 5], [15, 15, 15, 15]])
def test_num_peaks(): image = np.zeros((3, 7), dtype=np.uint8) image[1, 1] = 10 image[1, 3] = 11 image[1, 5] = 12 assert len(peak.peak_local_max(image, min_distance=1)) == 3 peaks_limited = peak.peak_local_max(image, min_distance=1, num_peaks=2) assert len(peaks_limited) == 2 assert (1, 3) in peaks_limited assert (1, 5) in peaks_limited
def test_threshold_rel_default(self): image = np.ones((5, 5)) image[2, 2] = 1 assert len(peak.peak_local_max(image)) == 0 image[2, 2] = 2 assert_equal(peak.peak_local_max(image), [[2, 2]]) image[2, 2] = 0 assert len(peak.peak_local_max(image, min_distance=0)) == image.size - 1
def test_sorted_peaks(self): image = np.zeros((5, 5), dtype=np.uint8) image[1, 1] = 20 image[3, 3] = 10 peaks = peak.peak_local_max(image, min_distance=1) assert peaks.tolist() == [[3, 3], [1, 1]] image = np.zeros((3, 10)) image[1, (1, 3, 5, 7)] = (1, 3, 2, 4) peaks = peak.peak_local_max(image, min_distance=1) assert peaks.tolist() == [[1, 7], [1, 5], [1, 3], [1, 1]]
def test_disk(): '''regression test of img-1194, footprint = [1] Test peak.peak_local_max when every point is a local maximum ''' image = np.random.uniform(size=(10, 20)) footprint = np.array([[1]]) result = peak.peak_local_max(image, labels=np.ones((10, 20)), footprint=footprint, min_distance=1, threshold_rel=0, indices=False, exclude_border=False) assert np.all(result) result = peak.peak_local_max(image, footprint=footprint) assert np.all(result)
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, 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, threshold_rel=0), [[5, 5, 5], [15, 15, 15]])
def test_num_peaks_and_labels(self): image = np.zeros((7, 7), dtype=np.uint8) labels = np.zeros((7, 7), dtype=np.uint8) + 20 image[1, 1] = 10 image[1, 3] = 11 image[1, 5] = 12 image[3, 5] = 8 image[5, 3] = 7 peaks_limited = peak.peak_local_max( image, min_distance=1, threshold_abs=0, labels=labels) assert len(peaks_limited) == 5 peaks_limited = peak.peak_local_max( image, min_distance=1, threshold_abs=0, labels=labels, num_peaks=2) assert len(peaks_limited) == 2
def test_4D(self): 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, 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 sorted(peak.peak_local_max(image, min_distance=10, threshold_rel=0, exclude_border=False).tolist()) == \ [[5, 5, 5, 5], [15, 15, 15, 15]] assert sorted(peak.peak_local_max(image, min_distance=5, threshold_rel=0).tolist()) == \ [[5, 5, 5, 5], [15, 15, 15, 15]]
def find_peaks(self, min_distance_mm=5): """ Find peaks in the image data. Arguments: ---------- min_distance_mm : float Minimum distance between peaks in mm Returns: -------- peaks: PointSet """ from skimage.feature.peak import peak_local_max from ..commons import affine_scaling img = self.fetch() dist = int(min_distance_mm / affine_scaling(img.affine) + 0.5) voxels = peak_local_max( img.get_fdata(), exclude_border=False, min_distance=dist, ) return ( PointSet( [np.dot(img.affine, [x, y, z, 1])[:3] for x, y, z in voxels], space=self.space, ), img, )
def test_num_peaks3D(self): # Issue 1354: the old code only hold for 2D arrays # and this code would die with IndexError image = np.zeros((10, 10, 100)) image[5,5,::5] = np.arange(20) peaks_limited = peak.peak_local_max(image, min_distance=1, num_peaks=2) assert len(peaks_limited) == 2
def test_absolute_threshold(self): image = np.zeros((5, 5), dtype=np.uint8) image[1, 1] = 10 image[3, 3] = 20 peaks = peak.peak_local_max(image, min_distance=1, threshold_abs=10) assert len(peaks) == 1 assert_close(peaks, [(3, 3)])
def test_adjacent_and_different(self): image = np.zeros((10, 20)) labels = np.zeros((10, 20), int) image[5, 5] = 1 image[5, 6] = .5 labels[5, 5:6] = 1 expected = (image == 1) result = peak.peak_local_max(image, labels=labels, footprint=np.ones((3, 3), bool), min_distance=1, threshold_rel=0, indices=False, exclude_border=False) assert np.all(result == expected) result = peak.peak_local_max(image, labels=labels, min_distance=1, threshold_rel=0, indices=False, exclude_border=False) assert np.all(result == expected)
def test_relative_threshold(self): image = np.zeros((5, 5), dtype=np.uint8) image[1, 1] = 10 image[3, 3] = 20 peaks = peak.peak_local_max(image, min_distance=1, threshold_rel=0.5) assert len(peaks) == 1 assert_array_almost_equal(peaks, [(3, 3)])
def test_empty(self): image = np.zeros((10, 20)) labels = np.zeros((10, 20), int) result = peak.peak_local_max(image, labels=labels, footprint=np.ones((3, 3), bool), min_distance=1, threshold_rel=0, indices=False, exclude_border=False) assert np.all(~ result)
def test_ndarray_exclude_border(self): nd_image = np.zeros((5, 5, 5)) nd_image[[1, 0, 0], [0, 1, 0], [0, 0, 1]] = 1 nd_image[3, 0, 0] = 1 nd_image[2, 2, 2] = 1 expected = np.zeros_like(nd_image, dtype=np.bool) expected[2, 2, 2] = True expectedNoBorder = nd_image > 0 result = peak.peak_local_max(nd_image, min_distance=2, exclude_border=2, indices=False) assert_equal(result, expected) # Check that bools work as expected assert_equal( peak.peak_local_max(nd_image, min_distance=2, exclude_border=2, indices=False), peak.peak_local_max(nd_image, min_distance=2, exclude_border=True, indices=False) ) assert_equal( peak.peak_local_max(nd_image, min_distance=2, exclude_border=0, indices=False), peak.peak_local_max(nd_image, min_distance=2, exclude_border=False, indices=False) ) # Check both versions with no border assert_equal( peak.peak_local_max(nd_image, min_distance=2, exclude_border=0, indices=False), expectedNoBorder, ) assert_equal( peak.peak_local_max(nd_image, exclude_border=False, indices=False), expectedNoBorder, )
def test_ndarray_exclude_border(): nd_image = np.zeros((5,5,5)) nd_image[[1,0,0],[0,1,0],[0,0,1]] = 1 nd_image[3,0,0] = 1 nd_image[2,2,2] = 1 expected = np.zeros_like(nd_image, dtype=np.bool) expected[2,2,2] = True result = peak.peak_local_max(nd_image, min_distance=2, indices=False) assert (result == expected).all()
def test_adjacent_and_same(self): image = np.zeros((10, 20)) labels = np.zeros((10, 20), int) image[5, 5:6] = 1 labels[5, 5:6] = 1 result = peak.peak_local_max(image, labels=labels, footprint=np.ones((3, 3), bool), min_distance=1, threshold_rel=0, indices=False, exclude_border=False) assert np.all(result == (labels == 1))
def test_input_labels_unmodified(self): image = np.zeros((10, 20)) labels = np.zeros((10, 20), int) image[5, 5] = 1 labels[5, 5] = 1 labelsin = labels.copy() result = peak.peak_local_max(image, labels=labels, footprint=np.ones((3, 3), bool), min_distance=1, threshold_rel=0, indices=False, exclude_border=False) assert np.all(labels == labelsin)
def test_num_peaks(self): image = np.zeros((7, 7), dtype=np.uint8) image[1, 1] = 10 image[1, 3] = 11 image[1, 5] = 12 image[3, 5] = 8 image[5, 3] = 7 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, threshold_abs=0, num_peaks=4) assert len(peaks_limited) == 4 assert (1, 3) in peaks_limited assert (1, 5) in peaks_limited assert (1, 1) in peaks_limited assert (3, 5) in peaks_limited
def test_two_objects(self): image = np.zeros((10, 20)) labels = np.zeros((10, 20), int) image[5, 5] = 1 image[5, 15] = .5 labels[5, 5] = 1 labels[5, 15] = 2 expected = (labels > 0) result = peak.peak_local_max(image, labels=labels, footprint=np.ones((3, 3), bool), min_distance=1, threshold_rel=0, indices=False, exclude_border=False) assert np.all(result == expected)
def test_noisy_peaks(self): peak_locations = [(7, 7), (7, 13), (13, 7), (13, 13)] # image with noise of amplitude 0.8 and peaks of amplitude 1 image = 0.8 * np.random.rand(20, 20) for r, c in peak_locations: image[r, c] = 1 peaks_detected = peak.peak_local_max(image, min_distance=5) assert len(peaks_detected) == len(peak_locations) for loc in peaks_detected: assert tuple(loc) in peak_locations
def test_num_peaks_tot_vs_labels_4quadrants(self): np.random.seed(21) image = np.random.uniform(size=(20, 30)) i, j = np.mgrid[0:20, 0:30] labels = 1 + (i >= 10) + (j >= 15) * 2 result = peak.peak_local_max(image, labels=labels, min_distance=1, threshold_rel=0, indices=True, num_peaks=np.inf, num_peaks_per_label=2) assert len(result) == 8 result = peak.peak_local_max(image, labels=labels, min_distance=1, threshold_rel=0, indices=True, num_peaks=np.inf, num_peaks_per_label=1) assert len(result) == 4 result = peak.peak_local_max(image, labels=labels, min_distance=1, threshold_rel=0, indices=True, num_peaks=2, num_peaks_per_label=2) assert len(result) == 2
def test_indices_with_labels(): image = np.random.uniform(size=(40, 60)) i, j = np.mgrid[0:40, 0:60] labels = 1 + (i >= 20) + (j >= 30) * 2 i, j = np.mgrid[-3:4, -3:4] footprint = (i * i + j * j <= 9) expected = np.zeros(image.shape, float) for imin, imax in ((0, 20), (20, 40)): for jmin, jmax in ((0, 30), (30, 60)): expected[imin:imax, jmin:jmax] = scipy.ndimage.maximum_filter( image[imin:imax, jmin:jmax], footprint=footprint) expected = (expected == image) result = peak.peak_local_max(image, labels=labels, min_distance=1, threshold_rel=0, footprint=footprint, indices=True, exclude_border=False) assert (result == np.transpose(expected.nonzero())).all()
def test_four_quadrants(self): image = np.random.uniform(size=(20, 30)) i, j = np.mgrid[0:20, 0:30] labels = 1 + (i >= 10) + (j >= 15) * 2 i, j = np.mgrid[-3:4, -3:4] footprint = (i * i + j * j <= 9) expected = np.zeros(image.shape, float) for imin, imax in ((0, 10), (10, 20)): for jmin, jmax in ((0, 15), (15, 30)): expected[imin:imax, jmin:jmax] = ndi.maximum_filter( image[imin:imax, jmin:jmax], footprint=footprint) expected = (expected == image) result = peak.peak_local_max(image, labels=labels, footprint=footprint, min_distance=1, threshold_rel=0, indices=False, exclude_border=False) assert np.all(result == expected)
def test_reorder_labels(): np.random.seed(21) image = np.random.uniform(size=(40, 60)) i, j = np.mgrid[0:40, 0:60] labels = 1 + (i >= 20) + (j >= 30) * 2 labels[labels == 4] = 5 i, j = np.mgrid[-3:4, -3:4] footprint = (i * i + j * j <= 9) expected = np.zeros(image.shape, float) for imin, imax in ((0, 20), (20, 40)): for jmin, jmax in ((0, 30), (30, 60)): expected[imin:imax, jmin:jmax] = ndi.maximum_filter( image[imin:imax, jmin:jmax], footprint=footprint) expected = (expected == image) result = peak.peak_local_max(image, labels=labels, min_distance=1, threshold_rel=0, footprint=footprint, indices=False, exclude_border=False) assert (result == expected).all()
def test_adjacent_different_objects(): image = np.zeros((10, 20)) labels = np.zeros((10, 20), int) image[5, 5] = 1 image[5, 6] = 0.5 labels[5, 5] = 1 labels[5, 6] = 2 expected = labels > 0 result = peak.peak_local_max( image, labels=labels, footprint=np.ones((3, 3), bool), min_distance=1, threshold_rel=0, indices=False, exclude_border=False, ) assert np.all(result == expected)
def blob_log(image, min_sigma=1, max_sigma=50, num_sigma=10, threshold=.2, overlap=.5, log_scale=False): """Finds blobs in the given grayscale image. Blobs are found using the Laplacian of Gaussian (LoG) method [1]_. For each blob found, the method returns its coordinates and the standard deviation of the Gaussian kernel that detected the blob. Parameters ---------- image : 2D or 3D ndarray Input grayscale image, blobs are assumed to be light on dark background (white on black). min_sigma : float, optional The minimum standard deviation for Gaussian Kernel. Keep this low to detect smaller blobs. max_sigma : float, optional The maximum standard deviation for Gaussian Kernel. Keep this high to detect larger blobs. num_sigma : int, optional The number of intermediate values of standard deviations to consider between `min_sigma` and `max_sigma`. threshold : float, optional. The absolute lower bound for scale space maxima. Local maxima smaller than thresh are ignored. Reduce this to detect blobs with less intensities. overlap : float, optional A value between 0 and 1. If the area of two blobs overlaps by a fraction greater than `threshold`, the smaller blob is eliminated. log_scale : bool, optional If set intermediate values of standard deviations are interpolated using a logarithmic scale to the base `10`. If not, linear interpolation is used. Returns ------- A : (n, image.ndim + 1) ndarray A 2d array with each row representing 3 values for a 2D image, and 4 values for a 3D image: ``(r, c, sigma)`` or ``(f, r, c, sigma)`` where ``(r, c)`` or ``(f, r, c)`` are coordinates of the blob and ``sigma`` is the standard deviation of the Gaussian kernel which detected the blob. References ---------- .. [1] http://en.wikipedia.org/wiki/Blob_detection#The_Laplacian_of_Gaussian Examples -------- >>> from skimage import data, feature, exposure >>> img = data.coins() >>> img = exposure.equalize_hist(img) # improves detection >>> feature.blob_log(img, threshold = .3) array([[ 113. , 323. , 1. ], [ 121. , 272. , 17.33333333], [ 124. , 336. , 11.88888889], [ 126. , 46. , 11.88888889], [ 126. , 208. , 11.88888889], [ 127. , 102. , 11.88888889], [ 128. , 154. , 11.88888889], [ 185. , 344. , 17.33333333], [ 194. , 213. , 17.33333333], [ 194. , 276. , 17.33333333], [ 197. , 44. , 11.88888889], [ 198. , 103. , 11.88888889], [ 198. , 155. , 11.88888889], [ 260. , 174. , 17.33333333], [ 263. , 244. , 17.33333333], [ 263. , 302. , 17.33333333], [ 266. , 115. , 11.88888889]]) Notes ----- The radius of each blob is approximately :math:`\sqrt{2}sigma` for a 2-D image and :math:`\sqrt{3}sigma` for a 3-D image. """ image = img_as_float(image) if log_scale: start, stop = log(min_sigma, 10), log(max_sigma, 10) sigma_list = np.logspace(start, stop, num_sigma) else: sigma_list = np.linspace(min_sigma, max_sigma, num_sigma) # computing gaussian laplace # s**2 provides scale invariance gl_images = [-gaussian_laplace(image, s) * s ** 2 for s in sigma_list] # Replace by image_cube = np.stack(hessian_images, axis=-1) # When we upgrade minimal requirements to NumPy 1.10 sl = (slice(None),) * image.ndim + (np.newaxis,) arrays = [np.asanyarray(arr) for arr in gl_images] extended_arrays = [arr[sl] for arr in arrays] image_cube = np.concatenate(extended_arrays, axis=-1) local_maxima = peak_local_max(image_cube, threshold_abs=threshold, footprint=np.ones((3,) * (image.ndim + 1)), threshold_rel=0.0, exclude_border=False) # Convert local_maxima to float64 lm = local_maxima.astype(np.float64) # Convert the last index to its corresponding scale value lm[:, -1] = sigma_list[local_maxima[:, -1]] return _prune_blobs(lm, overlap)
def blob_dog(image, min_sigma=1, max_sigma=50, sigma_ratio=1.6, threshold=2.0, overlap=.5, ): """Finds blobs in the given grayscale image. Blobs are found using the Difference of Gaussian (DoG) method [1]_. For each blob found, the method returns its coordinates and the standard deviation of the Gaussian kernel that detected the blob. Parameters ---------- image : 2D or 3D ndarray Input grayscale image, blobs are assumed to be light on dark background (white on black). min_sigma : float, optional The minimum standard deviation for Gaussian Kernel. Keep this low to detect smaller blobs. max_sigma : float, optional The maximum standard deviation for Gaussian Kernel. Keep this high to detect larger blobs. sigma_ratio : float, optional The ratio between the standard deviation of Gaussian Kernels used for computing the Difference of Gaussians threshold : float, optional. The absolute lower bound for scale space maxima. Local maxima smaller than thresh are ignored. Reduce this to detect blobs with less intensities. overlap : float, optional A value between 0 and 1. If the area of two blobs overlaps by a fraction greater than `threshold`, the smaller blob is eliminated. Returns ------- A : (n, image.ndim + 1) ndarray A 2d array with each row representing 3 values for a 2D image, and 4 values for a 3D image: ``(r, c, sigma)`` or ``(p, r, c, sigma)`` where ``(r, c)`` or ``(p, r, c)`` are coordinates of the blob and ``sigma`` is the standard deviation of the Gaussian kernel which detected the blob. References ---------- .. [1] http://en.wikipedia.org/wiki/Blob_detection#The_difference_of_Gaussians_approach Examples -------- >>> from skimage import data, feature >>> feature.blob_dog(data.coins(), threshold=.5, max_sigma=40) array([[ 45. , 336. , 16.777216], [ 52. , 155. , 16.777216], [ 52. , 216. , 16.777216], [ 54. , 42. , 16.777216], [ 54. , 276. , 10.48576 ], [ 58. , 100. , 10.48576 ], [ 120. , 272. , 16.777216], [ 124. , 337. , 10.48576 ], [ 125. , 45. , 16.777216], [ 125. , 208. , 10.48576 ], [ 127. , 102. , 10.48576 ], [ 128. , 154. , 10.48576 ], [ 185. , 347. , 16.777216], [ 193. , 213. , 16.777216], [ 194. , 277. , 16.777216], [ 195. , 102. , 16.777216], [ 196. , 43. , 10.48576 ], [ 198. , 155. , 10.48576 ], [ 260. , 46. , 16.777216], [ 261. , 173. , 16.777216], [ 263. , 245. , 16.777216], [ 263. , 302. , 16.777216], [ 267. , 115. , 10.48576 ], [ 267. , 359. , 16.777216]]) Notes ----- The radius of each blob is approximately :math:`\sqrt{2}sigma` for a 2-D image and :math:`\sqrt{3}sigma` for a 3-D image. """ image = img_as_float(image) # k such that min_sigma*(sigma_ratio**k) > max_sigma k = int(log(float(max_sigma) / min_sigma, sigma_ratio)) + 1 # a geometric progression of standard deviations for gaussian kernels sigma_list = np.array([min_sigma * (sigma_ratio ** i) for i in range(k + 1)]) gaussian_images = [gaussian_filter(image, s) for s in sigma_list] # computing difference between two successive Gaussian blurred images # multiplying with standard deviation provides scale invariance dog_images = [(gaussian_images[i] - gaussian_images[i + 1]) * sigma_list[i] for i in range(k)] # Replace by image_cube = np.stack(hessian_images, axis=-1) # When we upgrade minimal requirements to NumPy 1.10 sl = (slice(None),) * image.ndim + (np.newaxis,) arrays = [np.asanyarray(arr) for arr in dog_images] extended_arrays = [arr[sl] for arr in arrays] image_cube = np.concatenate(extended_arrays, axis=-1) # local_maxima = get_local_maxima(image_cube, threshold) local_maxima = peak_local_max(image_cube, threshold_abs=threshold, footprint=np.ones((3,) * (image.ndim + 1)), threshold_rel=0.0, exclude_border=False) # Convert local_maxima to float64 lm = local_maxima.astype(np.float64) # Convert the last index to its corresponding scale value lm[:, -1] = sigma_list[local_maxima[:, -1]] return _prune_blobs(lm, overlap)
def test_flat_peak(self): image = np.zeros((5, 5), dtype=np.uint8) image[1:3, 1:3] = 10 peaks = peak.peak_local_max(image, min_distance=1) assert len(peaks) == 4