如何计算两个点序列之间的“差异”?

时间:2011-06-20 21:55:51

标签: math numerical-methods edit-distance

我有两个长度为n和m的序列。每个都是形式(x,y)的一系列点,并表示图像中的曲线。我需要找到不同(或类似)这些序列给出的事实

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

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

  3. 感谢。

5 个答案:

答案 0 :(得分:3)

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

此方法不会旋转不变。如果您需要一个旋转不变的方法,您应该查看以边界为中心的极坐标编码。我找不到这方面的免费参考,但是如果你需要我来形容它,请告诉我。

答案 1 :(得分:2)

这些方法可能有效:

对于两个序列:

在序列中拟合曲线。确保从[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))也跟踪曲线))。

答案 2 :(得分:1)

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

答案 3 :(得分:1)

步骤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类似于路径的“直径”,也许是路径中任意两点之间的最大欧几里德距离。

答案 4 :(得分:0)

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