Implement line_aa

This commit is contained in:
François Boulogne
2013-08-27 16:36:19 +02:00
parent bf31517843
commit 90335efdda
3 changed files with 127 additions and 5 deletions
+4 -2
View File
@@ -1,9 +1,11 @@
from .draw import circle, ellipse, set_color
from ._draw import (line, polygon, ellipse_perimeter, circle_perimeter,
circle_perimeter_aa, bezier_segment)
from .draw3d import ellipsoid, ellipsoid_stats
from ._draw import (line, line_aa, polygon, ellipse_perimeter,
circle_perimeter, circle_perimeter_aa,
bezier_segment)
__all__ = ['line',
'line_aa',
'polygon',
'ellipse',
'ellipse_perimeter',
+81
View File
@@ -27,6 +27,10 @@ def line(Py_ssize_t y, Py_ssize_t x, Py_ssize_t y2, Py_ssize_t x2):
May be used to directly index into an array, e.g.
``img[rr, cc] = 1``.
Notes
-----
Anti-aliased line generator is available with `line_aa`.
Examples
--------
>>> from skimage.draw import line
@@ -89,6 +93,83 @@ def line(Py_ssize_t y, Py_ssize_t x, Py_ssize_t y2, Py_ssize_t x2):
return np.asarray(rr), np.asarray(cc)
def line_aa(Py_ssize_t y1, Py_ssize_t x1, Py_ssize_t y2, Py_ssize_t x2):
"""Generate line pixel coordinates.
Parameters
----------
y1, x1 : int
Starting position (row, column).
y2, x2 : int
End position (row, column).
Returns
-------
rr, cc, val : (N,) ndarray of int
Indices of pixels that belong to the line.
May be used to directly index into an array, e.g.
``img[rr, cc] = val``.
References
----------
.. [1] A Rasterizing Algorithm for Drawing Curves, A. Zingl, 2012
http://members.chello.at/easyfilter/Bresenham.pdf
"""
cdef list rr = list()
cdef list cc = list()
cdef list val = list()
cdef int dx = abs(x1 - x2)
cdef int dy = abs(y1 - y2)
cdef int err = dx - dy
cdef int x, y, e, ed, sign_x, sign_y
if x1 < x2:
sign_x = 1
else:
sign_x = -1
if y1 < y2:
sign_y = 1
else:
sign_y = -1
if dx + dy == 0:
ed = 1
else:
ed = <int>(sqrt(dx*dx + dy*dy))
x, y = x1, y1
while True:
cc.append(x)
rr.append(y)
val.append(255 * abs(err - dx + dy) / ed)
e = err
if 2 * e >= -dx:
if x == x2:
break
if e + dy < ed:
cc.append(x)
rr.append(y + sign_y)
val.append(255 * abs(e + dy) / ed)
err -= dy
x += sign_x
if 2 * e <= dy:
if y == y2:
break
if dx - e < ed:
cc.append(x)
rr.append(y)
val.append(255 * abs(dx - e) / ed)
err += dx
y += sign_y
return (np.array(rr, dtype=np.intp),
np.array(cc, dtype=np.intp),
255 - np.array(val, dtype=np.intp))
def polygon(y, x, shape=None):
"""Generate coordinates of pixels within polygon.
+42 -3
View File
@@ -1,8 +1,10 @@
from numpy.testing import assert_array_equal
from numpy.testing import assert_array_equal, assert_equal
import numpy as np
from skimage.draw import (line, polygon, circle, circle_perimeter,
circle_perimeter_aa, ellipse,
from skimage.draw import (line, line_aa,
polygon, circle,
circle_perimeter, circle_perimeter_aa,
ellipse,
ellipse_perimeter, bezier_segment,
)
@@ -54,6 +56,43 @@ def test_line_diag():
assert_array_equal(img, img_)
def test_line_aa_horizontal():
img = np.zeros((10, 10))
rr, cc, val = line_aa(0, 0, 0, 9)
img[rr, cc] = val
img_ = np.zeros((10, 10))
img_[0, :] = 255
assert_array_equal(img, img_)
def test_line_aa_vertical():
img = np.zeros((10, 10))
rr, cc, val = line_aa(0, 0, 9, 0)
img[rr, cc] = val
img_ = np.zeros((10, 10))
img_[:, 0] = 255
assert_array_equal(img, img_)
def test_line_aa_diagonal():
img = np.zeros((10, 10))
rr, cc, val = line_aa(0, 0, 9, 6)
img[rr, cc] = 1
# Check that each pixel belonging to line,
# also belongs to line_aa
r, c = line(0, 0, 9, 6)
for x, y in zip(r, c):
assert_equal(img[r, c], 1)
def test_polygon_rectangle():
img = np.zeros((10, 10), 'uint8')
poly = np.array(((1, 1), (4, 1), (4, 4), (1, 4), (1, 1)))