Skip to content

Commit

Permalink
ENH: Added float support for radius and centre in circle_perimeter fu…
Browse files Browse the repository at this point in the history
…nction
  • Loading branch information
bewithaman committed May 21, 2015
1 parent e91dcba commit 798411d
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 22 deletions.
35 changes: 15 additions & 20 deletions skimage/draw/_draw.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -289,15 +289,14 @@ def polygon(y, x, shape=None):
return np.array(rr, dtype=np.intp), np.array(cc, dtype=np.intp)


def circle_perimeter(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t radius,
def circle_perimeter(float cy, float cx, float radius,
method='bresenham', shape=None):
"""Generate circle perimeter coordinates.
Parameters
----------
cy, cx : int
cy, cx : float
Centre coordinate of circle.
radius: int
radius: float
Radius of circle.
method : {'bresenham', 'andres'}, optional
bresenham : Bresenham method (default)
Expand All @@ -306,30 +305,26 @@ def circle_perimeter(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t radius,
Image shape which is used to determine the maximum extent of output pixel
coordinates. This is useful for circles which exceed the image size.
By default the full extent of the circle are used.
Returns
-------
rr, cc : (N,) ndarray of int
Bresenham and Andres' method:
Indices of pixels that belong to the circle perimeter.
May be used to directly index into an array, e.g.
``img[rr, cc] = 1``.
Notes
-----
Andres method presents the advantage that concentric
circles create a disc whereas Bresenham can make holes. There
is also less distortions when Andres circles are rotated.
Bresenham method is also known as midpoint circle algorithm.
Anti-aliased circle generator is available with `circle_perimeter_aa`.
References
----------
.. [1] J.E. Bresenham, "Algorithm for computer control of a digital
plotter", IBM Systems journal, 4 (1965) 25-30.
.. [2] E. Andres, "Discrete circles, rings and spheres", Computers &
Graphics, 18 (1994) 695-706.
Examples
--------
>>> from skimage.draw import circle_perimeter
Expand All @@ -347,18 +342,14 @@ def circle_perimeter(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t radius,
[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, 0, 0, 0]], dtype=uint8)
"""

cdef list rr = list()
cdef list cc = list()

cdef Py_ssize_t x = 0
cdef Py_ssize_t y = radius
cdef Py_ssize_t d = 0

cdef double dceil = 0
cdef double dceil_prev = 0
cdef float x = 0
cdef float y = radius
cdef float d = 0

cdef char cmethod
if method == 'bresenham':
Expand Down Expand Up @@ -392,12 +383,16 @@ def circle_perimeter(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t radius,
d = d + 2 * (y - x - 1)
y = y - 1
x = x + 1

ry = (np.array(rr, dtype=np.float) + cy)
rx = (np.array(cc, dtype=np.float) + cx)
ry = np.round(ry)
rx = np.round(rx)

if shape is not None:
return _coords_inside_image(np.array(rr, dtype=np.intp) + cy,
np.array(cc, dtype=np.intp) + cx,
shape)
return (np.array(rr, dtype=np.intp) + cy,
np.array(cc, dtype=np.intp) + cx)
return _coords_inside_image(ry.astype(np.int), rx.astype(np.int), shape)

return (ry.astype(np.int), rx.astype(np.int))


def circle_perimeter_aa(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t radius,
Expand Down
50 changes: 48 additions & 2 deletions skimage/draw/tests/test_draw.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,28 @@ def test_circle_perimeter_bresenham():
)
assert_array_equal(img, img_)

img = np.zeros((15, 15), 'uint8')
rr, cc = circle_perimeter(4.4, 8, 4.3, method='bresenham')
img[rr, cc] = 1
img_ = np.array(
[[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0],
[0, 0, 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, 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, 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_circle_perimeter_bresenham_shape():
img = np.zeros((15, 20), 'uint8')
Expand Down Expand Up @@ -276,6 +298,30 @@ def test_circle_perimeter_andres():
)
assert_array_equal(img, img_)

img = np.zeros((17 ,17), 'uint8')
rr, cc = circle_perimeter(7.2, 8.8, 7.4, method='andres')
img[rr, cc] = 1
img_ = np.array(
[[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
[0, 0, 1, 0, 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, 0, 0, 0, 1],
[0, 1, 0, 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, 0, 0, 0, 1],
[0, 1, 0, 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, 0, 0, 0, 1],
[0, 1, 0, 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, 0, 0, 0, 1],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 1, 1, 0, 0, 0, 0, 0, 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, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 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]]
)
assert_array_equal(img, img_)


def test_circle_perimeter_aa():
img = np.zeros((15, 15), 'uint8')
Expand Down Expand Up @@ -471,8 +517,8 @@ def test_ellipse_with_shape():
[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, 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, 0, 0, 0, 0, 0]
])

assert_array_equal(img, img_)

Expand Down

0 comments on commit 798411d

Please sign in to comment.