Skip to content

Commit

Permalink
[Bug fix] box points ordering (#1205)
Browse files Browse the repository at this point in the history
* fix sort_points

* remove functools

* add test cases

* add descriptions for coordinates

* del

Co-authored-by: xinyu <wangxinyu2017@gmail.com>
  • Loading branch information
yjmm10 and xinke-wang committed Oct 12, 2022
1 parent a71889a commit 8905dae
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 28 deletions.
47 changes: 19 additions & 28 deletions mmocr/utils/box_util.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Copyright (c) OpenMMLab. All rights reserved.
import functools
import math
import operator
from functools import reduce

import numpy as np

Expand Down Expand Up @@ -160,8 +162,14 @@ def bezier_to_polygon(bezier_points, num_sample=20):


def sort_points(points):
"""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
Expand All @@ -170,30 +178,13 @@ def sort_points(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))
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)
22 changes: 22 additions & 0 deletions tests/test_utils/test_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,27 @@ def test_sort_points():
points = [[1, 1], [1, -1], [-1, 1], [-1, -1]]
assert 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]]
assert 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]]
assert 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]]
assert 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]]
with pytest.raises(AssertionError):
assert np.allclose(target, sort_points(points))

with pytest.raises(AssertionError):
sort_points([1, 2])

0 comments on commit 8905dae

Please sign in to comment.