我有一个表示线 backbone 的(x,y)坐标列表。该列表直接从二进制图像中获得:
import numpy as np
list=np.where(img_skeleton>0)
现在,列表中的点将根据它们在图像中沿着其中一个轴的位置进行排序。
我想对列表进行排序,使其顺序代表沿着直线的平滑路径。(目前,这不是直线向后弯曲的情况)。随后,我想对这些点拟合样条曲线。
一个类似的问题已经被描述并使用arcPy here解决了。是否有一个方便的方法来实现这一点使用python,numpy,scipy,openCV(或其他库?)
下面是一个示例图像。它产生一个59(x,y)坐标的列表。
当我将列表发送到scipy的样条拟合例程时,我遇到了一个问题,因为这些点在直线上没有“排序”:
6条答案
按热度按时间tzcvj98z1#
我为提前给出的冗长答案道歉:P(问题没有那么简单)。
让我们重新表述这个问题。寻找一条连接所有点的线,可以重新表述为图中的最短路径问题,其中(1)图节点是空间中的点,(2)每个节点连接到其2个最近的邻居,和(3)最短路径通过每个节点仅一次。最后一个约束是非常重要的本质上,问题是找到长度为
N
的排列,其中排列指的是路径中每个节点的顺序(N
是节点的总数)。寻找所有可能的排列并评估它们的成本太昂贵了(如果我没猜错的话,有
N!
个排列,这对于问题来说太大了)。下面我提出了一种方法,先找到N
个最佳排列(每个N
点的最佳排列),然后(从这些N
中)找到使错误/成本最小化的排列。1.用无序点创建随机问题
现在,让我们开始创建一个示例问题:
而在这里,未排序版本的点
[x, y]
模拟了一个随机点在空间中连接成一条线:然后问题是对这些点进行排序以恢复它们的原始顺序,从而正确地绘制线。
2.在节点之间创建2-NN图
我们可以先重新排列
[N, 2]
数组中的点:然后,我们可以从创建一个最近邻图开始,将每个节点连接到它的2个最近邻:
G
是稀疏的N x N
矩阵,其中每行表示一个节点,并且列的非零元素表示到那些点的欧几里得距离。然后,我们可以使用
networkx
从该稀疏矩阵构造图:3.查找从源到目标的最短路径
这里开始 * 魔术 *:我们可以使用dfs_preorder_nodes来提取路径,在给定开始节点(如果没有给定,则选择0节点)的情况下,这将实质上创建通过所有节点的路径(通过它们中的每一个恰好一次)。
这是因为无序列表中的点
0
位于直线的中间,也就是说,它首先是向一个方向运动,然后返回,并在另一个方向结束。4.从所有源中查找开销最小的路径
因此,为了获得最优顺序,我们可以仅获得所有节点的最优顺序:
现在我们已经有了从每个
N = 100
节点开始的最优路径,我们可以丢弃它们,并找到使连接之间的距离最小化的路径(优化问题):为每条最优路径的点排序,然后计算成本(通过计算所有点对
i
和i+1
之间的欧几里德距离)。如果路径开始于start
或end
点,则其将具有最小成本,因为所有节点将是连续的。另一方面,如果路径起始于位于线中间的节点,则在某个点的成本将非常高,因为它需要从线的结束(或开始)行进到初始位置以探索另一个方向。使成本最小化的路径是起始于最佳点的路径。现在,我们可以适当地重构这个顺序:
q8l4jmvw2#
一个可能的解决方案是使用最近邻方法,可能是使用KDTree。Scikit-learn有一个很好的界面。然后可以使用networkx来构建一个图形表示。只有当要绘制的线应该经过最近邻时,这才真正起作用:
更新:如果起点和终点未知,并且数据已合理地分开,则可以通过在图形中查找团来找到终点。起点和终点将形成一个团。如果从团中删除最长的边,则将在图形中创建一个自由端,该自由端可用作起点和终点。例如,此列表中的起点和终点显示在中间:
构建完图之后,现在需要从团中删除最长的边,以找到图的自由端:
lqfhib0f3#
我也遇到了同样的问题。如果你有两个数组,其中的x和y值不是太弯曲,那么你可以将这些点转换到PCA空间,在PCA空间中对它们排序,然后再将它们转换回来。(我还添加了一些额外的平滑功能)。
c8ib6hqw4#
我同意Imanol_Luengo Imanol Luengo的解决方案,但是如果您知道第一个点的索引,那么有一个简单得多的解决方案,它只使用NumPy:
此方法似乎适用于正弦曲线示例,尤其是因为很容易将第一个点定义为最左侧或最右侧的点。
对于问题中引用的
img_skeleton
数据,同样容易通过算法获得第一个点,例如作为最高点。jfgube3f5#
我正在研究一个类似的问题,但它有一个重要的约束(很像OP给出的例子),即每个像素都有一个或两个相邻的像素,在8连通的意义上。
svujldwt6#
修改Toddp的答案,你可以找到任意形状的线的端点使用这个代码,然后排序点如Toddp所述,这比Imanol Luengo的答案快得多,唯一的约束是,线必须只有2个端点: