From b0f2afe67370268d95ac93aea208e36ceece865c Mon Sep 17 00:00:00 2001 From: Alexandre de Siqueira Date: Mon, 3 Jun 2019 15:32:11 -0700 Subject: [PATCH] Improving docs and tests for directional filters --- doc/examples/edges/plot_edge_filter.py | 19 +++-- skimage/filters/edges.py | 53 +++++------- skimage/filters/tests/test_edges.py | 109 ++++++++++++------------- 3 files changed, 83 insertions(+), 98 deletions(-) diff --git a/doc/examples/edges/plot_edge_filter.py b/doc/examples/edges/plot_edge_filter.py index 749818e424d..a1c9a2bad38 100644 --- a/doc/examples/edges/plot_edge_filter.py +++ b/doc/examples/edges/plot_edge_filter.py @@ -90,21 +90,22 @@ plt.show() ###################################################################### -# As in the example above, we illustrate the rotational invariance -# of the filters in this example. The top row shows a -# rotationally invariant image along with the angle of its analytical gradient. -# The other two rows contain the difference between the different gradient -# approximations (Sobel, Prewitt, Scharr & Farid) and analytical gradient. +# As in the previous example, here we illustrate the rotational invariance of +# the filters. The top row shows a rotationally invariant image along with the +# angle of its analytical gradient. The other two rows contain the difference +# between the different gradient approximations (Sobel, Prewitt, Scharr & +# Farid) and analytical gradient. # # The Farid & Simoncelli derivative filters [4]_, [5]_ are the most # rotationally invariant, but require a 5x5 kernel, which is computationally # more intensive than a 3x3 kernel. # -# .. [4] Farid, Hany, and Eero P. Simoncelli. "Differentiation of discrete -# multidimensional signals." -# IEEE Transactions on image processing 13.4 (2004): 496-508. +# .. [4] Farid, H. and Simoncelli, E. P., "Differentiation of discrete +# multidimensional signals", IEEE Transactions on Image Processing 13(4): +# 496-508, 2004. :DOI:`10.1109/TIP.2004.823819` # -# .. [5] https://en.wikipedia.org/wiki/Image_derivatives +# .. [5] Wikipedia, "Farid and Simoncelli Derivatives." Available at: +# x, y = np.mgrid[-10:10:255j, -10:10:255j] diff --git a/skimage/filters/edges.py b/skimage/filters/edges.py index 6ad8225b86c..232eaa4f263 100644 --- a/skimage/filters/edges.py +++ b/skimage/filters/edges.py @@ -548,7 +548,7 @@ def laplace(image, ksize=3, mask=None): def farid(image, mask=None): - """Find the edge magnitude using the Farid & Simoncelli transform. + """Find the edge magnitude using the Farid transform. Parameters ---------- @@ -562,7 +562,7 @@ def farid(image, mask=None): Returns ------- output : 2-D array - The Farid & Simoncelli edge map. + The Farid edge map. See also -------- @@ -577,13 +577,11 @@ def farid(image, mask=None): References ---------- - .. [1] Farid, Hany, and Eero P. Simoncelli. "Differentiation of discrete - multidimensional signals." - IEEE Transactions on image processing 13.4 (2004): 496-508. - - - .. [2] https://en.wikipedia.org/wiki/Image_derivatives - #Farid_and_Simoncelli_Derivatives + .. [1] Farid, H. and Simoncelli, E. P., "Differentiation of discrete + multidimensional signals", IEEE Transactions on Image Processing + 13(4): 496-508, 2004. :DOI:`10.1109/TIP.2004.823819` + .. [2] Wikipedia, "Farid and Simoncelli Derivatives." Available at: + Examples -------- @@ -599,8 +597,7 @@ def farid(image, mask=None): def farid_h(image, mask=None): - """Find the horizontal edges of an image using the Farid & Simoncelli - transform. + """Find the horizontal edges of an image using the Farid transform. Parameters ---------- @@ -614,23 +611,20 @@ def farid_h(image, mask=None): Returns ------- output : 2-D array - The Farid & Simoncelli edge map. + The Farid edge map. Notes ----- - The kernel was constructed using the 5-tap weights from [1] - + The kernel was constructed using the 5-tap weights from [1]. References ---------- - .. [1] Farid, Hany, and Eero P. Simoncelli. "Differentiation of discrete - multidimensional signals." - IEEE Transactions on image processing 13.4 (2004): 496-508. - .. [2] Farid, Hany, and Eero P. Simoncelli. "Optimally - rotation-equivariant directional derivative kernels." - International Conference on Computer Analysis of Images and Patterns. - Springer, Berlin, Heidelberg, 1997. - + .. [1] Farid, H. and Simoncelli, E. P., "Differentiation of discrete + multidimensional signals", IEEE Transactions on Image Processing + 13(4): 496-508, 2004. :DOI:`10.1109/TIP.2004.823819` + .. [2] Farid, H. and Simoncelli, E. P. "Optimally rotation-equivariant + directional derivative kernels", In: 7th International Conference on + Computer Analysis of Images and Patterns, Kiel, Germany. Sep, 1997. """ assert_nD(image, 2) image = img_as_float(image) @@ -639,8 +633,7 @@ def farid_h(image, mask=None): def farid_v(image, mask=None): - """Find the vertical edges of an image using the Farid & Simoncelli - transform. + """Find the vertical edges of an image using the Farid transform. Parameters ---------- @@ -654,19 +647,17 @@ def farid_v(image, mask=None): Returns ------- output : 2-D array - The Farid & Simoncelli edge map. + The Farid edge map. Notes ----- - The kernel was constructed using the 5-tap weights from [1] - + The kernel was constructed using the 5-tap weights from [1]. References ---------- - .. [1] Farid, Hany, and Eero P. Simoncelli. "Differentiation of discrete - multidimensional signals." - IEEE Transactions on image processing 13.4 (2004): 496-508. - + .. [1] Farid, H. and Simoncelli, E. P., "Differentiation of discrete + multidimensional signals", IEEE Transactions on Image Processing + 13(4): 496-508, 2004. :DOI:`10.1109/TIP.2004.823819` """ assert_nD(image, 2) image = img_as_float(image) diff --git a/skimage/filters/tests/test_edges.py b/skimage/filters/tests/test_edges.py index dac8750d036..252dd528652 100644 --- a/skimage/filters/tests/test_edges.py +++ b/skimage/filters/tests/test_edges.py @@ -41,9 +41,8 @@ def test_sobel_zeros(): def test_sobel_mask(): """Sobel on a masked array should be zero.""" - np.random.seed(0) result = filters.sobel(np.random.uniform(size=(10, 10)), - np.zeros((10, 10), bool)) + np.zeros((10, 10), dtype=bool)) assert (np.all(result == 0)) @@ -52,7 +51,7 @@ def test_sobel_horizontal(): i, j = np.mgrid[-5:6, -5:6] image = (i >= 0).astype(float) result = filters.sobel(image) * np.sqrt(2) - # Fudge the eroded points + # Check if result match transform direction i[np.abs(j) == 5] = 10000 assert_allclose(result[i == 0], 1) assert (np.all(result[np.abs(i) > 1] == 0)) @@ -70,15 +69,14 @@ def test_sobel_vertical(): def test_sobel_h_zeros(): """Horizontal sobel on an array of all zeros.""" - result = filters.sobel_h(np.zeros((10, 10)), np.ones((10, 10), bool)) + result = filters.sobel_h(np.zeros((10, 10)), np.ones((10, 10), dtype=bool)) assert (np.all(result == 0)) def test_sobel_h_mask(): """Horizontal Sobel on a masked array should be zero.""" - np.random.seed(0) result = filters.sobel_h(np.random.uniform(size=(10, 10)), - np.zeros((10, 10), bool)) + np.zeros((10, 10), dtype=bool)) assert (np.all(result == 0)) @@ -87,7 +85,7 @@ def test_sobel_h_horizontal(): i, j = np.mgrid[-5:6, -5:6] image = (i >= 0).astype(float) result = filters.sobel_h(image) - # Fudge the eroded points + # Check if result match transform direction i[np.abs(j) == 5] = 10000 assert (np.all(result[i == 0] == 1)) assert (np.all(result[np.abs(i) > 1] == 0)) @@ -103,15 +101,14 @@ def test_sobel_h_vertical(): def test_sobel_v_zeros(): """Vertical sobel on an array of all zeros.""" - result = filters.sobel_v(np.zeros((10, 10)), np.ones((10, 10), bool)) + result = filters.sobel_v(np.zeros((10, 10)), np.ones((10, 10), dtype=bool)) assert_allclose(result, 0) def test_sobel_v_mask(): """Vertical Sobel on a masked array should be zero.""" - np.random.seed(0) result = filters.sobel_v(np.random.uniform(size=(10, 10)), - np.zeros((10, 10), bool)) + np.zeros((10, 10), dtype=bool)) assert_allclose(result, 0) @@ -120,7 +117,7 @@ def test_sobel_v_vertical(): i, j = np.mgrid[-5:6, -5:6] image = (j >= 0).astype(float) result = filters.sobel_v(image) - # Fudge the eroded points + # Check if result match transform direction j[np.abs(i) == 5] = 10000 assert (np.all(result[j == 0] == 1)) assert (np.all(result[np.abs(j) > 1] == 0)) @@ -136,15 +133,14 @@ def test_sobel_v_horizontal(): def test_scharr_zeros(): """Scharr on an array of all zeros.""" - result = filters.scharr(np.zeros((10, 10)), np.ones((10, 10), bool)) + result = filters.scharr(np.zeros((10, 10)), np.ones((10, 10), dtype=bool)) assert (np.all(result < 1e-16)) def test_scharr_mask(): """Scharr on a masked array should be zero.""" - np.random.seed(0) result = filters.scharr(np.random.uniform(size=(10, 10)), - np.zeros((10, 10), bool)) + np.zeros((10, 10), dtype=bool)) assert_allclose(result, 0) @@ -153,7 +149,7 @@ def test_scharr_horizontal(): i, j = np.mgrid[-5:6, -5:6] image = (i >= 0).astype(float) result = filters.scharr(image) * np.sqrt(2) - # Fudge the eroded points + # Check if result match transform direction i[np.abs(j) == 5] = 10000 assert_allclose(result[i == 0], 1) assert (np.all(result[np.abs(i) > 1] == 0)) @@ -171,15 +167,15 @@ def test_scharr_vertical(): def test_scharr_h_zeros(): """Horizontal Scharr on an array of all zeros.""" - result = filters.scharr_h(np.zeros((10, 10)), np.ones((10, 10), bool)) + result = filters.scharr_h(np.zeros((10, 10)), + np.ones((10, 10), dtype=bool)) assert_allclose(result, 0) def test_scharr_h_mask(): """Horizontal Scharr on a masked array should be zero.""" - np.random.seed(0) result = filters.scharr_h(np.random.uniform(size=(10, 10)), - np.zeros((10, 10), bool)) + np.zeros((10, 10), dtype=bool)) assert_allclose(result, 0) @@ -188,7 +184,7 @@ def test_scharr_h_horizontal(): i, j = np.mgrid[-5:6, -5:6] image = (i >= 0).astype(float) result = filters.scharr_h(image) - # Fudge the eroded points + # Check if result match transform direction i[np.abs(j) == 5] = 10000 assert (np.all(result[i == 0] == 1)) assert (np.all(result[np.abs(i) > 1] == 0)) @@ -204,15 +200,15 @@ def test_scharr_h_vertical(): def test_scharr_v_zeros(): """Vertical Scharr on an array of all zeros.""" - result = filters.scharr_v(np.zeros((10, 10)), np.ones((10, 10), bool)) + result = filters.scharr_v(np.zeros((10, 10)), + np.ones((10, 10), dtype=bool)) assert_allclose(result, 0) def test_scharr_v_mask(): """Vertical Scharr on a masked array should be zero.""" - np.random.seed(0) result = filters.scharr_v(np.random.uniform(size=(10, 10)), - np.zeros((10, 10), bool)) + np.zeros((10, 10), dtype=bool)) assert_allclose(result, 0) @@ -221,7 +217,7 @@ def test_scharr_v_vertical(): i, j = np.mgrid[-5:6, -5:6] image = (j >= 0).astype(float) result = filters.scharr_v(image) - # Fudge the eroded points + # Check if result match transform direction j[np.abs(i) == 5] = 10000 assert (np.all(result[j == 0] == 1)) assert (np.all(result[np.abs(j) > 1] == 0)) @@ -237,15 +233,15 @@ def test_scharr_v_horizontal(): def test_prewitt_zeros(): """Prewitt on an array of all zeros.""" - result = filters.prewitt(np.zeros((10, 10)), np.ones((10, 10), bool)) + result = filters.prewitt(np.zeros((10, 10)), + np.ones((10, 10), dtype=bool)) assert_allclose(result, 0) def test_prewitt_mask(): """Prewitt on a masked array should be zero.""" - np.random.seed(0) result = filters.prewitt(np.random.uniform(size=(10, 10)), - np.zeros((10, 10), bool)) + np.zeros((10, 10), dtype=bool)) assert_allclose(np.abs(result), 0) @@ -254,7 +250,7 @@ def test_prewitt_horizontal(): i, j = np.mgrid[-5:6, -5:6] image = (i >= 0).astype(float) result = filters.prewitt(image) * np.sqrt(2) - # Fudge the eroded points + # Check if result match transform direction i[np.abs(j) == 5] = 10000 assert (np.all(result[i == 0] == 1)) assert_allclose(result[np.abs(i) > 1], 0, atol=1e-10) @@ -272,15 +268,15 @@ def test_prewitt_vertical(): def test_prewitt_h_zeros(): """Horizontal prewitt on an array of all zeros.""" - result = filters.prewitt_h(np.zeros((10, 10)), np.ones((10, 10), bool)) + result = filters.prewitt_h(np.zeros((10, 10)), + np.ones((10, 10), dtype=bool)) assert_allclose(result, 0) def test_prewitt_h_mask(): """Horizontal prewitt on a masked array should be zero.""" - np.random.seed(0) result = filters.prewitt_h(np.random.uniform(size=(10, 10)), - np.zeros((10, 10), bool)) + np.zeros((10, 10), dtype=bool)) assert_allclose(result, 0) @@ -289,7 +285,7 @@ def test_prewitt_h_horizontal(): i, j = np.mgrid[-5:6, -5:6] image = (i >= 0).astype(float) result = filters.prewitt_h(image) - # Fudge the eroded points + # Check if result match transform direction i[np.abs(j) == 5] = 10000 assert (np.all(result[i == 0] == 1)) assert_allclose(result[np.abs(i) > 1], 0, atol=1e-10) @@ -305,15 +301,15 @@ def test_prewitt_h_vertical(): def test_prewitt_v_zeros(): """Vertical prewitt on an array of all zeros.""" - result = filters.prewitt_v(np.zeros((10, 10)), np.ones((10, 10), bool)) + result = filters.prewitt_v(np.zeros((10, 10)), + np.ones((10, 10), dtype=bool)) assert_allclose(result, 0) def test_prewitt_v_mask(): """Vertical prewitt on a masked array should be zero.""" - np.random.seed(0) result = filters.prewitt_v(np.random.uniform(size=(10, 10)), - np.zeros((10, 10), bool)) + np.zeros((10, 10), dtype=bool)) assert_allclose(result, 0) @@ -322,7 +318,7 @@ def test_prewitt_v_vertical(): i, j = np.mgrid[-5:6, -5:6] image = (j >= 0).astype(float) result = filters.prewitt_v(image) - # Fudge the eroded points + # Check if result match transform direction j[np.abs(i) == 5] = 10000 assert (np.all(result[j == 0] == 1)) assert_allclose(result[np.abs(j) > 1], 0, atol=1e-10) @@ -342,16 +338,16 @@ def test_laplace_zeros(): image = np.zeros((9, 9)) image[3:-3, 3:-3] = 1 result = filters.laplace(image) - res_chk = np.array([[0., 0., 0., 0., 0., 0., 0., 0., 0.], - [0., 0., 0., 0., 0., 0., 0., 0., 0.], - [0., 0., 0., -1., -1., -1., 0., 0., 0.], - [0., 0., -1., 2., 1., 2., -1., 0., 0.], - [0., 0., -1., 1., 0., 1., -1., 0., 0.], - [0., 0., -1., 2., 1., 2., -1., 0., 0.], - [0., 0., 0., -1., -1., -1., 0., 0., 0.], - [0., 0., 0., 0., 0., 0., 0., 0., 0.], - [0., 0., 0., 0., 0., 0., 0., 0., 0.]]) - assert_allclose(result, res_chk) + check_result = np.array([[0., 0., 0., 0., 0., 0., 0., 0., 0.], + [0., 0., 0., 0., 0., 0., 0., 0., 0.], + [0., 0., 0., -1., -1., -1., 0., 0., 0.], + [0., 0., -1., 2., 1., 2., -1., 0., 0.], + [0., 0., -1., 1., 0., 1., -1., 0., 0.], + [0., 0., -1., 2., 1., 2., -1., 0., 0.], + [0., 0., 0., -1., -1., -1., 0., 0., 0.], + [0., 0., 0., 0., 0., 0., 0., 0., 0.], + [0., 0., 0., 0., 0., 0., 0., 0., 0.]]) + assert_allclose(result, check_result) def test_laplace_mask(): @@ -360,21 +356,20 @@ def test_laplace_mask(): image = np.zeros((9, 9)) image[3:-3, 3:-3] = 1 # Define the mask - result = filters.laplace(image, ksize=3, mask=np.zeros((9, 9), bool)) + result = filters.laplace(image, ksize=3, mask=np.zeros((9, 9), dtype=bool)) assert (np.all(result == 0)) def test_farid_zeros(): """Farid on an array of all zeros.""" - result = filters.farid(np.zeros((10, 10)), np.ones((10, 10), bool)) + result = filters.farid(np.zeros((10, 10)), np.ones((10, 10), dtype=bool)) assert (np.all(result == 0)) def test_farid_mask(): """Farid on a masked array should be zero.""" - np.random.seed(0) result = filters.farid(np.random.uniform(size=(10, 10)), - np.zeros((10, 10), bool)) + np.zeros((10, 10), dtype=bool)) assert (np.all(result == 0)) @@ -383,7 +378,7 @@ def test_farid_horizontal(): i, j = np.mgrid[-5:6, -5:6] image = (i >= 0).astype(float) result = filters.farid(image) * np.sqrt(2) - # Fudge the eroded points + # Check if result match transform direction i[np.abs(j) == 5] = 10000 assert (np.all(result[i == 0] == result[i == 0][0])) assert_allclose(result[np.abs(i) > 2], 0, atol=1e-10) @@ -401,15 +396,14 @@ def test_farid_vertical(): def test_farid_h_zeros(): """Horizontal Farid on an array of all zeros.""" - result = filters.farid_h(np.zeros((10, 10)), np.ones((10, 10), bool)) + result = filters.farid_h(np.zeros((10, 10)), np.ones((10, 10), dtype=bool)) assert (np.all(result == 0)) def test_farid_h_mask(): """Horizontal Farid on a masked array should be zero.""" - np.random.seed(0) result = filters.farid_h(np.random.uniform(size=(10, 10)), - np.zeros((10, 10), bool)) + np.zeros((10, 10), dtype=bool)) assert (np.all(result == 0)) @@ -418,7 +412,7 @@ def test_farid_h_horizontal(): i, j = np.mgrid[-5:6, -5:6] image = (i >= 0).astype(float) result = filters.farid_h(image) - # Fudge the eroded points + # Check if result match transform direction i[np.abs(j) == 5] = 10000 assert np.all(result[i == 0] == result[i == 0][0]) assert_allclose(result[np.abs(i) > 2], 0, atol=1e-10) @@ -434,15 +428,14 @@ def test_farid_h_vertical(): def test_farid_v_zeros(): """Vertical Farid on an array of all zeros.""" - result = filters.farid_v(np.zeros((10, 10)), np.ones((10, 10), bool)) + result = filters.farid_v(np.zeros((10, 10)), np.ones((10, 10), dtype=bool)) assert_allclose(result, 0, atol=1e-10) def test_farid_v_mask(): """Vertical Farid on a masked array should be zero.""" - np.random.seed(0) result = filters.farid_v(np.random.uniform(size=(10, 10)), - np.zeros((10, 10), bool)) + np.zeros((10, 10), dtype=bool)) assert_allclose(result, 0) @@ -451,7 +444,7 @@ def test_farid_v_vertical(): i, j = np.mgrid[-5:6, -5:6] image = (j >= 0).astype(float) result = filters.farid_v(image) - # Fudge the eroded points + # Check if result match transform direction j[np.abs(i) == 5] = 10000 assert (np.all(result[j == 0] == result[j == 0][0])) assert_allclose(result[np.abs(j) > 2], 0, atol=1e-10)