diff --git a/skimage/draw/__init__.py b/skimage/draw/__init__.py index 4eac9b63..b213f93f 100644 --- a/skimage/draw/__init__.py +++ b/skimage/draw/__init__.py @@ -1,2 +1,2 @@ -from ._draw import line, polygon, ellipse, circle +from ._draw import line, polygon, ellipse, circle, circle_perimeter bresenham = line diff --git a/skimage/draw/_draw.pyx b/skimage/draw/_draw.pyx index ca0c502a..b5b96a2b 100644 --- a/skimage/draw/_draw.pyx +++ b/skimage/draw/_draw.pyx @@ -187,3 +187,42 @@ def circle(double cy, double cx, double radius, shape=None): ``img[rr, cc] = 1``. """ return ellipse(cy, cx, radius, radius, shape) + + +def circle_perimeter(int cy, int cx, int radius): + """Generate circle perimeter coordinates. + + Parameters + ---------- + cy, cx : int + Centre coordinate of circle. + radius: int + Radius of circle. + + Returns + ------- + rr, cc : (N,) ndarray of int + Indices of pixels that belong to the circle perimeter. + May be used to directly index into an array, e.g. + ``img[rr, cc] = 1``. + + """ + + cdef list rr = list() + cdef list cc = list() + + cdef int x = 0 + cdef int y = radius + cdef int d = 3 - 2 * radius + + while y >= x: + rr.extend([y, -y, y, -y, x, -x, x, -x]) + cc.extend([x, x, -x, -x, y, y, -y, -y]) + if d < 0: + d += 4 * x + 6 + else: + d += 4 * (x - y) + 10 + y -= 1 + x += 1 + + return np.array(rr) + cy, np.array(cc) + cx diff --git a/skimage/draw/tests/test_draw.py b/skimage/draw/tests/test_draw.py index 9e6ca8e8..04cbae92 100644 --- a/skimage/draw/tests/test_draw.py +++ b/skimage/draw/tests/test_draw.py @@ -1,7 +1,7 @@ from numpy.testing import assert_array_equal import numpy as np -from skimage.draw import line, polygon, circle, ellipse +from skimage.draw import line, polygon, circle, circle_perimeter, ellipse def test_line_horizontal(): @@ -150,6 +150,37 @@ def test_circle(): assert_array_equal(img, img_) +def test_circle_perimeter(): + img = np.zeros((15, 15), 'uint8') + rr, cc = circle_perimeter(7, 7, 0) + img[rr, cc] = 1 + assert(np.sum(img) == 1) + + img = np.zeros((17, 15), 'uint8') + rr, cc = circle_perimeter(7, 7, 7) + img[rr, cc] = 1 + img_ = np.array( + [[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] + ) + assert_array_equal(img, img_) + + def test_ellipse(): img = np.zeros((15, 15), 'uint8')