Skip to content
Snippets Groups Projects
Commit 94358166 authored by Yoann Schneider's avatar Yoann Schneider :tennis: Committed by Bastien Abadie
Browse files

Correct rotation code

parent aa989681
No related branches found
No related tags found
1 merge request!203Correct rotation code
Pipeline #79521 passed with warnings
......@@ -270,7 +270,7 @@ def trim_polygon(polygon, image_width: int, image_height: int):
return updated_polygon
def revert_orientation(element, polygon):
def revert_orientation(element, polygon, reverse: bool = False):
"""
Update the coordinates of the polygon of a child element based on the orientation of
its parent.
......@@ -278,10 +278,15 @@ def revert_orientation(element, polygon):
This method should be called before sending any polygon to Arkindex, to undo the possible
orientation applied by :meth:`Element.open_image`.
In some cases, we want to apply the parent's orientation on the child's polygon instead. This is done
by enabling `reverse=True`.
:param element: Parent element.
:type element: Element or CachedElement
:param polygon: Polygon corresponding to the child element.
:type polygon: list(list(int or float))
:param mode: Whether we should revert (`revert`) or apply (`apply`) the parent's orientation.
:type mode: str
:return: A polygon with updated coordinates.
:rtype: list(list(int))
"""
......@@ -294,6 +299,7 @@ def revert_orientation(element, polygon):
assert polygon and isinstance(
polygon, list
), "polygon shouldn't be null and should be a list"
assert isinstance(reverse, bool), "Reverse should be a bool"
# Rotating with Pillow can cause it to move the image around, as the image cannot have negative coordinates
# and must be a rectangle. This means the origin point of any coordinates from an image is invalid, and the
# center of the bounding box of the rotated image is different from the center of the element's bounding box.
......@@ -322,13 +328,24 @@ def revert_orientation(element, polygon):
ring = LinearRing(polygon)
# First undo the negative coordinates offset, since this is the last step of the original rotation
ring = translate(ring, xoff=offset_x, yoff=offset_y)
if element.rotation_angle:
ring = rotate(ring, -element.rotation_angle, origin=origin)
if element.mirrored:
ring = scale(ring, xfact=-1, origin=origin)
if reverse:
# Apply the parent's orientation on the child's polygon
# Apply mirroring
if element.mirrored:
ring = scale(ring, xfact=-1, origin=origin)
# Apply rotation
if element.rotation_angle:
ring = rotate(ring, element.rotation_angle, origin=origin)
# At last translate coordinates offset
ring = translate(ring, xoff=-offset_x, yoff=-offset_y)
else:
# First undo the negative coordinates offset, since this is the last step of the original transformation
ring = translate(ring, xoff=offset_x, yoff=offset_y)
# Revert any rotation
if element.rotation_angle:
ring = rotate(ring, -element.rotation_angle, origin=origin)
# Revert any mirroring
if element.mirrored:
ring = scale(ring, xfact=-1, origin=origin)
return [[int(x), int(y)] for x, y in ring.coords]
......@@ -10,8 +10,10 @@ from PIL import Image, ImageChops, ImageOps
from arkindex_worker.cache import CachedElement, create_tables, init_cache_db
from arkindex_worker.image import (
BoundingBox,
download_tiles,
open_image,
polygon_bounding_box,
revert_orientation,
trim_polygon,
)
......@@ -367,66 +369,114 @@ class TestTrimPolygon(unittest.TestCase):
@pytest.mark.parametrize(
"current_polygon,angle,mirrored,original_polygon",
"angle, mirrored, updated_bounds, reverse",
(
(
[[73, 40], [1013, 40], [1013, 178], [73, 178]],
0,
False,
[[73, 40], [1013, 40], [1013, 178], [73, 178], [73, 40]],
{"x": 295, "y": 11, "width": 111, "height": 47}, # upper right
True,
),
(
90,
False,
{"x": 510, "y": 295, "width": 47, "height": 111}, # lower right
True,
),
(
180,
False,
{"x": 9, "y": 510, "width": 111, "height": 47}, # lower left
True,
),
(
270,
False,
{"x": 11, "y": 9, "width": 47, "height": 111}, # upper left
True,
),
(
0,
True,
{"x": 9, "y": 11, "width": 111, "height": 47}, # upper left
True,
),
(
90,
True,
{"x": 510, "y": 9, "width": 47, "height": 111}, # upper right
True,
),
(
180,
True,
{"x": 295, "y": 510, "width": 111, "height": 47}, # lower right
True,
),
(
270,
True,
{"x": 11, "y": 295, "width": 47, "height": 111}, # lower left
True,
),
(
0,
False,
{"x": 295, "y": 11, "width": 111, "height": 47}, # upper right
False,
),
(
[[502, 73], [588, 73], [588, 1013], [502, 1013]],
90,
False,
[[73, 126], [73, 40], [1013, 40], [1013, 126], [73, 126]],
{"x": 11, "y": 162, "width": 47, "height": 111}, # upper left
False,
),
(
[[254, 205], [540, 205], [540, 327], [254, 327]],
180,
False,
[[785, 423], [499, 423], [499, 301], [785, 301], [785, 423]],
{"x": 9, "y": 510, "width": 111, "height": 47}, # lower left
False,
),
(
[[301, 139], [423, 139], [423, 540], [301, 540]],
270,
False,
[[900, 301], [900, 423], [499, 423], [499, 301], [900, 301]],
{"x": 357, "y": 295, "width": 47, "height": 111}, # lower right
False,
),
(
[[26, 40], [966, 40], [966, 191], [26, 191]],
0,
True,
[[1013, 40], [73, 40], [73, 191], [1013, 191], [1013, 40]],
{"x": 9, "y": 11, "width": 111, "height": 47}, # upper left
False,
),
(
[[502, 26], [588, 26], [588, 966], [502, 966]],
90,
True,
[[1013, 126], [1013, 40], [73, 40], [73, 126], [1013, 126]],
{"x": 357, "y": 162, "width": 47, "height": 111}, # lower left
False,
),
(
[[486, 89], [900, 89], [900, 311], [486, 311]],
180,
True,
[[486, 539], [900, 539], [900, 317], [486, 317], [486, 539]],
{"x": 295, "y": 510, "width": 111, "height": 47}, # lower right
False,
),
(
[[317, 486], [539, 486], [539, 900], [317, 900]],
270,
True,
[[486, 317], [486, 539], [900, 539], [900, 317], [486, 317]],
{"x": 11, "y": 295, "width": 47, "height": 111}, # upper right
False,
),
),
)
def test_revert_orientation(
current_polygon, angle, mirrored, original_polygon, tmp_path
):
def test_revert_orientation(angle, mirrored, updated_bounds, reverse, tmp_path):
"""Test cases, for both Elements and CachedElements:
- no rotation or orientation
- rotation with 3 different angles (90, 180, 270)
- rotation + mirror with 4 angles (0, 90, 180, 270)
"""
child_polygon = [[295, 11], [295, 58], [406, 58], [406, 11], [295, 11]]
# Setup cache db to test with CachedElements
db_path = f"{tmp_path}/db.sqlite"
init_cache_db(db_path)
......@@ -434,9 +484,9 @@ def test_revert_orientation(
image_polygon = [
[0, 0],
[0, 628],
[1039, 628],
[1039, 0],
[0, 568],
[415, 568],
[415, 0],
[0, 0],
]
element = Element(
......@@ -454,5 +504,10 @@ def test_revert_orientation(
rotation_angle=angle,
)
assert revert_orientation(element, current_polygon) == original_polygon
assert revert_orientation(cached_element, current_polygon) == original_polygon
assert polygon_bounding_box(
revert_orientation(element, child_polygon, reverse=reverse)
) == BoundingBox(**updated_bounds)
assert polygon_bounding_box(
revert_orientation(cached_element, child_polygon, reverse=reverse)
) == BoundingBox(**updated_bounds)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment