From de8369be50208f94db5f90ebe33474ebafd7a8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Scho=CC=88nberger?= Date: Mon, 23 Apr 2012 16:20:49 +0200 Subject: [PATCH] added draw circle and ellipse functions --- skimage/draw/_draw.pyx | 65 +++++++++++++++++++++++++++++++++ skimage/draw/draw.py | 2 +- skimage/draw/tests/test_draw.py | 54 ++++++++++++++++++++++++++- 3 files changed, 119 insertions(+), 2 deletions(-) diff --git a/skimage/draw/_draw.pyx b/skimage/draw/_draw.pyx index 44bfea55..6f6c955f 100644 --- a/skimage/draw/_draw.pyx +++ b/skimage/draw/_draw.pyx @@ -1,5 +1,6 @@ import numpy as np import math +from libc.math cimport sqrt cimport numpy as np cimport cython @@ -121,3 +122,67 @@ def polygon(verts, shape=None): cc.append(c) return np.array(rr), np.array(cc) + +@cython.boundscheck(False) +@cython.wraparound(False) +@cython.nonecheck(False) +@cython.cdivision(True) +def ellipse(double cy, double cx, double b, double a, shape=None): + """Generate coordinates of pixels within ellipse. + + Parameters + ---------- + cy, cx : double + centre coordinate of ellipse + b, a: double + minor and major semi-axes. (x/a)**2 + (y/b)**2 = 1 + + Returns + ------- + rr, cc : ndarray of int + Pixel coordinates of ellipse. + May be used to directly index into an array, e.g. + ``img[rr, cc] = 1``. + """ + cdef int minr = max(0, cy-b) + cdef int maxr = math.ceil(cy+b) + cdef int minc = max(0, cx-a) + cdef int maxc = math.ceil(cx+a) + + # make sure output coordinates do not exceed image size + if shape is not None: + maxr = min(shape[0]-1, maxr) + maxc = min(shape[1]-1, maxc) + + cdef int r, c + + #: output coordinate arrays + rr = list() + cc = list() + + for r in range(minr, maxr+1): + for c in range(minc, maxc+1): + if sqrt(((r - cy)/b)**2 + ((c - cx)/a)**2) < 1: + rr.append(r) + cc.append(c) + + return np.array(rr), np.array(cc) + +def circle(double cy, double cx, double radius, shape=None): + """Generate coordinates of pixels within circle. + + Parameters + ---------- + cy, cx : double + centre coordinate of circle + radius: double + radius of circle + + Returns + ------- + rr, cc : ndarray of int + Pixel coordinates of ellipse. + May be used to directly index into an array, e.g. + ``img[rr, cc] = 1``. + """ + return ellipse(cy, cx, radius, radius, shape) diff --git a/skimage/draw/draw.py b/skimage/draw/draw.py index 5a7f9339..a18cdeb6 100644 --- a/skimage/draw/draw.py +++ b/skimage/draw/draw.py @@ -3,4 +3,4 @@ Methods to draw on arrays. """ -from ._draw import bresenham, polygon +from ._draw import bresenham, polygon, ellipse, circle diff --git a/skimage/draw/tests/test_draw.py b/skimage/draw/tests/test_draw.py index 80873981..ed309cf6 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 bresenham, polygon +from skimage.draw import bresenham, polygon, circle, ellipse def test_bresenham_horizontal(): @@ -116,6 +116,58 @@ def test_polygon_exceed(): assert_array_equal(img, img_) +def test_circle(): + img = np.zeros((15, 15), 'uint8') + + rr, cc = circle(7, 7, 6) + img[rr,cc] = 1 + + img_ = np.array( + [[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, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0], + [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 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') + + rr, cc = ellipse(7, 7, 3, 7) + img[rr,cc] = 1 + + img_ = np.array( + [[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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], + [0, 0, 1, 1, 1, 1, 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, 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_) + if __name__ == "__main__": from numpy.testing import run_module_suite