mirror of https://github.com/open-mmlab/mmocr.git
* [Bug fix] box points ordering (#1205) * fix sort_points * remove functools * add test cases * add descriptions for coordinates * del Co-authored-by: xinyu <wangxinyu2017@gmail.com> * fix --------- Co-authored-by: liferecords <yjmm10@yeah.net> Co-authored-by: xinyu <wangxinyu2017@gmail.com>pull/1781/head
parent
75c06d34bb
commit
e9b23c56ad
|
@ -1,11 +1,10 @@
|
|||
# Copyright (c) OpenMMLab. All rights reserved.
|
||||
import functools
|
||||
from typing import List, Tuple
|
||||
|
||||
import numpy as np
|
||||
from shapely.geometry import LineString, Point
|
||||
|
||||
from mmocr.utils.check_argument import is_2dlist, is_type_list
|
||||
from mmocr.utils.check_argument import is_type_list
|
||||
from mmocr.utils.point_utils import point_distance, points_center
|
||||
from mmocr.utils.typing_utils import ArrayLike
|
||||
|
||||
|
@ -248,47 +247,6 @@ def bezier2polygon(bezier_points: np.ndarray,
|
|||
return points.tolist()
|
||||
|
||||
|
||||
def sort_points(points):
|
||||
# TODO Add typehints & test & docstring
|
||||
"""Sort arbitory points in clockwise order. Reference:
|
||||
https://stackoverflow.com/a/6989383.
|
||||
|
||||
Args:
|
||||
points (list[ndarray] or ndarray or list[list]): A list of unsorted
|
||||
boundary points.
|
||||
|
||||
Returns:
|
||||
list[ndarray]: A list of points sorted in clockwise order.
|
||||
"""
|
||||
|
||||
assert is_type_list(points, np.ndarray) or isinstance(points, np.ndarray) \
|
||||
or is_2dlist(points)
|
||||
|
||||
points = np.array(points)
|
||||
center = np.mean(points, axis=0)
|
||||
|
||||
def cmp(a, b):
|
||||
oa = a - center
|
||||
ob = b - center
|
||||
|
||||
# Some corner cases
|
||||
if oa[0] >= 0 and ob[0] < 0:
|
||||
return 1
|
||||
if oa[0] < 0 and ob[0] >= 0:
|
||||
return -1
|
||||
|
||||
prod = np.cross(oa, ob)
|
||||
if prod > 0:
|
||||
return 1
|
||||
if prod < 0:
|
||||
return -1
|
||||
|
||||
# a, b are on the same line from the center
|
||||
return 1 if (oa**2).sum() < (ob**2).sum() else -1
|
||||
|
||||
return sorted(points, key=functools.cmp_to_key(cmp))
|
||||
|
||||
|
||||
def sort_vertex(points_x, points_y):
|
||||
# TODO Add typehints & docstring & test
|
||||
"""Sort box vertices in clockwise order from left-top first.
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# Copyright (c) OpenMMLab. All rights reserved.
|
||||
import functools
|
||||
import math
|
||||
import operator
|
||||
from functools import reduce
|
||||
from typing import List, Optional, Sequence, Tuple, Union
|
||||
|
||||
import numpy as np
|
||||
|
@ -374,8 +376,14 @@ def boundary_iou(src: List,
|
|||
|
||||
def sort_points(points):
|
||||
# TODO Add typehints & test & docstring
|
||||
"""Sort arbitory points in clockwise order. Reference:
|
||||
https://stackoverflow.com/a/6989383.
|
||||
"""Sort arbitrary points in clockwise order in Cartesian coordinate, you
|
||||
may need to reverse the output sequence if you are using OpenCV's image
|
||||
coordinate.
|
||||
|
||||
Reference:
|
||||
https://github.com/novioleo/Savior/blob/master/Utils/GeometryUtils.py.
|
||||
|
||||
Warning: This function can only sort convex polygons.
|
||||
|
||||
Args:
|
||||
points (list[ndarray] or ndarray or list[list]): A list of unsorted
|
||||
|
@ -384,33 +392,16 @@ def sort_points(points):
|
|||
Returns:
|
||||
list[ndarray]: A list of points sorted in clockwise order.
|
||||
"""
|
||||
|
||||
assert is_list_of(points, np.ndarray) or isinstance(points, np.ndarray) \
|
||||
or is_2dlist(points)
|
||||
|
||||
points = np.array(points)
|
||||
center = np.mean(points, axis=0)
|
||||
|
||||
def cmp(a, b):
|
||||
oa = a - center
|
||||
ob = b - center
|
||||
|
||||
# Some corner cases
|
||||
if oa[0] >= 0 and ob[0] < 0:
|
||||
return 1
|
||||
if oa[0] < 0 and ob[0] >= 0:
|
||||
return -1
|
||||
|
||||
prod = np.cross(oa, ob)
|
||||
if prod > 0:
|
||||
return 1
|
||||
if prod < 0:
|
||||
return -1
|
||||
|
||||
# a, b are on the same line from the center
|
||||
return 1 if (oa**2).sum() < (ob**2).sum() else -1
|
||||
|
||||
return sorted(points, key=functools.cmp_to_key(cmp))
|
||||
center_point = tuple(
|
||||
map(operator.truediv,
|
||||
reduce(lambda x, y: map(operator.add, x, y), points),
|
||||
[len(points)] * 2))
|
||||
return sorted(
|
||||
points,
|
||||
key=lambda coord: (180 + math.degrees(
|
||||
math.atan2(*tuple(map(operator.sub, coord, center_point))))) % 360)
|
||||
|
||||
|
||||
def sort_vertex(points_x, points_y):
|
||||
|
|
|
@ -343,6 +343,27 @@ class TestPolygonUtils(unittest.TestCase):
|
|||
points = [[1, 1], [1, -1], [-1, 1], [-1, -1]]
|
||||
self.assertTrue(np.allclose(target, sort_points(points)))
|
||||
|
||||
points = [[0.5, 0.3], [1, 0.5], [-0.5, 0.8], [-0.1, 1]]
|
||||
target = [[-0.5, 0.8], [-0.1, 1], [1, 0.5], [0.5, 0.3]]
|
||||
self.assertTrue(np.allclose(target, sort_points(points)))
|
||||
|
||||
points = [[0.5, 3], [0.1, -0.2], [-0.5, -0.3], [-0.7, 3.1]]
|
||||
target = [[-0.5, -0.3], [-0.7, 3.1], [0.5, 3], [0.1, -0.2]]
|
||||
self.assertTrue(np.allclose(target, sort_points(points)))
|
||||
|
||||
points = [[1, 0.8], [0.8, -1], [1.8, 0.5], [1.9, -0.6], [-0.5, 2],
|
||||
[-1, 1.8], [-2, 0.7], [-1.6, -0.2], [-1, -0.5]]
|
||||
target = [[-1, -0.5], [-1.6, -0.2], [-2, 0.7], [-1, 1.8], [-0.5, 2],
|
||||
[1, 0.8], [1.8, 0.5], [1.9, -0.6], [0.8, -1]]
|
||||
self.assertTrue(np.allclose(target, sort_points(points)))
|
||||
|
||||
# concave polygon may failed
|
||||
points = [[1, 0], [-1, 0], [0, 0], [0, -1], [0.25, 1], [0.75, 1],
|
||||
[-0.25, 1], [-0.75, 1]]
|
||||
target = [[-1, 0], [-0.75, 1], [-0.25, 1], [0, 0], [0.25, 1],
|
||||
[0.75, 1], [1, 0], [0, -1]]
|
||||
self.assertFalse(np.allclose(target, sort_points(points)))
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
sort_points([1, 2])
|
||||
|
||||
|
|
Loading…
Reference in New Issue