我很难找到比较两条轨迹(曲线)的方法。
第一个原始包含点(x,y)。
第二个可以是偏移,更小或更大的比例,并与旋转-也与点阵列(x,y)
我做的第一个方法是找到两点之间的最小距离,并在每次迭代中重复此过程,求和并除以点数-然后我的结果告诉我每个点的平均误差值:
http://www.mathopenref.com/coorddist.html
我发现这个方法:
https://help.scilab.org/docs/6.0.0/en_US/fminsearch.html
但我不知道怎么用。
我想比较两个轨迹,但我的结果必须包括旋转,或至少偏移开始。
我现在的结果是计算每个点的误差(距离)
得到坐标(x,y)第二轨迹。
在循环中,我试图找到(x,y)与1之间的最小距离。从原始轨迹开始。
加上我在两步中找到的最小距离。
将最小距离之和除以第二条轨迹的点数。
我的结果描述了平均误差(距离)每点,如果我们比较原始轨迹。
但我不知道如何处理轨迹是旋转、缩放还是移动。
请看我的示例轨迹:
http://pokazywarka.pl/trajectory/
http://pokazywarka.pl/trajectory2/

最佳答案

所以需要比较两条曲线在旋转、平移和缩放上的形状不变。
解决方案
假设2个正弦波用于测试。旋转和缩放但具有相同长宽比和添加噪波的长宽比我用C++生成它们,像这样:

struct _pnt2D
    {
    double x,y;
    // inline
    _pnt2D()    {}
    _pnt2D(_pnt2D& a)   { *this=a; }
    ~_pnt2D()   {}
    _pnt2D* operator = (const _pnt2D *a) { *this=*a; return this; }
    //_pnt2D* operator = (const _pnt2D &a) { ...copy... return this; }
    };
List<_pnt2D> curve0,curve1;         // curves points
_pnt2D p0,u0,v0,p1,u1,v1;           // curves OBBs

const double deg=M_PI/180.0;
const double rad=180.0/M_PI;
void rotate2D(double alfa,double x0,double y0,double &x,double &y)
    {
    double   a=x-x0,b=y-y0,c,s;
    c=cos(alfa);
    s=sin(alfa);
    x=x0+a*c-b*s;
    y=y0+a*s+b*c;
    }

// this code is the init stuff:
int i;
double x,y,a;
_pnt2D p,*pp;
Randomize();
for (x=0;x<2.0*M_PI;x+=0.01)
    {
    y=sin(x);

    p.x= 50.0+(100.0*x);
    p.y=180.0-( 50.0*y);
    rotate2D(+15.0*deg,200,180,p.x,p.y);
    curve0.add(p);

    p.x=150.0+( 50.0*x);
    p.y=200.0-( 25.0*y)+5.0*Random();
    rotate2D(-25.0*deg,250,100,p.x,p.y);
    curve1.add(p);
    }

面向对象的边界框
计算OBB这将找到两条曲线的旋转角度和位置,因此旋转其中一条曲线,使它们从同一位置开始并具有相同的方向。
如果obb的大小太不同,那么曲线就不同。
对于上面的例子,它可以得出这样的结果:
java - 如何比较两条曲线(点阵列)-LMLPHP
每个OBB由起始点P和基向量U,V定义,其中|U|>=|V|U x V的z坐标为正这将确保所有OBB的绕组相同可以在OBBox_compute中通过将此添加到末尾来完成:
// |U|>=|V|
if ((u.x*u.x)+(u.y*u.y)<(v.x*v.x)+(v.y*v.y)) { _pnt2D p; p=u; u=v; v=p; }
// (U x V).z > 0
if ((u.x*v.y)-(u.y*v.x)<0.0)
    {
    p0.x+=v.x;
    p0.y+=v.y;
    v.x=-v.x;
    v.y=-v.y;
    }

所以curve0p0,u0,v0curve1p1,u1,v1
现在我们要重新缩放、平移和旋转curve1以匹配curve0可以这样做:
// compute OBB
OBBox_compute(p0,u0,v0,curve0.dat,curve0.num);
OBBox_compute(p1,u1,v1,curve1.dat,curve1.num);
// difference angle = - acos((U0.U1)/(|U0|.|U1|))
a=-acos(((u0.x*u1.x)+(u0.y*u1.y))/(sqrt((u0.x*u0.x)+(u0.y*u0.y))*sqrt((u1.x*u1.x)+(u1.y*u1.y))));
// rotate curve1
for (pp=curve1.dat,i=0;i<curve1.num;i++,pp++)
 rotate2D(a,p1.x,p1.y,pp->x,pp->y);
// rotate OBB1
rotate2D(a,0.0,0.0,u1.x,u1.y);
rotate2D(a,0.0,0.0,v1.x,v1.y);
// translation difference = P0-P1
x=p0.x-p1.x;
y=p0.y-p1.y;
// translate curve1
for (pp=curve1.dat,i=0;i<curve1.num;i++,pp++)
    {
    pp->x+=x;
    pp->y+=y;
    }
// translate OBB1
p1.x+=x;
p1.y+=y;
// scale difference = |P0|/|P1|
x=sqrt((u0.x*u0.x)+(u0.y*u0.y))/sqrt((u1.x*u1.x)+(u1.y*u1.y));
// scale curve1
for (pp=curve1.dat,i=0;i<curve1.num;i++,pp++)
    {
    pp->x=((pp->x-p0.x)*x)+p0.x;
    pp->y=((pp->y-p0.y)*x)+p0.y;
    }
// scale OBB1
u1.x*=x;
u1.y*=x;
v1.x*=x;
v1.y*=x;

您可以使用Understanding 4x4 homogenous transform matrices一步完成所有这一切。结果如下:
java - 如何比较两条曲线(点阵列)-LMLPHP
抽样
如果曲线之间或曲线的任何部分之间的点密度不一致或非常不同,则应重新采样曲线以获得公共点密度。可以使用线性或多项式插值您也不需要将新的采样存储在内存中,而是可以构建一个函数,该函数返回从一开始就由弧长参数化的每条曲线的点。
point curve0(double distance);
point curve1(double distance);

比较
现在,您可以对这两条曲线进行减法运算,并求出差异的绝对值。然后将其除以曲线长度并对结果设置阈值。
for (double sum=0.0,l=0.0;d<=bigger_curve_length;l+=step)
 sum+=fabs(curve0(l)-curve1(l));
sum/=bigger_curve_length;
if (sum>threshold) curves are different
 else curves match

你应该尝试这甚至与+180度的旋转,因为方向的差异,从obb只有一半的真实范围。
这里有几个相关的QA:
compare shapes
How can i produce multi point linear interpolation?

10-06 13:40
查看更多