Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
B
Base Worker
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Workers
Base Worker
Commits
a2ef1d92
Commit
a2ef1d92
authored
2 years ago
by
ml bonhomme
Committed by
Bastien Abadie
2 years ago
Browse files
Options
Downloads
Patches
Plain Diff
add helper to trim polygons so that they fit inside their image
parent
e557fdf1
No related branches found
Branches containing commit
No related tags found
Tags containing commit
1 merge request
!159
add helper to trim polygons so that they fit inside their image
Pipeline
#79140
passed
2 years ago
Stage: release
Changes
2
Pipelines
8
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
arkindex_worker/image.py
+46
-0
46 additions, 0 deletions
arkindex_worker/image.py
tests/test_image.py
+211
-1
211 additions, 1 deletion
tests/test_image.py
with
257 additions
and
1 deletion
arkindex_worker/image.py
+
46
−
0
View file @
a2ef1d92
...
...
@@ -181,3 +181,49 @@ def download_tiles(url):
)
return
full_image
def
trim_polygon
(
polygon
,
image_width
:
int
,
image_height
:
int
):
"""
This method takes as input:
- a polygon: a list or tuple of points
- image_width, image_height: an image
'
s dimensions
and outputs a new polygon, whose points are all located within the image.
If some of the polygon
'
s points are not inside the image, the polygon gets trimmed,
which means that some points can disappear or their coordinates be modified.
"""
assert
isinstance
(
polygon
,
(
list
,
tuple
)
),
"
Input polygon must be a valid list or tuple of points.
"
assert
all
(
isinstance
(
point
,
(
list
,
tuple
))
for
point
in
polygon
),
"
Polygon points must be tuples or lists.
"
assert
all
(
len
(
point
)
==
2
for
point
in
polygon
),
"
Polygon points must be tuples or lists of 2 elements.
"
assert
all
(
isinstance
(
point
[
0
],
int
)
and
isinstance
(
point
[
1
],
int
)
for
point
in
polygon
),
"
Polygon point coordinates must be integers.
"
assert
any
(
point
[
0
]
<=
image_width
and
point
[
1
]
<=
image_height
for
point
in
polygon
),
"
This polygon is entirely outside the image
'
s bounds.
"
trimmed_polygon
=
[
[
min
(
image_width
,
max
(
0
,
x
)),
min
(
image_height
,
max
(
0
,
y
)),
]
for
x
,
y
in
polygon
]
updated_polygon
=
[]
for
point
in
trimmed_polygon
:
if
point
not
in
updated_polygon
:
updated_polygon
.
append
(
point
)
# Add back the matching last point, if it was present in the original polygon
if
polygon
[
-
1
]
==
polygon
[
0
]:
updated_polygon
.
append
(
updated_polygon
[
0
])
return
updated_polygon
This diff is collapsed.
Click to expand it.
tests/test_image.py
+
211
−
1
View file @
a2ef1d92
# -*- coding: utf-8 -*-
import
math
import
unittest
from
io
import
BytesIO
from
pathlib
import
Path
import
pytest
from
PIL
import
Image
,
ImageChops
,
ImageOps
from
arkindex_worker.image
import
download_tiles
,
open_image
from
arkindex_worker.image
import
download_tiles
,
open_image
,
trim_polygon
FIXTURES
=
Path
(
__file__
).
absolute
().
parent
/
"
data
"
TILE
=
FIXTURES
/
"
test_image.jpg
"
...
...
@@ -14,6 +15,7 @@ FULL_IMAGE = FIXTURES / "tiled_image.jpg"
ROTATED_IMAGE
=
FIXTURES
/
"
rotated_image.jpg
"
MIRRORED_IMAGE
=
FIXTURES
/
"
mirrored_image.jpg
"
ROTATED_MIRRORED_IMAGE
=
FIXTURES
/
"
rotated_mirrored_image.jpg
"
TEST_IMAGE
=
{
"
width
"
:
800
,
"
height
"
:
300
}
def
_root_mean_square
(
img_a
,
img_b
):
...
...
@@ -146,3 +148,211 @@ def test_open_image_rotate_mirror(rotation_angle, mirrored, expected_path):
actual
=
open_image
(
str
(
TILE
),
rotation_angle
=
rotation_angle
,
mirrored
=
mirrored
)
actual
.
save
(
f
"
/tmp/
{
rotation_angle
}
_
{
mirrored
}
.jpg
"
)
assert
_root_mean_square
(
expected
,
actual
)
<=
15.0
class
TestTrimPolygon
(
unittest
.
TestCase
):
def
test_trim_polygon_partially_outside_image
(
self
):
bad_polygon
=
[
[
99
,
200
],
[
197
,
224
],
[
120
,
251
],
[
232
,
350
],
[
312
,
364
],
[
325
,
310
],
[
318
,
295
],
[
296
,
260
],
[
352
,
259
],
[
106
,
210
],
[
197
,
206
],
[
99
,
200
],
]
expected_polygon
=
[
[
99
,
200
],
[
197
,
224
],
[
120
,
251
],
[
232
,
300
],
[
312
,
300
],
[
325
,
300
],
[
318
,
295
],
[
296
,
260
],
[
352
,
259
],
[
106
,
210
],
[
197
,
206
],
[
99
,
200
],
]
assert
(
trim_polygon
(
bad_polygon
,
TEST_IMAGE
[
"
width
"
],
TEST_IMAGE
[
"
height
"
])
==
expected_polygon
)
def
test_trim_polygon_good_polygon
(
self
):
good_polygon
=
(
(
12
,
56
),
(
29
,
60
),
(
35
,
61
),
(
42
,
59
),
(
58
,
57
),
(
65
,
61
),
(
72
,
57
),
(
12
,
56
),
)
expected_polygon
=
[
[
12
,
56
],
[
29
,
60
],
[
35
,
61
],
[
42
,
59
],
[
58
,
57
],
[
65
,
61
],
[
72
,
57
],
[
12
,
56
],
]
assert
(
trim_polygon
(
good_polygon
,
TEST_IMAGE
[
"
width
"
],
TEST_IMAGE
[
"
height
"
])
==
expected_polygon
)
def
test_trim_polygon_invalid_polygon
(
self
):
"""
An assertion error is raised the polygon input isn
'
t a list or tuple
"""
bad_polygon
=
{
"
polygon
"
:
[
[
99
,
200
],
[
25
,
224
],
[
0
,
0
],
[
0
,
300
],
[
102
,
300
],
[
260
,
300
],
[
288
,
295
],
[
296
,
260
],
[
352
,
259
],
[
106
,
210
],
[
197
,
206
],
[
99
,
208
],
]
}
with
self
.
assertRaises
(
AssertionError
,
msg
=
"
Input polygon must be a valid list or tuple of points.
"
):
trim_polygon
(
bad_polygon
,
TEST_IMAGE
[
"
width
"
],
TEST_IMAGE
[
"
height
"
])
def
test_trim_polygon_negative_coordinates
(
self
):
"""
Negative coordinates are ignored and replaced by 0 with no error being thrown
"""
bad_polygon
=
[
[
99
,
200
],
[
25
,
224
],
[
-
8
,
-
52
],
[
-
12
,
350
],
[
102
,
364
],
[
260
,
310
],
[
288
,
295
],
[
296
,
260
],
[
352
,
259
],
[
106
,
210
],
[
197
,
206
],
[
99
,
200
],
]
expected_polygon
=
[
[
99
,
200
],
[
25
,
224
],
[
0
,
0
],
[
0
,
300
],
[
102
,
300
],
[
260
,
300
],
[
288
,
295
],
[
296
,
260
],
[
352
,
259
],
[
106
,
210
],
[
197
,
206
],
[
99
,
200
],
]
assert
(
trim_polygon
(
bad_polygon
,
TEST_IMAGE
[
"
width
"
],
TEST_IMAGE
[
"
height
"
])
==
expected_polygon
)
def
test_trim_polygon_outside_image_error
(
self
):
"""
An assertion error is raised when none of the polygon
'
s points are inside the image
"""
bad_polygon
=
[
[
999
,
200
],
[
1097
,
224
],
[
1020
,
251
],
[
1232
,
350
],
[
1312
,
364
],
[
1325
,
310
],
[
1318
,
295
],
[
1296
,
260
],
[
1352
,
259
],
[
1006
,
210
],
[
997
,
206
],
[
999
,
200
],
]
with
self
.
assertRaises
(
AssertionError
,
msg
=
"
This polygon is entirely outside the image
'
s bounds.
"
):
trim_polygon
(
bad_polygon
,
TEST_IMAGE
[
"
width
"
],
TEST_IMAGE
[
"
height
"
])
def
test_trim_polygon_float_coordinates
(
self
):
"""
An assertion error is raised when point coordinates are not integers
"""
bad_polygon
=
[
[
9.9
,
200
],
[
25
,
224
],
[
0
,
0
],
[
0
,
300
],
[
102
,
300
],
[
260
,
300
],
[
288
,
295
],
[
296
,
260
],
[
352
,
259
],
[
106
,
210
],
[
197
,
206
],
[
99
,
20.8
],
]
with
self
.
assertRaises
(
AssertionError
,
msg
=
"
Polygon point coordinates must be integers.
"
):
trim_polygon
(
bad_polygon
,
TEST_IMAGE
[
"
width
"
],
TEST_IMAGE
[
"
height
"
])
def
test_trim_polygon_invalid_points_1
(
self
):
"""
An assertion error is raised when point coordinates are not lists or tuples
"""
bad_polygon
=
[
[
12
,
56
],
[
29
,
60
],
[
35
,
61
],
"
[42, 59]
"
,
[
58
,
57
],
[
65
,
61
],
[
72
,
57
],
[
12
,
56
],
]
with
self
.
assertRaises
(
AssertionError
,
msg
=
"
Polygon points must be tuples or lists.
"
):
trim_polygon
(
bad_polygon
,
TEST_IMAGE
[
"
width
"
],
TEST_IMAGE
[
"
height
"
])
def
test_trim_polygon_invalid_points_2
(
self
):
"""
An assertion error is raised when point coordinates are not lists or tuples of length 2
"""
bad_polygon
=
[
[
12
,
56
],
[
29
,
60
,
3
],
[
35
,
61
],
[
42
,
59
],
[
58
,
57
],
[
65
,
61
],
[
72
,
57
],
[
12
,
56
],
]
with
self
.
assertRaises
(
AssertionError
,
msg
=
"
Polygon points must be tuples or lists of 2 elements.
"
):
trim_polygon
(
bad_polygon
,
TEST_IMAGE
[
"
width
"
],
TEST_IMAGE
[
"
height
"
])
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment