ADD: bezier_curve

This commit is contained in:
François Boulogne
2013-10-02 17:25:16 +02:00
parent 5c423475e6
commit 1548364b65
3 changed files with 214 additions and 7 deletions
+2 -1
View File
@@ -2,10 +2,11 @@ from .draw import circle, ellipse, set_color
from .draw3d import ellipsoid, ellipsoid_stats
from ._draw import (line, line_aa, polygon, ellipse_perimeter,
circle_perimeter, circle_perimeter_aa,
_bezier_segment)
_bezier_segment, bezier_curve)
__all__ = ['line',
'line_aa',
'bezier_curve',
'polygon',
'ellipse',
'ellipse_perimeter',
+112
View File
@@ -677,6 +677,118 @@ def _bezier_segment(Py_ssize_t y0, Py_ssize_t x0,
return np.array(py, dtype=np.intp), np.array(px, dtype=np.intp)
def bezier_curve(Py_ssize_t y0, Py_ssize_t x0,
Py_ssize_t y1, Py_ssize_t x1,
Py_ssize_t y2, Py_ssize_t x2,
double weight):
"""Generate Bezier curve coordinates.
Parameters
----------
y0, x0 : int
Coordinates of the first point
y1, x1 : int
Coordinates of the middle point
y2, x2 : int
Coordinates of the last point
weight : double
Middle point weight, it describes the line tension.
Returns
-------
rr, cc : (N,) ndarray of int
Indices of pixels that belong to the Bezier curve.
May be used to directly index into an array, e.g.
``img[rr, cc] = 1``.
Notes
-----
The algorithm is the rational quadratic algorithm presented in
reference [1].
References
----------
.. [1] A Rasterizing Algorithm for Drawing Curves, A. Zingl, 2012
http://members.chello.at/easyfilter/Bresenham.pdf
"""
# Pixels
cdef list px = list()
cdef list py = list()
cdef int x, y
cdef double xx, yy, ww, t, q
x = x0 - 2 * x1 + x2
y = y0 - 2 * y1 + y2
xx = x0 - x1
yy = y0 - y1
if xx * (x2 - x1) > 0:
if yy * (y2 - y1):
if abs(xx * y) > abs(yy * x):
x0 = x2
x2 = <Py_ssize_t>(xx + x1)
y0 = y2
y2 = <Py_ssize_t>(yy + y1)
if (x0 == x2) or (weight == 1.):
t = <double>(x0 - x1) / x
else:
q = sqrt(4. * weight * weight * (x0 - x1) * (x2 - x1) + (x2 - x0) * floor(x2 - x0))
if (x1 < x0):
q = -q
t = (2. * weight * (x0 - x1) - x0 + x2 + q) / (2. * (1. - weight) * (x2 - x0))
q = 1. / (2. * t * (1. - t) * (weight - 1.) + 1.0)
xx = (t * t * (x0 - 2. * weight * x1 + x2) + 2. * t * (weight * x1 - x0) + x0) * q
yy = (t * t * (y0 - 2. * weight * y1 + y2) + 2. * t * (weight * y1 - y0) + y0) * q
ww = t * (weight - 1.) + 1.
ww *= ww * q
weight = ((1. - t) * (weight - 1.) + 1.) * sqrt(q)
x = <int>(xx + 0.5)
y = <int>(yy + 0.5)
yy = (xx - x0) * (y1 - y0) / (x1 - x0) + y0
rr, cc = _bezier_segment(y0, x0, <int>(yy + 0.5), x, y, x, ww)
px.extend(rr)
py.extend(cc)
yy = (xx - x2) * (y1 - y2) / (x1 - x2) + y2
y1 = <int>(yy + 0.5)
x0 = x1 = x
y0 = y
if (y0 - y1) * floor(y2 - y1) > 0:
if (y0 == y2) or (weight == 1):
t = (y0 - y1) / (y0 - 2. * y1 + y2)
else:
q = sqrt(4. * weight * weight * (y0 - y1) * (y2 - y1) + (y2 - y0) * floor(y2 - y0))
if y1 < y0:
q = -q
t = (2. * weight * (y0 - y1) - y0 + y2 + q) / (2. * (1. - weight) * (y2 - y0))
q = 1. / (2. * t * (1. - t) * (weight - 1.) + 1.)
xx = (t * t * (x0 - 2. * weight * x1 + x2) + 2. * t * (weight * x1 - x0) + x0) * q
yy = (t * t * (y0 - 2. * weight * y1 + y2) + 2. * t * (weight * y1 - y0) + y0) * q
ww = t * (weight - 1.) + 1.
ww *= ww * q
weight = ((1. - t) * (weight - 1.) + 1.) * sqrt(q)
x = <int>(xx + 0.5)
y = <int>(yy + 0.5)
xx = (x1 - x0) * (yy - y0) / (y1 - y0) + x0
rr, cc = _bezier_segment(y0, x0, y, <int>(xx + 0.5), y, x, ww)
px.extend(rr)
py.extend(cc)
xx = (x1 - x2) * (yy - y2) / (y1 - y2) + x2
x1 = <int>(xx + 0.5)
x0 = x
y0 = y1 = y
rr, cc = _bezier_segment(y0, x0, y1, x1, y2, x2, weight * weight)
px.extend(rr)
py.extend(cc)
return np.array(px, dtype=np.intp), np.array(py, dtype=np.intp)
def set_color(img, coords, color):
"""Set pixel color in the image at the given coordinates.
+100 -6
View File
@@ -1,11 +1,10 @@
from numpy.testing import assert_array_equal, assert_equal
import numpy as np
from skimage.draw import (line, line_aa,
polygon, circle,
circle_perimeter, circle_perimeter_aa,
ellipse,
ellipse_perimeter, _bezier_segment,
from skimage.draw import (line, line_aa, polygon,
circle, circle_perimeter, circle_perimeter_aa,
ellipse, ellipse_perimeter,
_bezier_segment, bezier_curve,
)
@@ -444,7 +443,10 @@ def test_bezier_segment_straight():
def test_bezier_segment_curved():
img = np.zeros((25, 25), 'uint8')
rr, cc = _bezier_segment(20, 20, 20, 2, 2, 2, 1)
x1, y1 = 20, 20
x2, y2 = 20, 2
x3, y3 = 2, 2
rr, cc = _bezier_segment(x1, y1, x2, y2, x3, y3, 1)
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],
@@ -473,9 +475,101 @@ def test_bezier_segment_curved():
[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_equal(img[x1, y1], 1)
assert_equal(img[x3, y3], 1)
assert_array_equal(img, img_)
def test_bezier_curve_straight():
image = np.zeros((200, 200), dtype=int)
x0 = 50
y0 = 50
x1 = 150
y1 = 50
x2 = 150
y2 = 150
rr, cc = bezier_curve(x0, y0, x1, y1, x2, y2, 0)
image [rr, cc] = 1
image2 = np.zeros((200, 200), dtype=int)
rr, cc = line(x0, y0, x2, y2)
image2 [rr, cc] = 1
assert_array_equal(image, image2)
def test_bezier_curved_weight_eq_1():
img = np.zeros((23, 8), 'uint8')
x1, y1 = (1, 1)
x2, y2 = (11, 11)
x3, y3 = (21, 1)
rr, cc = bezier_curve(x1, y1, x2, y2, x3, y3, 1)
img[rr, cc] = 1
assert_equal(img[x1, y1], 1)
assert_equal(img[x3, y3], 1)
img_ = np.array(
[[0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0],
[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, 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, 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, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0]]
)
assert_equal(img, img_)
def test_bezier_curved_weight_neq_1():
img = np.zeros((23, 10), 'uint8')
x1, y1 = (1, 1)
x2, y2 = (11, 11)
x3, y3 = (21, 1)
rr, cc = bezier_curve(x1, y1, x2, y2, x3, y3, 2)
img[rr, cc] = 1
assert_equal(img[x1, y1], 1)
assert_equal(img[x3, y3], 1)
img_ = np.array(
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
)
assert_equal(img, img_)
if __name__ == "__main__":
from numpy.testing import run_module_suite
run_module_suite()