mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-13 05:17:07 +08:00
add shape option to draw functions
This commit is contained in:
+62
-4
@@ -10,6 +10,31 @@ from libc.math cimport sqrt, sin, cos, floor, ceil
|
||||
from skimage._shared.geometry cimport point_in_polygon
|
||||
|
||||
|
||||
def _coords_inside_image(rr, cc, shape, val=None):
|
||||
"""
|
||||
Return the coordinates inside an image of a given shape.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rr, cc : (N,) ndarray of int
|
||||
Indices of pixels.
|
||||
shape : tuple, optional
|
||||
Image shape which is used to determine maximum extents of output pixel
|
||||
coordinates.
|
||||
val : ndarray of float
|
||||
Values of pixels.
|
||||
|
||||
Returns
|
||||
-------
|
||||
rr, cc, val : (N,) ndarray (int, int, float)
|
||||
Indices of pixels (and values if specified) inside the shape.
|
||||
"""
|
||||
mask = (rr >= 0) & (rr < shape[0]) & (cc >= 0) & (cc < shape[1])
|
||||
if val is not None:
|
||||
return rr[mask], cc[mask], val[mask]
|
||||
return rr[mask], cc[mask]
|
||||
|
||||
|
||||
def line(Py_ssize_t y, Py_ssize_t x, Py_ssize_t y2, Py_ssize_t x2):
|
||||
"""Generate line pixel coordinates.
|
||||
|
||||
@@ -263,7 +288,7 @@ def polygon(y, x, shape=None):
|
||||
|
||||
|
||||
def circle_perimeter(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t radius,
|
||||
method='bresenham'):
|
||||
method='bresenham', shape=None):
|
||||
"""Generate circle perimeter coordinates.
|
||||
|
||||
Parameters
|
||||
@@ -275,6 +300,10 @@ def circle_perimeter(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t radius,
|
||||
method : {'bresenham', 'andres'}, optional
|
||||
bresenham : Bresenham method (default)
|
||||
andres : Andres method
|
||||
shape : tuple, optional
|
||||
Image shape which is used to determine maximum extents of output pixel
|
||||
coordinates. This is useful for circles which exceed the image size.
|
||||
By default the full extents of the polygon are used.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -361,11 +390,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
|
||||
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)
|
||||
|
||||
|
||||
def circle_perimeter_aa(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t radius):
|
||||
def circle_perimeter_aa(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t radius,
|
||||
shape=None):
|
||||
"""Generate anti-aliased circle perimeter coordinates.
|
||||
|
||||
Parameters
|
||||
@@ -374,6 +408,10 @@ def circle_perimeter_aa(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t radius):
|
||||
Centre coordinate of circle.
|
||||
radius: int
|
||||
Radius of circle.
|
||||
shape : tuple, optional
|
||||
Image shape which is used to determine maximum extents of output pixel
|
||||
coordinates. This is useful for circles which exceed the image size.
|
||||
By default the full extents of the polygon are used.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -436,13 +474,18 @@ def circle_perimeter_aa(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t radius):
|
||||
val.extend([1 - dceil, dceil] * 8)
|
||||
dceil_prev = dceil
|
||||
|
||||
if shape is not None:
|
||||
return _coords_inside_image(np.array(rr, dtype=np.intp) + cy,
|
||||
np.array(cc, dtype=np.intp) + cx,
|
||||
shape,
|
||||
val=np.array(val, dtype=np.float))
|
||||
return (np.array(rr, dtype=np.intp) + cy,
|
||||
np.array(cc, dtype=np.intp) + cx,
|
||||
np.array(val, dtype=np.float))
|
||||
|
||||
|
||||
def ellipse_perimeter(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t yradius,
|
||||
Py_ssize_t xradius, double orientation=0):
|
||||
Py_ssize_t xradius, double orientation=0, shape=None):
|
||||
"""Generate ellipse perimeter coordinates.
|
||||
|
||||
Parameters
|
||||
@@ -453,6 +496,10 @@ def ellipse_perimeter(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t yradius,
|
||||
Minor and major semi-axes. ``(x/xradius)**2 + (y/yradius)**2 = 1``.
|
||||
orientation : double, optional (default 0)
|
||||
Major axis orientation in clockwise direction as radians.
|
||||
shape : tuple, optional
|
||||
Image shape which is used to determine maximum extents of output pixel
|
||||
coordinates. This is useful for ellipses which exceed the image size.
|
||||
By default the full extents of the polygon are used.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -574,6 +621,9 @@ def ellipse_perimeter(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t yradius,
|
||||
py.extend(rr)
|
||||
px.extend(cc)
|
||||
|
||||
if shape is not None:
|
||||
return _coords_inside_image(np.array(py, dtype=np.intp),
|
||||
np.array(px, dtype=np.intp), shape)
|
||||
return np.array(py, dtype=np.intp), np.array(px, dtype=np.intp)
|
||||
|
||||
|
||||
@@ -708,7 +758,7 @@ def _bezier_segment(Py_ssize_t y0, Py_ssize_t x0,
|
||||
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):
|
||||
double weight, shape=None):
|
||||
"""Generate Bezier curve coordinates.
|
||||
|
||||
Parameters
|
||||
@@ -721,6 +771,10 @@ def bezier_curve(Py_ssize_t y0, Py_ssize_t x0,
|
||||
Coordinates of the last control point.
|
||||
weight : double
|
||||
Middle control point weight, it describes the line tension.
|
||||
shape : tuple, optional
|
||||
Image shape which is used to determine maximum extents of output pixel
|
||||
coordinates. This is useful for curves which exceed the image size.
|
||||
By default the full extents of the polygon are used.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -833,4 +887,8 @@ def bezier_curve(Py_ssize_t y0, Py_ssize_t x0,
|
||||
rr, cc = _bezier_segment(y0, x0, y1, x1, y2, x2, weight * weight)
|
||||
px.extend(rr)
|
||||
py.extend(cc)
|
||||
|
||||
if shape is not None:
|
||||
return _coords_inside_image(np.array(px, dtype=np.intp),
|
||||
np.array(py, dtype=np.intp), shape)
|
||||
return np.array(px, dtype=np.intp), np.array(py, dtype=np.intp)
|
||||
|
||||
@@ -234,6 +234,17 @@ def test_circle_perimeter_bresenham():
|
||||
assert_array_equal(img, img_)
|
||||
|
||||
|
||||
def test_circle_perimeter_bresenham_shape():
|
||||
img = np.zeros((15, 20), 'uint8')
|
||||
rr, cc = circle_perimeter(7, 10, 9, method='bresenham', shape=(15, 20))
|
||||
img[rr, cc] = 1
|
||||
shift = 5
|
||||
img_ = np.zeros((15 + 2 * shift, 20), 'uint8')
|
||||
rr, cc = circle_perimeter(7 + shift, 10, 9, method='bresenham', shape=None)
|
||||
img_[rr, cc] = 1
|
||||
assert_array_equal(img, img_[shift:-shift, :])
|
||||
|
||||
|
||||
def test_circle_perimeter_andres():
|
||||
img = np.zeros((15, 15), 'uint8')
|
||||
rr, cc = circle_perimeter(7, 7, 0, method='andres')
|
||||
@@ -298,6 +309,16 @@ def test_circle_perimeter_aa():
|
||||
assert_array_equal(img, img_)
|
||||
|
||||
|
||||
def test_circle_perimeter_aa_shape():
|
||||
img = np.zeros((15, 20), 'uint8')
|
||||
rr, cc, val = circle_perimeter_aa(7, 10, 9, shape=(15, 20))
|
||||
img[rr, cc] = val * 255
|
||||
shift = 5
|
||||
img_ = np.zeros((15 + 2 * shift, 20), 'uint8')
|
||||
rr, cc, val = circle_perimeter_aa(7 + shift, 10, 9, shape=None)
|
||||
img_[rr, cc] = val * 255
|
||||
assert_array_equal(img, img_[shift:-shift, :])
|
||||
|
||||
def test_ellipse_trivial():
|
||||
img = np.zeros((2, 2), 'uint8')
|
||||
rr, cc = ellipse(0.5, 0.5, 0.5, 0.5)
|
||||
@@ -580,6 +601,17 @@ def test_ellipse_perimeter_nzeroangle():
|
||||
assert_array_equal(img, img_)
|
||||
|
||||
|
||||
def test_ellipse_perimeter_shape():
|
||||
img = np.zeros((15, 20), 'uint8')
|
||||
rr, cc = ellipse_perimeter(7, 10, 9, 9, 0, shape=(15, 20))
|
||||
img[rr, cc] = 1
|
||||
shift = 5
|
||||
img_ = np.zeros((15 + 2 * shift, 20), 'uint8')
|
||||
rr, cc = ellipse_perimeter(7 + shift, 10, 9, 9, 0, shape=None)
|
||||
img_[rr, cc] = 1
|
||||
assert_array_equal(img, img_[shift:-shift, :])
|
||||
|
||||
|
||||
def test_bezier_segment_straight():
|
||||
image = np.zeros((200, 200), dtype=int)
|
||||
x0 = 50
|
||||
@@ -726,6 +758,24 @@ def test_bezier_curved_weight_neq_1():
|
||||
)
|
||||
assert_equal(img, img_)
|
||||
|
||||
|
||||
def test_bezier_curve_shape():
|
||||
img = np.zeros((15, 20), 'uint8')
|
||||
x1, y1 = (1, 5)
|
||||
x2, y2 = (6, 11)
|
||||
x3, y3 = (1, 14)
|
||||
rr, cc = bezier_curve(x1, y1, x2, y2, x3, y3, 2, shape=(15, 20))
|
||||
img[rr, cc] = 1
|
||||
shift = 5
|
||||
img_ = np.zeros((15 + 2 * shift, 20), 'uint8')
|
||||
x1, y1 = (1 + shift, 5)
|
||||
x2, y2 = (6 + shift, 11)
|
||||
x3, y3 = (1 + shift, 14)
|
||||
rr, cc = bezier_curve(x1, y1, x2, y2, x3, y3, 2, shape=None)
|
||||
img_[rr, cc] = 1
|
||||
assert_array_equal(img, img_[shift:-shift, :])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from numpy.testing import run_module_suite
|
||||
run_module_suite()
|
||||
|
||||
Reference in New Issue
Block a user