Skip to content

Commit

Permalink
utils: moved filter_polygons upwards: from coco.py to shapely.py
Browse files Browse the repository at this point in the history
  • Loading branch information
sergiev committed Jul 18, 2024
1 parent d2b558e commit be2b459
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 24 deletions.
21 changes: 0 additions & 21 deletions sahi/utils/coco.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,28 +224,7 @@ def __init__(
self._shapely_annotation = shapely_annotation

def get_sliced_coco_annotation(self, slice_bbox: List[int]):
def filter_polygons(geometry):
"""
Filters out and returns only Polygon or MultiPolygon components of a geometry.
If geometry is a Polygon, it converts it into a MultiPolygon.
If it's a GeometryCollection, it filters to create a MultiPolygon from any Polygons in the collection.
Returns an empty MultiPolygon if no Polygon or MultiPolygon components are found.
"""
if isinstance(geometry, Polygon):
return MultiPolygon([geometry])
elif isinstance(geometry, MultiPolygon):
return geometry
elif isinstance(geometry, GeometryCollection):
polygons = [geom for geom in geometry.geoms if isinstance(geom, Polygon)]
return MultiPolygon(polygons) if polygons else MultiPolygon()
return MultiPolygon()

shapely_polygon = box(slice_bbox[0], slice_bbox[1], slice_bbox[2], slice_bbox[3])
samp = self._shapely_annotation.multipolygon
if not samp.is_valid:
valid = make_valid(samp)
valid = filter_polygons(valid)
self._shapely_annotation.multipolygon = valid
intersection_shapely_annotation = self._shapely_annotation.get_intersection(shapely_polygon)
return CocoAnnotation.from_shapely_annotation(
intersection_shapely_annotation,
Expand Down
26 changes: 23 additions & 3 deletions sahi/utils/shapely.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

from typing import List

from shapely.geometry import CAP_STYLE, JOIN_STYLE, MultiPolygon, Polygon, box
from shapely.geometry import CAP_STYLE, JOIN_STYLE, GeometryCollection, MultiPolygon, Polygon, box
from shapely.validation import make_valid


def get_shapely_box(x: int, y: int, width: int, height: int) -> Polygon:
Expand All @@ -21,15 +22,34 @@ def get_shapely_box(x: int, y: int, width: int, height: int) -> Polygon:

def get_shapely_multipolygon(coco_segmentation: List[List]) -> MultiPolygon:
"""
Accepts coco style polygon coords and converts it to shapely multipolygon object
Accepts coco style polygon coords and converts it to valid shapely multipolygon object
"""
def filter_polygons(geometry):
"""
Filters out and returns only Polygon or MultiPolygon components of a geometry.
If geometry is a Polygon, it converts it into a MultiPolygon.
If it's a GeometryCollection, it filters to create a MultiPolygon from any Polygons in the collection.
Returns an empty MultiPolygon if no Polygon or MultiPolygon components are found.
"""
if isinstance(geometry, Polygon):
return MultiPolygon([geometry])
elif isinstance(geometry, MultiPolygon):
return geometry
elif isinstance(geometry, GeometryCollection):
polygons = [geom for geom in geometry.geoms if isinstance(geom, Polygon)]
return MultiPolygon(polygons) if polygons else MultiPolygon()
return MultiPolygon()

polygon_list = []
for coco_polygon in coco_segmentation:
point_list = list(zip(coco_polygon[0::2], coco_polygon[1::2]))
shapely_polygon = Polygon(point_list)
polygon_list.append(shapely_polygon)
shapely_multipolygon = MultiPolygon(polygon_list)


if not shapely_multipolygon.is_valid:
shapely_multipolygon = filter_polygons(make_valid(shapely_multipolygon))

return shapely_multipolygon


Expand Down
6 changes: 6 additions & 0 deletions tests/test_shapelyutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ def test_get_shapely_multipolygon(self):
self.assertEqual(shapely_multipolygon.area, 41177.5)
self.assertTupleEqual(shapely_multipolygon.bounds, (1, 1, 325, 200))

def test_get_shapely_multipolygon_naughty(self):
# self-intersection case
coco_segmentation = [[3559.0, 2046.86, 3.49, 2060.0, 3540.9, 3249.7, 2060.0, 3239.61, 2052.87]]
shapely_multipolygon = get_shapely_multipolygon(coco_segmentation)
self.assertTrue(shapely_multipolygon.is_valid)

def test_shapely_annotation(self):
# init shapely_annotation from coco segmentation
segmentation = [[1, 1, 325, 125.2, 250, 200, 5, 200]]
Expand Down

0 comments on commit be2b459

Please sign in to comment.