From f2246027fd350b676c18ac99955bcbaa1b0f3f9a Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Mon, 3 Sep 2012 07:55:05 -0400 Subject: [PATCH 1/6] STY: Clean up imports --- skimage/filter/tests/test_edges.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/skimage/filter/tests/test_edges.py b/skimage/filter/tests/test_edges.py index bd9a2702..44791728 100644 --- a/skimage/filter/tests/test_edges.py +++ b/skimage/filter/tests/test_edges.py @@ -1,11 +1,6 @@ -import os - -from numpy.testing import * import numpy as np -from scipy.ndimage import binary_dilation, binary_erosion import skimage.filter as F -from skimage import data_dir, img_as_float class TestSobel(): @@ -208,4 +203,5 @@ class TestVPrewitt(): if __name__ == "__main__": - run_module_suite() + from numpy import testing + testing.run_module_suite() From 6e3d460b3cc203c50a76d78f49bc137536422618 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Mon, 3 Sep 2012 08:03:57 -0400 Subject: [PATCH 2/6] STY: Rename tests. Test classes were unnecessary. Simplify to functions. --- skimage/filter/tests/test_edges.py | 332 ++++++++++++++--------------- 1 file changed, 163 insertions(+), 169 deletions(-) diff --git a/skimage/filter/tests/test_edges.py b/skimage/filter/tests/test_edges.py index 44791728..7fe8da4b 100644 --- a/skimage/filter/tests/test_edges.py +++ b/skimage/filter/tests/test_edges.py @@ -3,203 +3,197 @@ import numpy as np import skimage.filter as F -class TestSobel(): - def test_00_00_zeros(self): - """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_sobel_zeros(): + """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)), - np.zeros((10, 10), bool)) - assert (np.all(result == 0)) +def test_sobel_mask(): + """Sobel on a masked array should be zero""" + np.random.seed(0) + result = F.sobel(np.random.uniform(size=(10, 10)), + np.zeros((10, 10), bool)) + assert (np.all(result == 0)) - def test_01_01_horizontal(self): - """Sobel on an edge should be a horizontal line""" - i, j = np.mgrid[-5:6, -5:6] - image = (i >= 0).astype(float) - result = F.sobel(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_sobel_horizontal(): + """Sobel on an edge should be a horizontal line""" + i, j = np.mgrid[-5:6, -5:6] + image = (i >= 0).astype(float) + result = F.sobel(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): - """Sobel on a vertical edge should be a vertical line""" - i, j = np.mgrid[-5:6, -5:6] - image = (j >= 0).astype(float) - result = F.sobel(image) - j[np.abs(i) == 5] = 10000 - assert (np.all(result[j == 0] == 1)) - assert (np.all(result[np.abs(j) > 1] == 0)) +def test_sobel_vertical(): + """Sobel on a vertical edge should be a vertical line""" + i, j = np.mgrid[-5:6, -5:6] + image = (j >= 0).astype(float) + result = F.sobel(image) + j[np.abs(i) == 5] = 10000 + assert (np.all(result[j == 0] == 1)) + assert (np.all(result[np.abs(j) > 1] == 0)) -class TestHSobel(): - def test_00_00_zeros(self): - """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_hsobel_zeros(): + """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)), - np.zeros((10, 10), bool)) - assert (np.all(result == 0)) +def test_hsobel_mask(): + """Horizontal Sobel on a masked array should be zero""" + np.random.seed(0) + 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] - 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_hsobel_horizontal(): + """Horizontal Sobel on an edge should be a horizontal line""" + 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] - image = (j >= 0).astype(float) - result = F.hsobel(image) - assert (np.all(result == 0)) +def test_hsobel_vertical(): + """Horizontal Sobel on a vertical edge should be zero""" + i, j = np.mgrid[-5:6, -5:6] + image = (j >= 0).astype(float) + result = F.hsobel(image) + assert (np.all(result == 0)) -class TestVSobel(): - def test_00_00_zeros(self): - """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_vsobel_zeros(): + """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)), - np.zeros((10, 10), bool)) - assert (np.all(result == 0)) +def test_vsobel_mask(): + """Vertical Sobel on a masked array should be zero""" + np.random.seed(0) + 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] - 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_vsobel_vertical(): + """Vertical Sobel on an edge should be a vertical line""" + 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] - image = (i >= 0).astype(float) - result = F.vsobel(image) - eps = .000001 - assert (np.all(np.abs(result) < eps)) +def test_vsobel_horizontal(): + """vertical Sobel on a horizontal edge should be zero""" + i, j = np.mgrid[-5:6, -5:6] + image = (i >= 0).astype(float) + result = F.vsobel(image) + eps = .000001 + assert (np.all(np.abs(result) < eps)) -class TestPrewitt(): - def test_00_00_zeros(self): - """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_prewitt_zeros(): + """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)) - eps = .000001 - assert (np.all(np.abs(result) < eps)) +def test_prewitt_mask(): + """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)) + 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] - image = (i >= 0).astype(float) - result = F.prewitt(image) - # Fudge the eroded points - i[np.abs(j) == 5] = 10000 - eps = .000001 - assert (np.all(result[i == 0] == 1)) - assert (np.all(np.abs(result[np.abs(i) > 1]) < eps)) +def test_prewitt_horizontal(): + """Prewitt on an edge should be a horizontal line""" + i, j = np.mgrid[-5:6, -5:6] + image = (i >= 0).astype(float) + result = F.prewitt(image) + # Fudge the eroded points + i[np.abs(j) == 5] = 10000 + 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] - image = (j >= 0).astype(float) - result = F.prewitt(image) - eps = .000001 - j[np.abs(i) == 5] = 10000 - assert (np.all(result[j == 0] == 1)) - assert (np.all(np.abs(result[np.abs(j) > 1]) < eps)) +def test_prewitt_vertical(): + """Prewitt on a vertical edge should be a vertical line""" + i, j = np.mgrid[-5:6, -5:6] + image = (j >= 0).astype(float) + result = F.prewitt(image) + eps = .000001 + j[np.abs(i) == 5] = 10000 + assert (np.all(result[j == 0] == 1)) + assert (np.all(np.abs(result[np.abs(j) > 1]) < eps)) -class TestHPrewitt(): - def test_00_00_zeros(self): - """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_hprewitt_zeros(): + """Horizontal prewitt 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)) - eps = .000001 - assert (np.all(np.abs(result) < eps)) +def test_hprewitt_mask(): + """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)) + 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] - image = (i >= 0).astype(float) - result = F.hprewitt(image) - # Fudge the eroded points - i[np.abs(j) == 5] = 10000 - eps = .000001 - assert (np.all(result[i == 0] == 1)) - assert (np.all(np.abs(result[np.abs(i) > 1]) < eps)) +def test_hprewitt_horizontal(): + """Horizontal prewitt on an edge should be a horizontal line""" + i, j = np.mgrid[-5:6, -5:6] + image = (i >= 0).astype(float) + result = F.hprewitt(image) + # Fudge the eroded points + i[np.abs(j) == 5] = 10000 + 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] - image = (j >= 0).astype(float) - result = F.hprewitt(image) - eps = .000001 - assert (np.all(np.abs(result) < eps)) +def test_hprewitt_vertical(): + """Horizontal prewitt on a vertical edge should be zero""" + i, j = np.mgrid[-5:6, -5:6] + image = (j >= 0).astype(float) + result = F.hprewitt(image) + eps = .000001 + assert (np.all(np.abs(result) < eps)) -class TestVPrewitt(): - def test_00_00_zeros(self): - """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_vprewitt_zeros(): + """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)) - assert (np.all(result == 0)) +def test_vprewitt_mask(): + """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)) + 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] - image = (j >= 0).astype(float) - result = F.vprewitt(image) - # Fudge the eroded points - j[np.abs(i) == 5] = 10000 - assert (np.all(result[j == 0] == 1)) - eps = .000001 - assert (np.all(np.abs(result[np.abs(j) > 1]) < eps)) +def test_vprewitt_vertical(): + """Vertical prewitt on an edge should be a vertical line""" + i, j = np.mgrid[-5:6, -5:6] + image = (j >= 0).astype(float) + result = F.vprewitt(image) + # Fudge the eroded points + j[np.abs(i) == 5] = 10000 + 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] - image = (i >= 0).astype(float) - result = F.vprewitt(image) - eps = .000001 - assert (np.all(np.abs(result) < eps)) +def test_vprewitt_horizontal(): + """Vertical prewitt on a horizontal edge should be zero""" + 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__": From 852481e0550aeded06c1e81562f93037c5636cd5 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Mon, 3 Sep 2012 22:27:51 -0400 Subject: [PATCH 3/6] TST: Add tests for masked region --- skimage/filter/tests/test_edges.py | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/skimage/filter/tests/test_edges.py b/skimage/filter/tests/test_edges.py index 7fe8da4b..a5d52aa5 100644 --- a/skimage/filter/tests/test_edges.py +++ b/skimage/filter/tests/test_edges.py @@ -1,4 +1,5 @@ import numpy as np +from numpy.testing import assert_array_almost_equal as assert_close import skimage.filter as F @@ -196,6 +197,40 @@ def test_vprewitt_horizontal(): assert (np.all(np.abs(result) < eps)) +def test_horizontal_mask_line(): + """Horizontal edge filters mask pixels surrounding input mask.""" + vgrad, _ = np.mgrid[:1:11j, :1:11j] # vertical gradient with spacing 0.1 + vgrad[5, :] = 1 # bad horizontal line + + mask = np.ones_like(vgrad) + mask[5, :] = 0 # mask bad line + + expected = np.zeros_like(vgrad) + expected[1:-1, 1:-1] = 0.2 # constant gradient for most of image, + expected[4:7, 1:-1] = 0 # but line and neighbors masked + + for grad_func in (F.hprewitt, F.hsobel): + result = grad_func(vgrad, mask) + yield assert_close, result, expected + + +def test_vertical_mask_line(): + """Vertical edge filters mask pixels surrounding input mask.""" + _, hgrad = np.mgrid[:1:11j, :1:11j] # horizontal gradient with spacing 0.1 + hgrad[:, 5] = 1 # bad vertical line + + mask = np.ones_like(hgrad) + mask[:, 5] = 0 # mask bad line + + expected = np.zeros_like(hgrad) + expected[1:-1, 1:-1] = 0.2 # constant gradient for most of image, + expected[1:-1, 4:7] = 0 # but line and neighbors masked + + for grad_func in (F.vprewitt, F.vsobel): + result = grad_func(hgrad, mask) + yield assert_close, result, expected + + if __name__ == "__main__": from numpy import testing testing.run_module_suite() From bd2f8ac3d3c7c5413bb9f01724a536d0ab92af8b Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Mon, 3 Sep 2012 22:36:11 -0400 Subject: [PATCH 4/6] DOC: Add note about expanded masking --- skimage/filter/edges.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/skimage/filter/edges.py b/skimage/filter/edges.py index cd91effb..ac27802f 100644 --- a/skimage/filter/edges.py +++ b/skimage/filter/edges.py @@ -22,6 +22,8 @@ def sobel(image, mask=None): Image to process. mask : array_like, dtype=bool, optional An optional mask to limit the application to a certain area. + Note that pixels surrounding masked regions are also masked to + prevent masked regions from affecting the result. Returns ------- @@ -49,6 +51,8 @@ def hsobel(image, mask=None): Image to process. mask : array_like, dtype=bool, optional An optional mask to limit the application to a certain area. + Note that pixels surrounding masked regions are also masked to + prevent masked regions from affecting the result. Returns ------- @@ -88,6 +92,8 @@ def vsobel(image, mask=None): Image to process mask : array_like, dtype=bool, optional An optional mask to limit the application to a certain area + Note that pixels surrounding masked regions are also masked to + prevent masked regions from affecting the result. Returns ------- @@ -127,6 +133,8 @@ def prewitt(image, mask=None): Image to process. mask : array_like, dtype=bool, optional An optional mask to limit the application to a certain area. + Note that pixels surrounding masked regions are also masked to + prevent masked regions from affecting the result. Returns ------- @@ -150,6 +158,8 @@ def hprewitt(image, mask=None): Image to process. mask : array_like, dtype=bool, optional An optional mask to limit the application to a certain area. + Note that pixels surrounding masked regions are also masked to + prevent masked regions from affecting the result. Returns ------- @@ -189,6 +199,8 @@ def vprewitt(image, mask=None): Image to process. mask : array_like, dtype=bool, optional An optional mask to limit the application to a certain area. + Note that pixels surrounding masked regions are also masked to + prevent masked regions from affecting the result. Returns ------- From 6c9810c6e9fd5105b70271108f494448bd6e7da5 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Mon, 3 Sep 2012 22:50:57 -0400 Subject: [PATCH 5/6] Refactor masking --- skimage/filter/edges.py | 50 ++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/skimage/filter/edges.py b/skimage/filter/edges.py index ac27802f..1568886c 100644 --- a/skimage/filter/edges.py +++ b/skimage/filter/edges.py @@ -13,6 +13,24 @@ from skimage import img_as_float from scipy.ndimage import convolve, binary_erosion, generate_binary_structure +EROSION_SELEM = generate_binary_structure(2, 2) + + +def _mask_filter_result(result, mask): + """Return result after masking. + + Input masks are eroded so that mask areas in the original image don't + affect values in the result. + """ + if mask is None: + mask = np.zeros(result.shape, bool) + mask[1:-1, 1:-1] = True + else: + mask = binary_erosion(mask, EROSION_SELEM, border_value=0) + result[mask == False] = 0 + return result + + def sobel(image, mask=None): """Calculate the absolute magnitude Sobel to find edges. @@ -70,17 +88,11 @@ def hsobel(image, mask=None): """ image = img_as_float(image) - 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, 2, 1], [ 0, 0, 0], [-1,-2,-1]]).astype(float) / 4.0)) - result[big_mask == False] = 0 - return result + return _mask_filter_result(result, mask) def vsobel(image, mask=None): @@ -111,17 +123,11 @@ def vsobel(image, mask=None): """ image = img_as_float(image) - 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)) - result[big_mask == False] = 0 - return result + return _mask_filter_result(result, mask) def prewitt(image, mask=None): @@ -177,17 +183,11 @@ def hprewitt(image, mask=None): """ image = img_as_float(image) - 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, 1, 1], [ 0, 0, 0], [-1,-1,-1]]).astype(float) / 3.0)) - result[big_mask == False] = 0 - return result + return _mask_filter_result(result, mask) def vprewitt(image, mask=None): @@ -218,14 +218,8 @@ def vprewitt(image, mask=None): """ image = img_as_float(image) - 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[big_mask == False] = 0 - return result + return _mask_filter_result(result, mask) From 367e39094c3658e0e63f84f8c334934c4967a77b Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Tue, 4 Sep 2012 09:35:35 -0400 Subject: [PATCH 6/6] STY: Rework masking based on suggestions by @ahojnnes --- skimage/filter/edges.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/skimage/filter/edges.py b/skimage/filter/edges.py index 1568886c..134aa796 100644 --- a/skimage/filter/edges.py +++ b/skimage/filter/edges.py @@ -23,12 +23,14 @@ def _mask_filter_result(result, mask): affect values in the result. """ if mask is None: - mask = np.zeros(result.shape, bool) - mask[1:-1, 1:-1] = True + result[0, :] = 0 + result[-1, :] = 0 + result[:, 0] = 0 + result[:, -1] = 0 + return result else: mask = binary_erosion(mask, EROSION_SELEM, border_value=0) - result[mask == False] = 0 - return result + return result * mask def sobel(image, mask=None):