在python中对xy坐标列表进行排序
我有一个很长的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 >>>
>>> 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形状,如果点分布很好,这也适用于星形形状-但是如果分布不好,找到正确的中心就不那么简单了简单的代码不起作用,因为形状太复杂,第二个建议的点太多,所以速度太慢。凸包算法不会考虑“内部”点。看来他想要所有的。