9

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

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

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

谢谢。

4

5 回答 5

3

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

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

于 2011-06-21T04:12:34.450 回答
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)) 也跟踪曲线))。

于 2011-06-21T13:11:54.617 回答
1

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

于 2011-06-21T03:35:49.987 回答
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 类似于路径的“直径”,可能是路径中任意两点之间的最大欧几里得距离。

于 2011-06-22T01:03:02.697 回答
0

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

于 2011-06-21T21:26:33.387 回答