From cbb84d5588d78c3338e521128f3b28b53188b6b1 Mon Sep 17 00:00:00 2001 From: Stefan van der Walt Date: Tue, 19 Apr 2011 14:57:11 +0200 Subject: [PATCH] ENH: Minor clean-ups to edge-detection patch. --- scikits/image/filter/edges.py | 120 ++++++++++++----------- scikits/image/filter/tests/test_edges.py | 68 ++++++------- 2 files changed, 98 insertions(+), 90 deletions(-) diff --git a/scikits/image/filter/edges.py b/scikits/image/filter/edges.py index d4fbc5ef..8ffeee8e 100644 --- a/scikits/image/filter/edges.py +++ b/scikits/image/filter/edges.py @@ -12,15 +12,15 @@ import numpy as np from scipy.ndimage import convolve, binary_erosion, generate_binary_structure def sobel(image, mask=None): - """Calculate the absolute magnitude Sobel to find the edges. + """Calculate the absolute magnitude Sobel to find edges. Parameters ---------- image : array_like, dtype=float - Image to process + Image to process. mask : array_like, dtype=bool, optional - An optional mask to limit the application to a certain area - + An optional mask to limit the application to a certain area. + Returns ------- output : ndarray @@ -31,34 +31,36 @@ def sobel(image, mask=None): Take the square root of the sum of the squares of the horizontal and vertical Sobels to get a magnitude that's somewhat insensitive to direction. - - Note that scipy's Sobel returns a directional Sobel which isn't - useful for edge detection in its raw form. + + Note that ``scipy.ndimage.sobel`` returns a directional Sobel which + has to be further processed to perform edge detection. """ - return np.sqrt(hsobel(image,mask)**2 + vsobel(image,mask)**2) + return np.sqrt(hsobel(image, mask)**2 + vsobel(image, mask)**2) def hsobel(image, mask=None): - """Find the horizontal edges of an image using the Sobel transform - + """Find the horizontal edges of an image using the Sobel transform. + Parameters ---------- image : array_like, dtype=float - Image to process + Image to process. mask : array_like, dtype=bool, optional An optional mask to limit the application to a certain area. - + Returns ------- output : ndarray The Sobel edge map. - + Notes ----- We use the following kernel and return the absolute value of the - result at each point: - 1 2 1 - 0 0 0 - -1 -2 -1 + result at each point:: + + 1 2 1 + 0 0 0 + -1 -2 -1 + """ if mask is None: mask = np.ones(image.shape, bool) @@ -73,88 +75,92 @@ def hsobel(image, mask=None): def vsobel(image, mask=None): """Find the vertical edges of an image using the Sobel transform. - + Parameters ---------- image : array_like, dtype=float Image to process mask : array_like, dtype=bool, optional An optional mask to limit the application to a certain area - + Returns ------- output : ndarray The Sobel edge map. - + Notes ----- We use the following kernel and return the absolute value of the - result at each point: - 1 0 -1 - 2 0 -2 - 1 0 -1 + result at each point:: + + 1 0 -1 + 2 0 -2 + 1 0 -1 + """ if mask is None: mask = np.ones(image.shape, bool) big_mask = binary_erosion(mask, generate_binary_structure(2, 2), - border_value = 0) - result = np.abs(convolve(image, np.array([[ 1, 0,-1], - [ 2, 0,-2], - [ 1, 0,-1]]).astype(float) / 4.0)) + border_value=0) + result = np.abs(convolve(image, np.array([[1, 0, -1], + [2, 0, -2], + [1, 0, -1]]).astype(float) / 4.0)) result[big_mask == False] = 0 return result def prewitt(image, mask=None): """Find the edge magnitude using the Prewitt transform. - + Parameters ---------- image : array_like, dtype=float - Image to process + Image to process. mask : array_like, dtype=bool, optional - An optional mask to limit the application to a certain area - + An optional mask to limit the application to a certain area. + Returns ------- output : ndarray The Prewitt edge map. - + Notes ----- Return the square root of the sum of squares of the horizontal and vertical Prewitt transforms. """ return np.sqrt(hprewitt(image, mask) ** 2 + vprewitt(image, mask) ** 2) - + def hprewitt(image, mask=None): """Find the horizontal edges of an image using the Prewitt transform. - + Parameters ---------- image : array_like, dtype=float - Image to process + Image to process. mask : array_like, dtype=bool, optional - An optional mask to limit the application to a certain area - + An optional mask to limit the application to a certain area. + Returns ------- output : ndarray The Prewitt edge map. - + Notes ----- We use the following kernel and return the absolute value of the - result at each point: - 1 1 1 - 0 0 0 - -1 -1 -1 + result at each point:: + + 1 1 1 + 0 0 0 + -1 -1 -1 + """ if mask is None: mask = np.ones(image.shape, bool) big_mask = binary_erosion(mask, generate_binary_structure(2, 2), - border_value = 0) + border_value=0) result = np.abs(convolve(image, np.array([[ 1, 1, 1], [ 0, 0, 0], [-1,-1,-1]]).astype(float) / 3.0)) @@ -163,34 +169,36 @@ def hprewitt(image, mask=None): def vprewitt(image, mask=None): """Find the vertical edges of an image using the Prewitt transform. - + Parameters ---------- image : array_like, dtype=float - Image to process + Image to process. mask : array_like, dtype=bool, optional - An optional mask to limit the application to a certain area - + An optional mask to limit the application to a certain area. + Returns ------- output : ndarray The Prewitt edge map. - + Notes ----- We use the following kernel and return the absolute value of the - result at each point: - 1 0 -1 - 1 0 -1 - 1 0 -1 + result at each point:: + + 1 0 -1 + 1 0 -1 + 1 0 -1 + """ if mask is None: mask = np.ones(image.shape, bool) big_mask = binary_erosion(mask, generate_binary_structure(2, 2), border_value=0) - result = np.abs(convolve(image, np.array([[ 1, 0,-1], - [ 1, 0,-1], - [ 1, 0,-1]]).astype(float) / 3.0)) + result = np.abs(convolve(image, np.array([[1, 0, -1], + [1, 0, -1], + [1, 0, -1]]).astype(float) / 3.0)) result[big_mask == False] = 0 return result diff --git a/scikits/image/filter/tests/test_edges.py b/scikits/image/filter/tests/test_edges.py index 1ce479f0..7f296b7f 100644 --- a/scikits/image/filter/tests/test_edges.py +++ b/scikits/image/filter/tests/test_edges.py @@ -8,11 +8,11 @@ class TestSobel(): """Sobel on an array of all zeros""" result = F.sobel(np.zeros((10, 10)), np.ones((10, 10), bool)) assert (np.all(result == 0)) - + def test_00_01_mask(self): """Sobel on a masked array should be zero""" np.random.seed(0) - result = F.sobel(np.random.uniform(size=(10, 10)), + result = F.sobel(np.random.uniform(size=(10, 10)), np.zeros((10, 10), bool)) assert (np.all(result == 0)) @@ -25,10 +25,10 @@ class TestSobel(): i[np.abs(j) == 5] = 10000 assert (np.all(result[i == 0] == 1)) assert (np.all(result[np.abs(i) > 1] == 0)) - + def test_01_02_vertical(self): """Sobel on a vertical edge should be a vertical line""" - i,j = np.mgrid[-5:6, -5:6] + i, j = np.mgrid[-5:6, -5:6] image = (j >= 0).astype(float) result = F.sobel(image) j[np.abs(i) == 5] = 10000 @@ -40,27 +40,27 @@ class TestHSobel(): """Horizontal sobel on an array of all zeros""" result = F.hsobel(np.zeros((10, 10)), np.ones((10, 10), bool)) assert (np.all(result == 0)) - + def test_00_01_mask(self): """Horizontal Sobel on a masked array should be zero""" np.random.seed(0) - result = F.hsobel(np.random.uniform(size=(10, 10)), + result = F.hsobel(np.random.uniform(size=(10, 10)), np.zeros((10, 10), bool)) assert (np.all(result == 0)) def test_01_01_horizontal(self): """Horizontal Sobel on an edge should be a horizontal line""" - i,j = np.mgrid[-5:6, -5:6] + i, j = np.mgrid[-5:6, -5:6] image = (i >= 0).astype(float) result = F.hsobel(image) # Fudge the eroded points i[np.abs(j) == 5] = 10000 assert (np.all(result[i == 0] == 1)) assert (np.all(result[np.abs(i) > 1] == 0)) - + def test_01_02_vertical(self): """Horizontal Sobel on a vertical edge should be zero""" - i,j = np.mgrid[-5:6, -5:6] + i, j = np.mgrid[-5:6, -5:6] image = (j >= 0).astype(float) result = F.hsobel(image) assert (np.all(result == 0)) @@ -70,27 +70,27 @@ class TestVSobel(): """Vertical sobel on an array of all zeros""" result = F.vsobel(np.zeros((10, 10)), np.ones((10, 10), bool)) assert (np.all(result == 0)) - + def test_00_01_mask(self): """Vertical Sobel on a masked array should be zero""" np.random.seed(0) - result = F.vsobel(np.random.uniform(size=(10, 10)), + result = F.vsobel(np.random.uniform(size=(10, 10)), np.zeros((10, 10), bool)) assert (np.all(result == 0)) def test_01_01_vertical(self): """Vertical Sobel on an edge should be a vertical line""" - i,j = np.mgrid[-5:6, -5:6] + i, j = np.mgrid[-5:6, -5:6] image = (j >= 0).astype(float) result = F.vsobel(image) # Fudge the eroded points j[np.abs(i) == 5] = 10000 assert (np.all(result[j == 0] == 1)) assert (np.all(result[np.abs(j) > 1] == 0)) - + def test_01_02_horizontal(self): """vertical Sobel on a horizontal edge should be zero""" - i,j = np.mgrid[-5:6, -5:6] + i, j = np.mgrid[-5:6, -5:6] image = (i >= 0).astype(float) result = F.vsobel(image) eps = .000001 @@ -101,18 +101,18 @@ class TestPrewitt(): """Prewitt on an array of all zeros""" result = F.prewitt(np.zeros((10, 10)), np.ones((10, 10), bool)) assert (np.all(result == 0)) - + def test_00_01_mask(self): """Prewitt on a masked array should be zero""" np.random.seed(0) - result = F.prewitt(np.random.uniform(size=(10, 10)), - np.zeros((10, 10), bool)) + result = F.prewitt(np.random.uniform(size=(10, 10)), + np.zeros((10, 10), bool)) eps = .000001 assert (np.all(np.abs(result) < eps)) def test_01_01_horizontal(self): """Prewitt on an edge should be a horizontal line""" - i,j = np.mgrid[-5:6, -5:6] + i, j = np.mgrid[-5:6, -5:6] image = (i >= 0).astype(float) result = F.prewitt(image) # Fudge the eroded points @@ -120,10 +120,10 @@ class TestPrewitt(): eps = .000001 assert (np.all(result[i == 0] == 1)) assert (np.all(np.abs(result[np.abs(i) > 1]) < eps)) - + def test_01_02_vertical(self): """Prewitt on a vertical edge should be a vertical line""" - i,j = np.mgrid[-5:6, -5:6] + i, j = np.mgrid[-5:6, -5:6] image = (j >= 0).astype(float) result = F.prewitt(image) eps = .000001 @@ -136,18 +136,18 @@ class TestHPrewitt(): """Horizontal sobel on an array of all zeros""" result = F.hprewitt(np.zeros((10, 10)), np.ones((10, 10), bool)) assert (np.all(result == 0)) - + def test_00_01_mask(self): """Horizontal prewitt on a masked array should be zero""" np.random.seed(0) - result = F.hprewitt(np.random.uniform(size=(10, 10)), - np.zeros((10, 10), bool)) + result = F.hprewitt(np.random.uniform(size=(10, 10)), + np.zeros((10, 10), bool)) eps = .000001 assert (np.all(np.abs(result) < eps)) def test_01_01_horizontal(self): """Horizontal prewitt on an edge should be a horizontal line""" - i,j = np.mgrid[-5:6, -5:6] + i, j = np.mgrid[-5:6, -5:6] image = (i >= 0).astype(float) result = F.hprewitt(image) # Fudge the eroded points @@ -155,10 +155,10 @@ class TestHPrewitt(): eps = .000001 assert (np.all(result[i == 0] == 1)) assert (np.all(np.abs(result[np.abs(i) > 1]) < eps)) - + def test_01_02_vertical(self): """Horizontal prewitt on a vertical edge should be zero""" - i,j = np.mgrid[-5:6, -5:6] + i, j = np.mgrid[-5:6, -5:6] image = (j >= 0).astype(float) result = F.hprewitt(image) eps = .000001 @@ -169,17 +169,17 @@ class TestVPrewitt(): """Vertical prewitt on an array of all zeros""" result = F.vprewitt(np.zeros((10, 10)), np.ones((10, 10), bool)) assert (np.all(result == 0)) - + def test_00_01_mask(self): """Vertical prewitt on a masked array should be zero""" np.random.seed(0) - result = F.vprewitt(np.random.uniform(size=(10, 10)), - np.zeros((10, 10), bool)) + result = F.vprewitt(np.random.uniform(size=(10, 10)), + np.zeros((10, 10), bool)) assert (np.all(result == 0)) def test_01_01_vertical(self): """Vertical prewitt on an edge should be a vertical line""" - i,j = np.mgrid[-5:6, -5:6] + i, j = np.mgrid[-5:6, -5:6] image = (j >= 0).astype(float) result = F.vprewitt(image) # Fudge the eroded points @@ -187,15 +187,15 @@ class TestVPrewitt(): assert (np.all(result[j == 0] == 1)) eps = .000001 assert (np.all(np.abs(result[np.abs(j) > 1]) < eps)) - + def test_01_02_horizontal(self): """Vertical prewitt on a horizontal edge should be zero""" - i,j = np.mgrid[-5:6, -5:6] + i, j = np.mgrid[-5:6, -5:6] image = (i >= 0).astype(float) result = F.vprewitt(image) eps = .000001 assert (np.all(np.abs(result) < eps)) - - + + if __name__ == "__main__": run_module_suite()