Fixed ellipse symmetry and added some tests.

This commit is contained in:
Alexey Umnov
2014-09-17 19:13:36 +04:00
parent b67d46ab91
commit abcd613593
2 changed files with 166 additions and 34 deletions
+27 -13
View File
@@ -7,6 +7,15 @@ def _coords_inside_image(rr, cc, shape):
return rr[mask], cc[mask]
def _ellipse_in_shape(shape, center, radiuses):
"""Generate coordinates of points within ellipse bounded by shape."""
y, x = np.ogrid[0:shape[0], 0:shape[1]]
cy, cx = center
ry, rx = radiuses
distances = ((y - cy) / ry) ** 2 + ((x - cx) / rx) ** 2
return np.nonzero(distances < 1)
def ellipse(cy, cx, yradius, xradius, shape=None):
"""Generate coordinates of pixels within ellipse.
@@ -48,21 +57,26 @@ def ellipse(cy, cx, yradius, xradius, shape=None):
"""
dr = 1 / float(yradius)
dc = 1 / float(xradius)
r, c = np.ogrid[-1:1:dr, -1:1:dc]
rr, cc = np.nonzero(r ** 2 + c ** 2 < 1)
rr.flags.writeable = True
cc.flags.writeable = True
rr += cy - yradius
cc += cx - xradius
center = np.array([cy, cx])
radiuses = np.array([yradius, xradius])
if shape is not None:
return _coords_inside_image(rr, cc, shape)
return _ellipse_in_shape(shape, center, radiuses)
else:
# rounding here is necessary to avoid rounding issues later
upper_left = np.floor(center - radiuses)
return rr, cc
shifted_center = center - upper_left
# Shifted center is in interval [radiuses, radiuses + 1], so
# the ellipse must fit in [0, 2*radiuses + 1].
bounding_shape = np.ceil(2 * radiuses + 1)
rr, cc = _ellipse_in_shape(bounding_shape, shifted_center, radiuses)
rr.flags.writeable = True
cc.flags.writeable = True
rr += upper_left[0]
cc += upper_left[1]
return rr, cc
def circle(cy, cx, radius, shape=None):
+139 -21
View File
@@ -298,30 +298,134 @@ def test_circle_perimeter_aa():
assert_array_equal(img, img_)
def test_ellipse():
img = np.zeros((15, 15), 'uint8')
def test_ellipse_trivial():
img = np.zeros((2, 2), 'uint8')
rr, cc = ellipse(0.5, 0.5, 0.5, 0.5)
img[rr, cc] = 1
img_correct = np.array([
[0, 0],
[0, 0]
])
assert_array_equal(img, img_correct)
img = np.zeros((2, 2), 'uint8')
rr, cc = ellipse(0.5, 0.5, 1.1, 1.1)
img[rr, cc] = 1
img_correct = np.array([
[1, 1],
[1, 1],
])
assert_array_equal(img, img_correct)
img = np.zeros((3, 3), 'uint8')
rr, cc = ellipse(1, 1, 0.9, 0.9)
img[rr, cc] = 1
img_correct = np.array([
[0, 0, 0],
[0, 1, 0],
[0, 0, 0],
])
assert_array_equal(img, img_correct)
img = np.zeros((3, 3), 'uint8')
rr, cc = ellipse(1, 1, 1.1, 1.1)
img[rr, cc] = 1
img_correct = np.array([
[0, 1, 0],
[1, 1, 1],
[0, 1, 0],
])
assert_array_equal(img, img_correct)
img = np.zeros((3, 3), 'uint8')
rr, cc = ellipse(1, 1, 1.5, 1.5)
img[rr, cc] = 1
img_correct = np.array([
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
])
assert_array_equal(img, img_correct)
def test_ellipse_generic():
img = np.zeros((4, 4), 'uint8')
rr, cc = ellipse(1.5, 1.5, 1.1, 1.7)
img[rr, cc] = 1
img_ = np.array([
[0, 0, 0, 0],
[1, 1, 1, 1],
[1, 1, 1, 1],
[0, 0, 0, 0],
])
assert_array_equal(img, img_)
img = np.zeros((5, 5), 'uint8')
rr, cc = ellipse(2, 2, 1.7, 1.7)
img[rr, cc] = 1
img_ = np.array([
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 0],
])
assert_array_equal(img, img_)
img = np.zeros((10, 10), 'uint8')
rr, cc = ellipse(5, 5, 3, 4)
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, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 0, 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],
])
assert_array_equal(img, img_)
img = np.zeros((10, 10), 'uint8')
rr, cc = ellipse(4.5, 5, 3.5, 4)
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, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 0, 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],
])
assert_array_equal(img, img_)
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]]
)
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_)
@@ -352,6 +456,20 @@ def test_ellipse_with_shape():
assert_array_equal(img, img_)
def test_ellipse_negative():
rr, cc = ellipse(-3, -3, 1.7, 1.7)
rr_, cc_ = np.nonzero(np.array([
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 0],
]))
assert_array_equal(rr, rr_ - 5)
assert_array_equal(cc, cc_ - 5)
def test_ellipse_perimeter_dot_zeroangle():
# dot, angle == 0
img = np.zeros((30, 15), 'uint8')