From 4c68a5ad44546e8810b73fa65a198ae8666ec4bf Mon Sep 17 00:00:00 2001 From: Pratap Vardhan Date: Mon, 15 Dec 2014 13:10:06 +0530 Subject: [PATCH 1/5] ENH: ellipse structuring element --- skimage/morphology/selem.py | 46 ++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/skimage/morphology/selem.py b/skimage/morphology/selem.py index 57c17214..954bcd35 100644 --- a/skimage/morphology/selem.py +++ b/skimage/morphology/selem.py @@ -5,7 +5,7 @@ import numpy as np from scipy import ndimage - +from skimage import draw def square(width, dtype=np.uint8): """ @@ -118,6 +118,50 @@ def disk(radius, dtype=np.uint8): return np.array((X ** 2 + Y ** 2) <= radius ** 2, dtype=dtype) +def ellipse(radius, height, dtype=np.uint8): + """ + Generates a flat, ellipse-shaped structuring element of given + radius and height. Every pixel along the perimeter satisfies + the equation ``(x/radius+1)**2 + (y/height+1)**2 = 1``. + + Parameters + ---------- + radius : int + The radius of the ellipse-shaped structuring element. + height : int + The height of the ellipse-shaped structuring element. + + Other Parameters + ---------------- + dtype : data-type + The data type of the structuring element. + + Returns + ------- + selem : ndarray + The structuring element where elements of the neighborhood + are 1 and 0 otherwise. + + Examples + -------- + >>> from skimage.morphology import selem + >>> selem.ellipse(5, 3) + array([[0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0]], dtype=uint8) + + """ + + selem = np.zeros((2 * height + 1, 2 * radius + 1), dtype=dtype) + rows, cols = draw.ellipse(height, radius, height + 1, radius + 1) + selem[rows, cols] = 1 + return selem + + def cube(width, dtype=np.uint8): """ Generates a cube-shaped structuring element (the 3D equivalent of From 8d50561d186f0dc927ba1184f360ccbde877b3e0 Mon Sep 17 00:00:00 2001 From: Pratap Vardhan Date: Mon, 15 Dec 2014 13:21:15 +0530 Subject: [PATCH 2/5] TST: Test for ellipse structuring element --- skimage/morphology/tests/test_selem.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/skimage/morphology/tests/test_selem.py b/skimage/morphology/tests/test_selem.py index 35559fe4..545cb0d4 100644 --- a/skimage/morphology/tests/test_selem.py +++ b/skimage/morphology/tests/test_selem.py @@ -102,6 +102,25 @@ class TestSElem(): assert_equal(expected_mask1, actual_mask1) assert_equal(expected_mask2, actual_mask2) + def test_selem_ellipse(self): + """Test ellipse structuring elements""" + expected_mask1 = np.array([[0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0]], dtype=uint8) + actual_mask1 = selem.ellipse(5, 3) + expected_mask2 = np.array([[1, 1, 1], + [1, 1, 1], + [1, 1, 1]], dtype=np.uint8) + actual_mask2 = selem.ellipse(1, 1) + assert_equal(expected_mask1, actual_mask1) + assert_equal(expected_mask2, actual_mask2) + assert_equal(expected_mask1, selem.ellipse(3, 5).T) + assert_equal(expected_mask2, selem.ellipse(1, 1).T) + def test_selem_star(self): """Test star structuring elements""" expected_mask1 = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], From 65c6b773ce87c9d18238b4d41e751440632a175a Mon Sep 17 00:00:00 2001 From: Pratap Vardhan Date: Mon, 15 Dec 2014 14:49:26 +0530 Subject: [PATCH 3/5] DOC: Clean up doc strings --- skimage/morphology/selem.py | 95 +++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/skimage/morphology/selem.py b/skimage/morphology/selem.py index 954bcd35..a84a0fe1 100644 --- a/skimage/morphology/selem.py +++ b/skimage/morphology/selem.py @@ -8,15 +8,15 @@ from scipy import ndimage from skimage import draw def square(width, dtype=np.uint8): - """ - Generates a flat, square-shaped structuring element. Every pixel - along the perimeter has a chessboard distance no greater than radius - (radius=floor(width/2)) pixels. + """Generates a flat, square-shaped structuring element. + + Every pixel along the perimeter has a chessboard distance + no greater than radius (radius=floor(width/2)) pixels. Parameters ---------- width : int - The width and height of the square + The width and height of the square. Other Parameters ---------------- @@ -34,17 +34,17 @@ def square(width, dtype=np.uint8): def rectangle(width, height, dtype=np.uint8): - """ - Generates a flat, rectangular-shaped structuring element of a - given width and height. Every pixel in the rectangle belongs - to the neighboorhood. + """Generates a flat, rectangular-shaped structuring element. + + Every pixel in the rectangle generated for a given width and given height + belongs to the neighboorhood. Parameters ---------- width : int - The width of the rectangle + The width of the rectangle. height : int - The height of the rectangle + The height of the rectangle. Other Parameters ---------------- @@ -62,11 +62,11 @@ def rectangle(width, height, dtype=np.uint8): def diamond(radius, dtype=np.uint8): - """ - Generates a flat, diamond-shaped structuring element of a given - radius. A pixel is part of the neighborhood (i.e. labeled 1) if - the city block/manhattan distance between it and the center of the - neighborhood is no greater than radius. + """Generates a flat, diamond-shaped structuring element. + + A pixel is part of the neighborhood (i.e. labeled 1) if + the city block/manhattan distance between it and the center of + the neighborhood is no greater than radius. Parameters ---------- @@ -92,8 +92,8 @@ def diamond(radius, dtype=np.uint8): def disk(radius, dtype=np.uint8): - """ - Generates a flat, disk-shaped structuring element of a given radius. + """Generates a flat, disk-shaped structuring element. + A pixel is within the neighborhood if the euclidean distance between it and the origin is no greater than radius. @@ -119,9 +119,9 @@ def disk(radius, dtype=np.uint8): def ellipse(radius, height, dtype=np.uint8): - """ - Generates a flat, ellipse-shaped structuring element of given - radius and height. Every pixel along the perimeter satisfies + """Generates a flat, ellipse-shaped structuring element. + + Every pixel along the perimeter of ellipse satisfies the equation ``(x/radius+1)**2 + (y/height+1)**2 = 1``. Parameters @@ -163,15 +163,16 @@ def ellipse(radius, height, dtype=np.uint8): def cube(width, dtype=np.uint8): - """ - Generates a cube-shaped structuring element (the 3D equivalent of - a square). Every pixel along the perimeter has a chessboard distance + """ Generates a cube-shaped structuring element. + + This is the 3D equivalent of a square. + Every pixel along the perimeter has a chessboard distance no greater than radius (radius=floor(width/2)) pixels. Parameters ---------- width : int - The width, height and depth of the cube + The width, height and depth of the cube. Other Parameters ---------------- @@ -189,12 +190,12 @@ def cube(width, dtype=np.uint8): def octahedron(radius, dtype=np.uint8): - """ - Generates a octahedron-shaped structuring element of a given radius - (the 3D equivalent of a diamond). A pixel is part of the - neighborhood (i.e. labeled 1) if the city block/manhattan distance - between it and the center of the neighborhood is no greater than - radius. + """Generates a octahedron-shaped structuring element. + + This is the 3D equivalent of a diamond. + A pixel is part of the neighborhood (i.e. labeled 1) if + the city block/manhattan distance between it and the center of + the neighborhood is no greater than radius. Parameters ---------- @@ -223,11 +224,11 @@ def octahedron(radius, dtype=np.uint8): def ball(radius, dtype=np.uint8): - """ - Generates a ball-shaped structuring element of a given radius (the - 3D equivalent of a disk). A pixel is within the neighborhood if the - euclidean distance between it and the origin is no greater than - radius. + """Generates a ball-shaped structuring element. + + This is the 3D equivalent of a disk. + A pixel is within the neighborhood if the euclidean distance between + it and the origin is no greater than radius. Parameters ---------- @@ -254,10 +255,11 @@ def ball(radius, dtype=np.uint8): def octagon(m, n, dtype=np.uint8): - """ - Generates an octagon shaped structuring element with a given size of - horizontal and vertical sides and a given height or width of slanted - sides. The slanted sides are 45 or 135 degrees to the horizontal axis + """Generates an octagon shaped structuring element. + + For a given size of (m) horizontal and vertical sides + and a given (n) height or width of slanted sides octagon is generated. + The slanted sides are 45 or 135 degrees to the horizontal axis and hence the widths and heights are equal. Parameters @@ -294,9 +296,10 @@ def octagon(m, n, dtype=np.uint8): def star(a, dtype=np.uint8): - """ - Generates a star shaped structuring element that has 8 vertices and is an - overlap of square of size `2*a + 1` with its 45 degree rotated version. + """Generates a star shaped structuring element. + + Start has 8 vertices and is an overlap of square of size `2*a + 1` + with its 45 degree rotated version. The slanted sides are 45 or 135 degrees to the horizontal axis. Parameters @@ -342,9 +345,9 @@ def star(a, dtype=np.uint8): def _default_selem(ndim): - """ - Generates a cross-shaped structuring element (connectivity=1). This is the - default structuring element (selem) if no selem was specified. + """Generates a cross-shaped structuring element (connectivity=1). + + This is the default structuring element (selem) if no selem was specified. Parameters ---------- From db7b43199db33cd83ed446cf62042b43681b2bf3 Mon Sep 17 00:00:00 2001 From: Pratap Vardhan Date: Mon, 15 Dec 2014 18:13:39 +0530 Subject: [PATCH 4/5] BUG: Change dtype --- skimage/morphology/tests/test_selem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/morphology/tests/test_selem.py b/skimage/morphology/tests/test_selem.py index 545cb0d4..ebefdfa1 100644 --- a/skimage/morphology/tests/test_selem.py +++ b/skimage/morphology/tests/test_selem.py @@ -110,7 +110,7 @@ class TestSElem(): [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0]], dtype=uint8) + [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0]], dtype=np.uint8) actual_mask1 = selem.ellipse(5, 3) expected_mask2 = np.array([[1, 1, 1], [1, 1, 1], From 2d4a77d94e271cdc244b2a65f94d897fd2f12fd4 Mon Sep 17 00:00:00 2001 From: Pratap Vardhan Date: Tue, 16 Dec 2014 10:40:01 +0530 Subject: [PATCH 5/5] DOC: Change selem.ellipse params --- skimage/morphology/selem.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/skimage/morphology/selem.py b/skimage/morphology/selem.py index a84a0fe1..f75022ab 100644 --- a/skimage/morphology/selem.py +++ b/skimage/morphology/selem.py @@ -118,16 +118,16 @@ def disk(radius, dtype=np.uint8): return np.array((X ** 2 + Y ** 2) <= radius ** 2, dtype=dtype) -def ellipse(radius, height, dtype=np.uint8): +def ellipse(width, height, dtype=np.uint8): """Generates a flat, ellipse-shaped structuring element. Every pixel along the perimeter of ellipse satisfies - the equation ``(x/radius+1)**2 + (y/height+1)**2 = 1``. + the equation ``(x/width+1)**2 + (y/height+1)**2 = 1``. Parameters ---------- - radius : int - The radius of the ellipse-shaped structuring element. + width : int + The width of the ellipse-shaped structuring element. height : int The height of the ellipse-shaped structuring element. @@ -155,9 +155,8 @@ def ellipse(radius, height, dtype=np.uint8): [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0]], dtype=uint8) """ - - selem = np.zeros((2 * height + 1, 2 * radius + 1), dtype=dtype) - rows, cols = draw.ellipse(height, radius, height + 1, radius + 1) + selem = np.zeros((2 * height + 1, 2 * width + 1), dtype=dtype) + rows, cols = draw.ellipse(height, width, height + 1, width + 1) selem[rows, cols] = 1 return selem