【问题标题】:How do I calculate the "difference" between two sequences of points?如何计算两个点序列之间的“差异”?
【发布时间】:2011-09-19 01:40:22
【问题描述】:

我有两个长度为 n 和 m 的序列。每个点都是 (x,y) 形式的点序列,表示图像中的曲线。我需要找出这些序列有多么不同(或相似),因为

  1. 一个序列可能比另一个长(即,一个序列可能是另一个序列的一半或四分之一,但如果它们追踪大致相同的曲线,它们是相同的)
  2. 这些序列可能是相反的方向(即序列 1 从左到右,而序列 2 从右到左)

    我研究了一些差异估计,例如 Levenshtein 以及蛋白质折叠的结构相似性匹配中的编辑距离,但它们似乎都没有奏效。我可以编写自己的蛮力方法,但我想知道是否有更好的方法。

谢谢。

【问题讨论】:

  • 您能否更具体地说明您想要从编辑距离中得到什么?您是否试图在序列上提出某种度量空间?你只是想对比赛进行排名吗?或者您只是在寻找相似度的主观衡量标准?
  • @templatetypedef - 我真正想做的是将序列(路线)分类。我希望通过计算相似性或差异值并使用预定义的阈值将该序列分配给一个组来做到这一点。
  • 当你说一个序列比另一个序列短时,你的意思是它只遵循另一条曲线的一部分,还是它遵循同一条曲线但点更少?
  • @Beta - 有可能两者兼而有之。这些序列是穿越空间的对象的位置,并且传入的数据容易出错 - 它可能从中间开始(仅曲线的一部分),也可能缺少信息(点较少)。
  • 还有更多关于曲线的信息吗?例如,它们可以自相交吗? Catmull-Rom 能在多大程度上逼近曲线?等等...

标签: math numerical-methods edit-distance


【解决方案1】:

为什么不做一些曲线拟合程序(最小二乘,无论是普通的还是非线性的),看看形状参数的系数是否相同。如果您将其作为面板数据类型的模型运行,则有明确的统计测试参数集是否彼此显着不同。这将解决相同曲线但以不同分辨率采样的问题。

【讨论】:

  • 这可行。但是,它不应该是平移不变的,因为曲线上点的绝对位置很重要。这也可能吗?
【解决方案2】:

您的意思是您要匹配在 x,y 坐标中平移的曲线?图像处理中的一种技术是使用链码 [我正在寻找一个不错的参考,但我现在只能找到this] 对每个序列进行编码,然后比较这些链码。您可以取差值之和(模 8),如果结果为 0,则曲线相同。由于序列具有不同的长度并且不一定从相同的相对位置开始,因此您必须移动一个序列并一次又一次地执行此操作,但您只需创建一次链码。检测其中一个序列是否反转的唯一方法是尝试其中一个序列的正向和反向。如果曲线不完全相同,总和将大于零,但不能简单地判断曲线与总和之间的差异。

这种方法不会是旋转不变的。如果您需要一种旋转不变的方法,您应该查看 Boundary-Centered Polar Encoding。我找不到免费的参考资料,但如果您需要我描述它,请告诉我。

【讨论】:

  • 了解一条曲线与另一条曲线的不同很重要,因为这就是我对曲线进行分类的方式,尽管看起来总和会给我一个粗略的想法,如果曲线类足够不同。此外,曲线的绝对坐标不仅重要的是它们的空间性(两条看起来相同但位于图像不同部分的曲线是不同的),而且从我的阅读来看,链码似乎是平移不变的?如果是这样,那就无济于事了。
【解决方案3】:

这样的方法可能会奏效:

对于两个序列:

通过序列拟合曲线。确保从 [0,1] 到此曲线上的点具有连续的一对一函数。也就是说,对于 0 到 1 之间的每个(实数)数字,此函数返回属于它的曲线上的一个点。通过跟踪从 0 到 1 的所有数字的函数,可以得到整条曲线。

拟合曲线的一种方法是在每对连续点之间画一条直线(这不是一条很好的曲线,因为它有急剧的弯曲,但它可能适合您的目的)。在这种情况下,可以通过计算所有线段的总长度来获得函数(毕达哥拉斯)。曲线上对应于数字 Y(介于 0 和 1 之间)的点对应于曲线上与序列上第一个点的距离为 Y *(所有线段的总长度)的点,通过在线段(!!)。

