在python中对xy坐标列表进行排序

时间:2016-08-24 08:38:44

标签: python sorting coordinates shortest-path

我有一长串的xy坐标,如下所示:

>>> data = [(x1,y1),(x2,y2),(x3,y3),...]

每对坐标代表图像中轮廓的一个点,我想对它们进行排序,就好像它们沿着轮廓(最短路径)排列一样。轮廓的形状非常复杂(它是一个国家的形状),这就是ConvexHull的原因。  不会工作。

我尝试了这段代码,但不够精确:

>>> import math
>>> import matplotlib.patches as patches
>>> import pylab

>>> pp=[(1,1),(2,3),(3,4)]

# compute centroid
>>> cent=(sum([p[0] for p in pp])/len(pp),sum([p[1] for p in pp])/len(pp))
# sort by polar angle
>>> pp.sort(key=lambda p: math.atan2(p[1]-cent[1],p[0]-cent[0]))
# plot points
>>> pylab.scatter([p[0] for p in pp],[p[1] for p in pp])
# plot polyline

>>> pylab.gca().add_patch(patches.Polygon(pp,closed=False,fill=False))
>>> pylab.grid()
>>> pylab.show()

我已尝试过像this case中的建议 但它效果不好,因为我的坐标列表太长了。

由于这些点彼此非常接近this question的解决方案 对我来说可能看起来太复杂了。

This might illustrate my problem

3 个答案:

答案 0 :(得分:0)

如果您的形状为“简单”,则可以计算点云的中心(X和Y的平均值)。按照从中心到点的角度对点进行排序,如果它们中的两个具有相同的角度,则按它们与中心的距离对它们进行排序。这应该可以解决问题。

center = functools.reduce(lambda p1, p2: (p1[0]+p2[0], p1[1]+p2[1]), data)
center = (center[0] / len(data), center[1] / len(data))

def angle(p1, p2):
    return math.atan2(p2[1], p2[0]) - math.atan2(p1[1], p1[0])

answer = sorted(data, key=lambda p: (angle(p, center), distance(p, center)))

对于更复杂的形状,我有另一种算法叫做放气船体。从你的云的船体,你放气,直到它触及所有剩余的点:

def deflate_hull(points):
    hull = convex_hull(points)

    for p in hull:
        points.remove(p)

    while points:
        l = len(hull)
        _, p, i = min((distance(hull[i-1], p) + distance(p, hull[i]) - distance(hull[i-1], hull[i]), p, i) 
                      for p in points 
                      for i in range(l))
        points.remove(p)
        hull = hull[:i] + [p] + hull[i:]

    return hull

def convex_hull(points):
    if len(points) <= 3:
        return points
    upper = half_hull(sorted(points))
    lower = half_hull(reversed(sorted(points)))
    return upper + lower[1:-1]

def half_hull(sorted_points):
    hull = []
    for C in sorted_points:
        while len(hull) >= 2 and turn(hull[-2], hull[-1], C) <= -1e-6: 
            hull.pop()
        hull.append(C)
    return hull

def turn(A, B, C):
    return (B[0]-A[0]) * (C[1]-B[1]) - (B[1]-A[1]) * (C[0]-B[0]) 

def distance(p1, p2):
    return math.sqrt((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2)

answer = deflate_hull(data)

答案 1 :(得分:0)

您描述的问题类似于寻找凸包。你可以看看here

答案 2 :(得分:0)

更新: 同时我通过使用OpenCV的findContours解决了它 - 它输出了像我一样的坐标!