draw: Add alpha ability to set_color

This commit is contained in:
Stefan van der Walt
2015-12-14 00:39:01 -08:00
parent b9c951335a
commit e2f874e75f
3 changed files with 73 additions and 15 deletions
+11 -7
View File
@@ -21,20 +21,24 @@ def _coords_inside_image(rr, cc, shape, val=None):
shape : tuple
Image shape which is used to determine the maximum extent of output
pixel coordinates.
val : ndarray of float, optional
Values of pixels at coordinates [rr, cc].
val : (N, D) ndarray of float, optional
Values of pixels at coordinates ``[rr, cc]``.
Returns
-------
rr, cc : (N,) array of int
rr, cc : (M,) array of int
Row and column indices of valid pixels (i.e. those inside `shape`).
val : (N,) array of float, optional
val : (M, D) array of float, optional
Values at `rr, cc`. Returned only if `val` is given as input.
"""
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]
if val is None:
return rr[mask], cc[mask]
else:
if np.isscalar(val):
return rr[mask], cc[mask], val
else:
return rr[mask], cc[mask], val[mask]
def line(Py_ssize_t y0, Py_ssize_t x0, Py_ssize_t y1, Py_ssize_t x1):
+40 -6
View File
@@ -125,7 +125,7 @@ def circle(r, c, radius, shape=None):
return ellipse(r, c, radius, radius, shape)
def set_color(img, coords, color):
def set_color(img, coords, color, alpha=None):
"""Set pixel color in the image at the given coordinates.
Coordinates that exceed the shape of the image will be ignored.
@@ -134,10 +134,13 @@ def set_color(img, coords, color):
----------
img : (M, N, D) ndarray
Image
coords : ((P,) ndarray, (P,) ndarray)
Coordinates of pixels to be colored.
coords : tuple of ((P,) ndarray, (P,) ndarray)
Row and column coordinates of pixels to be colored.
color : (D,) ndarray
Color to be assigned to coordinates in the image.
alpha : scalar or (N,) ndarray
Alpha values used to blend color with image. 0 is transparent,
1 is opaque.
Returns
-------
@@ -163,7 +166,38 @@ def set_color(img, coords, color):
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1]], dtype=uint8)
"""
rr, cc = coords
rr, cc = _coords_inside_image(rr, cc, img.shape)
img[rr, cc] = color
if alpha is None:
rr, cc = _coords_inside_image(rr, cc, img.shape)
else:
rr, cc, alpha = _coords_inside_image(rr, cc, img.shape, val=alpha)
if not np.isscalar(color):
color = np.array(color)
if color.shape[0] != img.shape[-1]:
raise ValueError('Color shape ({}) must match last '
'image dimension ({}).'.format(color.shape[0],
img.shape[-1]))
if alpha is None:
img[rr, cc] = color
else:
if np.isscalar(alpha) or np.isscalar(color):
color = color * alpha
else:
color = color * alpha[:, None]
# Strategy: try operation directly. If scalar / correctly shaped
# vector, this will work. If not (e.g. vector alpha but color image),
# try broadcasting.
try:
vals = img[rr, cc] * (1 - alpha)
except ValueError:
vals = img[rr, cc] * (1 - alpha[:, None])
try:
img[rr, cc] = vals + color
except ValueError:
img[rr, cc] = vals + color[:, None]
+22 -2
View File
@@ -1,4 +1,4 @@
from numpy.testing import assert_array_equal, assert_equal
from numpy.testing import assert_array_equal, assert_equal, assert_raises
import numpy as np
from skimage._shared.testing import test_parallel
@@ -20,6 +20,24 @@ def test_set_color():
assert_array_equal(img, img_)
def test_set_color_with_alpha():
img = np.zeros((10, 10))
rr, cc, alpha = line_aa(0, 0, 0, 30)
set_color(img, (rr, cc), 1, alpha=alpha)
# Wrong dimensionality color
assert_raises(ValueError, set_color, img, (rr, cc), (255, 0, 0), alpha=alpha)
img = np.zeros((10, 10, 3))
rr, cc, alpha = line_aa(0, 0, 0, 30)
set_color(img, (rr, cc), 1, alpha=alpha)
rr, cc, alpha = line_aa(0, 0, 0, 30)
set_color(img, (rr, cc), (1, 0, 0), alpha=alpha)
@test_parallel()
def test_line_horizontal():
img = np.zeros((10, 10))
@@ -72,7 +90,7 @@ def test_line_aa_horizontal():
img = np.zeros((10, 10))
rr, cc, val = line_aa(0, 0, 0, 9)
img[rr, cc] = val
set_color(img, (rr, cc), 1, alpha=val)
img_ = np.zeros((10, 10))
img_[0, :] = 1
@@ -329,12 +347,14 @@ 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)