Merge pull request #669 from ankit-maverick/octagon

Adding Octagon structural element
This commit is contained in:
Johannes Schönberger
2013-08-07 23:35:35 -07:00
3 changed files with 164 additions and 31 deletions
+3 -1
View File
@@ -4,7 +4,8 @@ from .grey import (erosion, dilation, opening, closing, white_tophat,
black_tophat, greyscale_erode, greyscale_dilate,
greyscale_open, greyscale_close, greyscale_white_top_hat,
greyscale_black_top_hat)
from .selem import square, rectangle, diamond, disk, cube, octahedron, ball
from .selem import (square, rectangle, diamond, disk, cube, octahedron, ball,
octagon, star)
from .ccomp import label
from .watershed import watershed, is_local_maximum
from ._skeletonize import skeletonize, medial_axis
@@ -36,6 +37,7 @@ __all__ = ['binary_erosion',
'cube',
'octahedron',
'ball',
'octagon',
'label',
'watershed',
'is_local_maximum',
+119 -30
View File
@@ -15,18 +15,18 @@ def square(width, dtype=np.uint8):
Parameters
----------
width : int
The width and height of the square
The width and height of the square
Other Parameters
----------------
dtype : data-type
The data type of the structuring element.
The data type of the structuring element.
Returns
-------
selem : ndarray
A structuring element consisting only of ones, i.e. every
pixel belongs to the neighborhood.
A structuring element consisting only of ones, i.e. every
pixel belongs to the neighborhood.
"""
return np.ones((width, width), dtype=dtype)
@@ -41,21 +41,20 @@ def rectangle(width, height, dtype=np.uint8):
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
----------------
dtype : data-type
The data type of the structuring element.
The data type of the structuring element.
Returns
-------
selem : ndarray
A structuring element consisting only of ones, i.e. every
pixel belongs to the neighborhood.
A structuring element consisting only of ones, i.e. every
pixel belongs to the neighborhood.
"""
return np.ones((width, height), dtype=dtype)
@@ -71,17 +70,19 @@ def diamond(radius, dtype=np.uint8):
Parameters
----------
radius : int
The radius of the diamond-shaped structuring element.
The radius of the diamond-shaped structuring element.
Other Parameters
----------------
dtype : data-type
The data type of the structuring element.
The data type of the structuring element.
Returns
-------
selem : ndarray
The structuring element where elements of the neighborhood
are 1 and 0 otherwise.
The structuring element where elements of the neighborhood
are 1 and 0 otherwise.
"""
half = radius
(I, J) = np.meshgrid(range(0, radius * 2 + 1), range(0, radius * 2 + 1))
@@ -98,16 +99,18 @@ def disk(radius, dtype=np.uint8):
Parameters
----------
radius : int
The radius of the disk-shaped structuring element.
The radius of the disk-shaped structuring element.
Other Parameters
----------------
dtype : data-type
The data type of the structuring element.
The data type of the structuring element.
Returns
-------
selem : ndarray
The structuring element where elements of the neighborhood
are 1 and 0 otherwise.
The structuring element where elements of the neighborhood
are 1 and 0 otherwise.
"""
L = np.linspace(-radius, radius, 2 * radius + 1)
(X, Y) = np.meshgrid(L, L)
@@ -125,18 +128,18 @@ def cube(width, dtype=np.uint8):
Parameters
----------
width : int
The width, height and depth of the cube
The width, height and depth of the cube
Other Parameters
----------------
dtype : data-type
The data type of the structuring element.
The data type of the structuring element.
Returns
-------
selem : ndarray
A structuring element consisting only of ones, i.e. every
pixel belongs to the neighborhood.
A structuring element consisting only of ones, i.e. every
pixel belongs to the neighborhood.
"""
return np.ones((width, width, width), dtype=dtype)
@@ -153,17 +156,19 @@ def octahedron(radius, dtype=np.uint8):
Parameters
----------
radius : int
The radius of the octahedron-shaped structuring element.
The radius of the octahedron-shaped structuring element.
Other Parameters
----------------
dtype : data-type
The data type of the structuring element.
The data type of the structuring element.
Returns
-------
selem : ndarray
The structuring element where elements of the neighborhood
are 1 and 0 otherwise.
The structuring element where elements of the neighborhood
are 1 and 0 otherwise.
"""
# note that in contrast to diamond(), this method allows non-integer radii
n = 2 * radius + 1
@@ -184,16 +189,18 @@ def ball(radius, dtype=np.uint8):
Parameters
----------
radius : int
The radius of the ball-shaped structuring element.
The radius of the ball-shaped structuring element.
Other Parameters
----------------
dtype : data-type
The data type of the structuring element.
The data type of the structuring element.
Returns
-------
selem : ndarray
The structuring element where elements of the neighborhood
are 1 and 0 otherwise.
The structuring element where elements of the neighborhood
are 1 and 0 otherwise.
"""
n = 2 * radius + 1
Z, Y, X = np.mgrid[ -radius:radius:n*1j,
@@ -201,3 +208,85 @@ def ball(radius, dtype=np.uint8):
-radius:radius:n*1j]
s = X**2 + Y**2 + Z**2
return np.array(s <= radius * radius, dtype=dtype)
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
and hence the widths and heights are equal.
Parameters
----------
m : int
The size of the horizontal and vertical sides.
n : int
The height or width of the slanted sides.
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.
"""
from . import convex_hull_image
selem = np.zeros((m + 2*n, m + 2*n))
selem[0, n] = 1
selem[n, 0] = 1
selem[0, m + n -1] = 1
selem[m + n - 1, 0] = 1
selem[-1, n] = 1
selem[n, -1] = 1
selem[-1, m + n - 1] = 1
selem[m + n - 1, -1] = 1
selem = convex_hull_image(selem).astype(dtype)
return selem
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.
The slanted sides are 45 or 135 degrees to the horizontal axis.
Parameters
----------
a : int
Parameter deciding the size of the star structural element. The side
of the square array returned is `2*a + 1 + 2*floor(a / 2)`.
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.
"""
from . import convex_hull_image
if a == 1:
bfilter = np.zeros((3, 3), dtype)
bfilter[:] = 1
return bfilter
m = 2 * a + 1
n = a / 2
selem_square = np.zeros((m + 2 * n, m + 2 * n))
selem_square[n: m + n, n: m + n] = 1
c = (m + 2 * n - 1) / 2
selem_rotated = np.zeros((m + 2 * n, m + 2 * n))
selem_rotated[0, c] = selem_rotated[-1, c] = selem_rotated[c, 0] = selem_rotated[c, -1] = 1
selem_rotated = convex_hull_image(selem_rotated).astype(int)
selem = selem_square + selem_rotated
selem[selem > 0] = 1
return selem.astype(dtype)
+42
View File
@@ -66,6 +66,48 @@ class TestSElem():
def test_selem_octahedron(self):
self.strel_worker_3d("diamond-matlab-output.npz", selem.octahedron)
def test_selem_octagon(self):
expected_mask1 = np.array([[0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0]], dtype=np.uint8)
actual_mask1 = selem.octagon(5, 3)
expected_mask2 = np.array([[0, 1, 0],
[1, 1, 1],
[0, 1, 0]], dtype=np.uint8)
actual_mask2 = selem.octagon(1, 1)
assert_equal(expected_mask1, actual_mask1)
assert_equal(expected_mask2, actual_mask2)
def test_selem_star(self):
expected_mask1 = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]], dtype=np.uint8)
actual_mask1 = selem.star(4)
expected_mask2 = np.array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]], dtype=np.uint8)
actual_mask2 = selem.star(1)
assert_equal(expected_mask1, actual_mask1)
assert_equal(expected_mask2, actual_mask2)
if __name__ == '__main__':
np.testing.run_module_suite()