Skip to content

Commit e9b23c5

Browse files
gaotongxiaoyjmm10xinke-wang
authored
Cherry Pick #1205 (#1774)
* [Bug fix] box points ordering (#1205) * fix sort_points * remove functools * add test cases * add descriptions for coordinates * del Co-authored-by: xinyu <[email protected]> * fix --------- Co-authored-by: liferecords <[email protected]> Co-authored-by: xinyu <[email protected]>
1 parent 75c06d3 commit e9b23c5

File tree

3 files changed

+41
-71
lines changed

3 files changed

+41
-71
lines changed

mmocr/utils/bbox_utils.py

Lines changed: 1 addition & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
# Copyright (c) OpenMMLab. All rights reserved.
2-
import functools
32
from typing import List, Tuple
43

54
import numpy as np
65
from shapely.geometry import LineString, Point
76

8-
from mmocr.utils.check_argument import is_2dlist, is_type_list
7+
from mmocr.utils.check_argument import is_type_list
98
from mmocr.utils.point_utils import point_distance, points_center
109
from mmocr.utils.typing_utils import ArrayLike
1110

@@ -248,47 +247,6 @@ def bezier2polygon(bezier_points: np.ndarray,
248247
return points.tolist()
249248

250249

251-
def sort_points(points):
252-
# TODO Add typehints & test & docstring
253-
"""Sort arbitory points in clockwise order. Reference:
254-
https://stackoverflow.com/a/6989383.
255-
256-
Args:
257-
points (list[ndarray] or ndarray or list[list]): A list of unsorted
258-
boundary points.
259-
260-
Returns:
261-
list[ndarray]: A list of points sorted in clockwise order.
262-
"""
263-
264-
assert is_type_list(points, np.ndarray) or isinstance(points, np.ndarray) \
265-
or is_2dlist(points)
266-
267-
points = np.array(points)
268-
center = np.mean(points, axis=0)
269-
270-
def cmp(a, b):
271-
oa = a - center
272-
ob = b - center
273-
274-
# Some corner cases
275-
if oa[0] >= 0 and ob[0] < 0:
276-
return 1
277-
if oa[0] < 0 and ob[0] >= 0:
278-
return -1
279-
280-
prod = np.cross(oa, ob)
281-
if prod > 0:
282-
return 1
283-
if prod < 0:
284-
return -1
285-
286-
# a, b are on the same line from the center
287-
return 1 if (oa**2).sum() < (ob**2).sum() else -1
288-
289-
return sorted(points, key=functools.cmp_to_key(cmp))
290-
291-
292250
def sort_vertex(points_x, points_y):
293251
# TODO Add typehints & docstring & test
294252
"""Sort box vertices in clockwise order from left-top first.

mmocr/utils/polygon_utils.py

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Copyright (c) OpenMMLab. All rights reserved.
2-
import functools
2+
import math
3+
import operator
4+
from functools import reduce
35
from typing import List, Optional, Sequence, Tuple, Union
46

57
import numpy as np
@@ -374,8 +376,14 @@ def boundary_iou(src: List,
374376

375377
def sort_points(points):
376378
# TODO Add typehints & test & docstring
377-
"""Sort arbitory points in clockwise order. Reference:
378-
https://stackoverflow.com/a/6989383.
379+
"""Sort arbitrary points in clockwise order in Cartesian coordinate, you
380+
may need to reverse the output sequence if you are using OpenCV's image
381+
coordinate.
382+
383+
Reference:
384+
https://github.com/novioleo/Savior/blob/master/Utils/GeometryUtils.py.
385+
386+
Warning: This function can only sort convex polygons.
379387
380388
Args:
381389
points (list[ndarray] or ndarray or list[list]): A list of unsorted
@@ -384,33 +392,16 @@ def sort_points(points):
384392
Returns:
385393
list[ndarray]: A list of points sorted in clockwise order.
386394
"""
387-
388395
assert is_list_of(points, np.ndarray) or isinstance(points, np.ndarray) \
389396
or is_2dlist(points)
390-
391-
points = np.array(points)
392-
center = np.mean(points, axis=0)
393-
394-
def cmp(a, b):
395-
oa = a - center
396-
ob = b - center
397-
398-
# Some corner cases
399-
if oa[0] >= 0 and ob[0] < 0:
400-
return 1
401-
if oa[0] < 0 and ob[0] >= 0:
402-
return -1
403-
404-
prod = np.cross(oa, ob)
405-
if prod > 0:
406-
return 1
407-
if prod < 0:
408-
return -1
409-
410-
# a, b are on the same line from the center
411-
return 1 if (oa**2).sum() < (ob**2).sum() else -1
412-
413-
return sorted(points, key=functools.cmp_to_key(cmp))
397+
center_point = tuple(
398+
map(operator.truediv,
399+
reduce(lambda x, y: map(operator.add, x, y), points),
400+
[len(points)] * 2))
401+
return sorted(
402+
points,
403+
key=lambda coord: (180 + math.degrees(
404+
math.atan2(*tuple(map(operator.sub, coord, center_point))))) % 360)
414405

415406

416407
def sort_vertex(points_x, points_y):

tests/test_utils/test_polygon_utils.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,27 @@ def test_sort_points(self):
343343
points = [[1, 1], [1, -1], [-1, 1], [-1, -1]]
344344
self.assertTrue(np.allclose(target, sort_points(points)))
345345

346+
points = [[0.5, 0.3], [1, 0.5], [-0.5, 0.8], [-0.1, 1]]
347+
target = [[-0.5, 0.8], [-0.1, 1], [1, 0.5], [0.5, 0.3]]
348+
self.assertTrue(np.allclose(target, sort_points(points)))
349+
350+
points = [[0.5, 3], [0.1, -0.2], [-0.5, -0.3], [-0.7, 3.1]]
351+
target = [[-0.5, -0.3], [-0.7, 3.1], [0.5, 3], [0.1, -0.2]]
352+
self.assertTrue(np.allclose(target, sort_points(points)))
353+
354+
points = [[1, 0.8], [0.8, -1], [1.8, 0.5], [1.9, -0.6], [-0.5, 2],
355+
[-1, 1.8], [-2, 0.7], [-1.6, -0.2], [-1, -0.5]]
356+
target = [[-1, -0.5], [-1.6, -0.2], [-2, 0.7], [-1, 1.8], [-0.5, 2],
357+
[1, 0.8], [1.8, 0.5], [1.9, -0.6], [0.8, -1]]
358+
self.assertTrue(np.allclose(target, sort_points(points)))
359+
360+
# concave polygon may failed
361+
points = [[1, 0], [-1, 0], [0, 0], [0, -1], [0.25, 1], [0.75, 1],
362+
[-0.25, 1], [-0.75, 1]]
363+
target = [[-1, 0], [-0.75, 1], [-0.25, 1], [0, 0], [0.25, 1],
364+
[0.75, 1], [1, 0], [0, -1]]
365+
self.assertFalse(np.allclose(target, sort_points(points)))
366+
346367
with self.assertRaises(AssertionError):
347368
sort_points([1, 2])
348369

0 commit comments

Comments
 (0)