现在,在我们得到第一个序列的函数 F(double) 和第二个序列的 G(double) 之后,我们可以计算相似度如下:

double epsilon = 0.01;
double curveDistanceSquared = 0.0;
for(double d=0.0;d<1.0;d=d+epsilon)
{
   Point pointOnCurve1 = F(d);    
   Point pointOnCurve2 = G(d); 
   //alternatively, use G(1.0-d) to check whether the second sequence is reversed       
   double distanceOfPoints = pointOnCurve1.EuclideanDistance(pointOnCurve2);
   curveDistanceSquared = curveDistanceSquared + distanceOfPoints * distanceOfPoints;
}
similarity = 1.0/ curveDistanceSquared;

可能的改进:

-找到一种改进的方法来拟合曲线。请注意,您仍然需要跟踪曲线的函数才能使上述方法起作用。

-在计算距离时,考虑重新参数化函数 G,使距离最小。 (这意味着您有一个递增函数 R,使得 R(0) = 0 且 R(1)=1, 但这是一般的。在计算你使用的距离时

   Point pointOnCurve1 = F(d);    
   Point pointOnCurve2 = G(R(d)); 

随后,您尝试以最小化距离的方式选择 R。 (要查看会发生什么,请注意 G(R(d)) 也跟踪曲线))。

【讨论】:

  • 谢谢,我认为这行得通。我要做的唯一区别是将较大曲线的大小限制为较小的曲线,并且应该注意一条曲线是另一条曲线的子序列的情况。我会尝试并报告回来。这种技术有名字吗?它看起来类似于蛋白质折叠中的SSAP
  • 从你的问题,我知道两条曲线在二维空间中测量的长度相同,但是两条曲线的点数不同?现在我明白了曲线的长度可以不同,点的数量也可以不同。您可以以与我对重新参数化的评论类似的方式来适应这种情况。我不知道这种技术的名称..
【解决方案4】:

我会使用曲线拟合程序,但也会加入一个常数项,即 0 =B0 + B1*X + B2*Y + B3*X*Y + B4*X^ 2等。这将捕获平移方差,然后您可以对两组点形成的曲线的估计系数进行统计比较,作为对它们进行分类的一种方式。我假设如果数据在 x-y 平面上形成任意曲线,您将不得不进行双变量插值。

【讨论】:

    【解决方案5】:

    第 1 步:规范化方向。例如,假设所有曲线都从字典顺序最低的端点开始。

    def inCanonicalOrientation(path):
        return path if path[0]<path[-1] else reversed(path)
    

    第 2 步:您可以大致准确,也可以非常准确。如果您希望非常准确,请计算样条曲线,或将两条曲线拟合到适当次数的多项式,然后比较系数。如果您只想粗略估计,请执行以下操作:

    def resample(path, numPoints)
        pathLength = pathLength(path)  #write this function
    
        segments = generateSegments(path)
        currentSegment = next(segments)
        segmentsSoFar = [currentSegment]
    
        for i in range(numPoints):
            samplePosition = i/(numPoints-1)*pathLength
            while samplePosition > pathLength(segmentsSoFar)+currentSegment.length:
                currentSegment = next(segments)
                segmentsSoFar.insert(currentSegment)
            difference = samplePosition - pathLength(segmentsSoFar)
            howFar = difference/currentSegment.length
            yield Point((1-howFar)*currentSegment.start + (howFar)*currentSegment.end)
    

    这可以从线性重采样修改为更好的东西。

    def error(pathA, pathB):
        pathA = inCanonicalOrientation(pathA)
        pathB = inCanonicalOrientation(pathB)
    
        higherResolution = max([len(pathA), len(pathB)])
        resampledA = resample(pathA, higherResolution)
        resampledB = resample(pathA, higherResolution)
    
        error = sum(
            abs(pointInA-pointInB)
            for pointInA,pointInB in zip(pathA,pathB)
        )
        averageError = error / len(pathAorB)
        normalizedError = error / Z(AorB)
        return normalizedError
    

    其中 Z 类似于路径的“直径”,可能是路径中任意两点之间的最大欧几里得距离。

    【讨论】:

    • 感谢您的详细回复。自从我使用其他人发布的算法以来,我一直没有机会检查它,但是当我有时间时,我也会尝试你的。
    • @WanderingPhd:这个答案与接受的答案基本相同,勾勒出如何使用线段(可以修改为使用样条线)。
    猜你喜欢
    • 1970-01-01
    • 2010-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-21
    • 2010-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多