Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在python中对xy坐标列表进行排序_Python_Sorting_Coordinates_Shortest Path - Fatal编程技术网

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

在python中对xy坐标列表进行排序,python,sorting,coordinates,shortest-path,Python,Sorting,Coordinates,Shortest Path,我有一个很长的xy坐标列表,如下所示: >>> data = [(x1,y1),(x2,y2),(x3,y3),...] 每对坐标表示图像中轮廓的一个点,我想对它们进行排序,就像它们沿着轮廓排列一样(最短路径)。轮廓的形状非常复杂(它是一个国家的形状),这就是为什么 不行 我试过这个代码,但不够精确: >>> import math >>> import matplotlib.patches as patches >>>

我有一个很长的xy坐标列表,如下所示:

>>> data = [(x1,y1),(x2,y2),(x3,y3),...]
每对坐标表示图像中轮廓的一个点,我想对它们进行排序,就像它们沿着轮廓排列一样(最短路径)。轮廓的形状非常复杂(它是一个国家的形状),这就是为什么 不行

我试过这个代码,但不够精确:

>>> 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()
我已经试过了 但结果不太好,因为我的坐标列表太长了

由于这些点彼此非常接近,因此 对我来说可能太复杂了


如果您的形状是“简单”的,例如,您可以计算点云的中心(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)
def deflate_外壳(点):
外壳=凸面外壳(点)
对于船体中的p:
点。删除(p)
而要点:
l=长度(船体)
_,p,i=min((距离(外壳[i-1],p)+距离(外壳[i])-距离(外壳[i-1],外壳[i]),p,i)
对于p点
对于范围(l)中的i)
点。删除(p)
外壳=外壳[:i]+[p]+外壳[i:]
返回船体
def凸面外壳(点):

如果len(points)=2并转弯(hull[-2],hull[-1],C)您描述的问题类似于查找凸壳。您可以查看一下

您可以通过选择一个随机点并从中找到下一个点,如

def distance(a,b):
    pass
    #propably something with math.hypot for euclidean norm

points=set([(1,2),(2,3)])
current=points.pop()
path=[current]
while points:
    current=min(points,key=(lambda p: distance(current,p))
    points.remove(current)
    path.append(current)
这不是一个快速算法(关于O(n*n)),但它很简单

您可以通过使用kd树来加快搜索速度-最简单的情况是二叉树/仅沿其中一个轴进行二叉搜索-但是构建树/首先对点进行排序实际上并不快

如果您的计数几乎是凸的,@Cabu的解是最快的。

更新:
同时,我通过使用OpenCV的findContours解决了这个问题——它像我吹口哨一样输出坐标

你所描述的任务叫做旅行推销员的问题,一般来说很难解决。如果你能给我们看一些样品图片和相同的样品数据,也许有人会注意到一个模式,它允许我们提出一个有效的算法。由于它是一个计数,通常可以假设每个点有两个最近的邻居-路径上的前一个和后一个-并且最短路径也只包括这样的对。所以你可以使用一个运行时间为O(n*n)或更好的贪婪算法。你能再解释一下为什么“这个问题对我来说可能太复杂了”吗?你试过他的解决方案了吗?问题是什么?至少对图片基本正确这完全适用于konvex形状,如果点分布很好,这也适用于星形形状-但是如果分布不好,找到正确的中心就不那么简单了简单的代码不起作用,因为形状太复杂,第二个建议的点太多,所以速度太慢。凸包算法不会考虑“内部”点。看来他想要所有的。