From 60b560ff9eec996dea872078f2cd09d102f65af0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Boulogne?= Date: Sat, 12 Jan 2013 10:56:52 +0100 Subject: [PATCH 1/4] add andres method for circle_perimeter --- skimage/draw/_draw.pyx | 46 +++++++++++++++++++++++++++------ skimage/draw/tests/test_draw.py | 36 +++++++++++++++++++++++--- 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/skimage/draw/_draw.pyx b/skimage/draw/_draw.pyx index 509796bb..ff41410c 100644 --- a/skimage/draw/_draw.pyx +++ b/skimage/draw/_draw.pyx @@ -189,7 +189,7 @@ def circle(double cy, double cx, double radius, shape=None): return ellipse(cy, cx, radius, radius, shape) -def circle_perimeter(int cy, int cx, int radius): +def circle_perimeter(int cy, int cx, int radius, method='bresenham'): """Generate circle perimeter coordinates. Parameters @@ -198,6 +198,10 @@ def circle_perimeter(int cy, int cx, int radius): Centre coordinate of circle. radius: int Radius of circle. + method : string + bresenham : Bresenham method + andres : Andres method + Returns ------- @@ -206,6 +210,13 @@ def circle_perimeter(int cy, int cx, int radius): 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. + """ cdef list rr = list() @@ -213,17 +224,36 @@ def circle_perimeter(int cy, int cx, int radius): cdef int x = 0 cdef int y = radius - cdef int d = 3 - 2 * radius + cdef int d = 0 + if method == 'bresenham': + d = 3 - 2 * radius + elif method == 'andres': + d = radius - 1 + else: + raise ValueError('Wrong method') 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 + + if method == 'bresenham': + if d < 0: + d += 4 * x + 6 + else: + d += 4 * (x - y) + 10 + y -= 1 + x += 1 + elif method == 'andres': + if err >= 2 * (x - 1): + err = err - 2*x + x = x + 1 + elif err <= 2*(radius - y): + err = err + 2 * y - 1 + y = y - 1 + else: + err = err + 2*(y - x - 1) + y = y - 1 + x = 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 04cbae92..b2325015 100644 --- a/skimage/draw/tests/test_draw.py +++ b/skimage/draw/tests/test_draw.py @@ -150,14 +150,14 @@ def test_circle(): assert_array_equal(img, img_) -def test_circle_perimeter(): +def test_circle_perimeter_bresenham(): img = np.zeros((15, 15), 'uint8') - rr, cc = circle_perimeter(7, 7, 0) + rr, cc = circle_perimeter(7, 7, 0, method='bresenham') img[rr, cc] = 1 assert(np.sum(img) == 1) img = np.zeros((17, 15), 'uint8') - rr, cc = circle_perimeter(7, 7, 7) + rr, cc = circle_perimeter(7, 7, 7, method='bresenham') img[rr, cc] = 1 img_ = np.array( [[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], @@ -180,6 +180,36 @@ def test_circle_perimeter(): ) assert_array_equal(img, img_) +def test_circle_perimeter_andres(): + img = np.zeros((15, 15), 'uint8') + rr, cc = circle_perimeter(7, 7, 0, method='andres') + img[rr, cc] = 1 + assert(np.sum(img) == 1) + + img = np.zeros((17, 15), 'uint8') + rr, cc = circle_perimeter(7, 7, 7, method='andres') + img[rr, cc] = 1 + img_ = np.array( + [[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0], + [0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0], + [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], + [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [1, 1, 0, 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, 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], + [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1], + [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], + [0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 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, 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') From 1fb5ae1a7514d4963de5be63d78a760df9cee493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Boulogne?= Date: Sat, 12 Jan 2013 11:29:18 +0100 Subject: [PATCH 2/4] fix variable --- skimage/draw/_draw.pyx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/skimage/draw/_draw.pyx b/skimage/draw/_draw.pyx index ff41410c..e3048de3 100644 --- a/skimage/draw/_draw.pyx +++ b/skimage/draw/_draw.pyx @@ -244,14 +244,14 @@ def circle_perimeter(int cy, int cx, int radius, method='bresenham'): y -= 1 x += 1 elif method == 'andres': - if err >= 2 * (x - 1): - err = err - 2*x + if d >= 2 * (x - 1): + d = d - 2*x x = x + 1 - elif err <= 2*(radius - y): - err = err + 2 * y - 1 + elif d <= 2*(radius - y): + d = d + 2 * y - 1 y = y - 1 else: - err = err + 2*(y - x - 1) + d = d + 2*(y - x - 1) y = y - 1 x = x + 1 From 3b84744c251c4ad1855af3a6314d1e9cfecf5467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Boulogne?= Date: Sat, 12 Jan 2013 11:58:33 +0100 Subject: [PATCH 3/4] fix docstring + PEP8 --- skimage/draw/_draw.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/skimage/draw/_draw.pyx b/skimage/draw/_draw.pyx index e3048de3..6c50842f 100644 --- a/skimage/draw/_draw.pyx +++ b/skimage/draw/_draw.pyx @@ -198,7 +198,7 @@ def circle_perimeter(int cy, int cx, int radius, method='bresenham'): Centre coordinate of circle. radius: int Radius of circle. - method : string + method : {'bresenham', 'andres'}, optional bresenham : Bresenham method andres : Andres method @@ -245,13 +245,13 @@ def circle_perimeter(int cy, int cx, int radius, method='bresenham'): x += 1 elif method == 'andres': if d >= 2 * (x - 1): - d = d - 2*x + d = d - 2 * x x = x + 1 - elif d <= 2*(radius - y): + elif d <= 2 * (radius - y): d = d + 2 * y - 1 y = y - 1 else: - d = d + 2*(y - x - 1) + d = d + 2 * (y - x - 1) y = y - 1 x = x + 1 From 7eab419cabbc6eea70b04121be3762df0315f02c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Boulogne?= Date: Sat, 12 Jan 2013 12:19:06 +0100 Subject: [PATCH 4/4] add references --- skimage/draw/_draw.pyx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/skimage/draw/_draw.pyx b/skimage/draw/_draw.pyx index 6c50842f..7c77b423 100644 --- a/skimage/draw/_draw.pyx +++ b/skimage/draw/_draw.pyx @@ -217,6 +217,12 @@ def circle_perimeter(int cy, int cx, int radius, method='bresenham'): is also less distortions when Andres circles are rotated. Bresenham method is also known as midpoint circle algorithm. + References + ---------- + .. [1] J.E. Bresenham, "Algorithm for computer control of a digital + plotter", 4 (1965) 25-30. + .. [2] E. Andres, "Discrete circles, rings and spheres", 18 (1994) 695-706. + """ cdef list rr = list()