如何比较两条曲线(点数组)

时间:2011-07-17 10:15:40

标签: math

我有2个点(x,y)阵列,我可以绘制2条曲线。

任何人都有想法如何计算这些曲线的相似之处?

4 个答案:

答案 0 :(得分:16)

您始终可以计算这两条曲线之间的区域。 (如果端点匹配,这会更容易一些。)如果面积很小,曲线是相似的,如果面积不小,则曲线不相似。

请注意,我没有定义'小'。那是故意的。然后,你没有定义'相似'。

修改
有时区域不是最佳指标。例如,考虑函数f(x)= 0和f(x)= 1e6 * sin(x)。如果x的范围是2 * pi的某个整数倍,则这些曲线之间的面积为零。在正负一百万之间振荡的函数不是f(x)= 0的良好近似值。

需要更好的衡量标准。这是一对夫妇。注意:我在这里假设两组中的x值相同;唯一不同的是y值。

  1. 平方和。对于每个x值,计算delta_y i = y 1,i - y 2,i 并累积delta_y i 2 。该度量是最小二乘优化的基础,其目标是最小化误差平方和。这是一种广泛使用的方法,因为它通常很容易实现。

  2. 最大偏差。找到abs_delta_y i = | y 1,i - y 2,i |最大化| y 1,i - y 2,i |对于所有x值。该度量标准是数学库中许多函数实现的基础,其目标是最小化最大错误。这些数学库实现是真实函数的近似值。作为这种近似的消费者,我通常更关心近似对我的应用程序做的最糟糕的事情,而不是关心这种近似将如何平均表现。

答案 1 :(得分:4)

您可能需要考虑使用动态时间扭曲(DTW)或 Frechet距离

动态时间扭曲

动态时间扭曲对整个曲线中的差异求和。它可以处理两个不同大小的数组。以下是Wikipedia关于代码外观的代码段。该解决方案使用二维阵列。费用是两点之间的距离。数组DTW [n,m]的最终值包含累积距离。

int DTWDistance(s: array [1..n], t: array [1..m]) {
    DTW := array [0..n, 0..m]

    for i := 1 to n
        DTW[i, 0] := infinity
    for i := 1 to m
        DTW[0, i] := infinity
    DTW[0, 0] := 0

    for i := 1 to n
        for j := 1 to m
            cost:= d(s[i], t[j])
            DTW[i, j] := cost + minimum(DTW[i-1, j  ],    // insertion
                                        DTW[i  , j-1],    // deletion
                                        DTW[i-1, j-1])    // match

    return DTW[n, m]
}

DTW与Jacopson的答案相似。

Frechet Distance

Frechet distance计算曲线分开的最远距离。这意味着曲线上的所有其他点都比这个距离更近。这种方法通常用狗和所有者表示,如下所示: Frechet Distance Example

根据您的阵列,您可以比较点的距离并使用最大值。

答案 2 :(得分:3)

我假设曲线是实数上的2D点数组,数组的大小是N,所以我称p[i]为曲线的i点; i0转到N-1

我还假设两条曲线具有相同的大小,并且将第一条曲线的i点与第二条曲线的i点进行“比较”是有意义的。

我将Delta称为实数,即两条曲线的比较结果。

Delta可按如下方式计算:

Delta = 0;
for( i = 0; i < N; i++ ) {
   Delta = Delta + distance(p[i],q[i]);
}

其中p是第一条曲线的点,q是第二条曲线的点。

现在你必须根据你的问题选择合适的distance函数:函数有两个点作为参数并返回一个实数。

例如distance可以是平面上两点的通常距离(毕达哥拉斯定理和http://en.wikipedia.org/wiki/Euclidean_distance)。

C ++中方法的一个例子:

#include <numeric>
#include <vector>
#include <cmath>
#include <iostream>
#include <functional>
#include <stdexcept>

typedef double Real_t;

class Point
{
public:
    Point(){}
    Point(std::initializer_list<Real_t> args):x(args.begin()[0]),y(args.begin()[1]){}
    Point( const Real_t& xx, const Real_t& yy ):x(xx),y(yy){}
    Real_t x,y;
};

typedef std::vector< Point > Curve;

Real_t point_distance( const Point& a, const Point& b )
{
    return hypot(a.x-b.x,a.y-b.y);
}

Real_t curve_distance( const Curve& c1, const Curve& c2 )
{
    if ( c1.size() != c2.size() ) throw std::invalid_argument("size mismatch");
    return std::inner_product( c1.begin(), c1.end(), c2.begin(), Real_t(0), std::plus< Real_t >(), point_distance );
}

int main(int,char**)
{
    Curve c1{{0,0},
             {1,1},
             {2,4},
             {3,9}};

    Curve c2{{0.1,-0.1},
             {1.1,0.9},
             {2.1,3.9},
             {3.1,8.9}};

    std::cout << curve_distance(c1,c2) << "\n";

    return 0;
}

如果你的两条曲线有不同的大小,那么你必须考虑如何扩展前面的方法,例如你可以通过合适的算法减小最长曲线的大小(例如Ramer–Douglas–Peucker algorithm可以是一个起点),以使其与最短曲线的大小相匹配。

我刚刚描述了一种非常简单的方法,你也可以采取不同的方法;例如,您可以将两条曲线拟合到两组点,然后使用表示为数学函数的两条曲线。

答案 3 :(得分:0)

  

这也可以解决,只要考虑分布。

尤其是值的位置在数组中是否可互换。

然后,您可以计算两个阵列的均值和标准差(以及其他分布特征)。然后计算这些特征之间的差异