Algorithm 基于特征奇异值分解的两三角形仿射变换逼近

Algorithm 基于特征奇异值分解的两三角形仿射变换逼近,algorithm,cgaffinetransform,Algorithm,Cgaffinetransform,在下面的代码中,我试图实现所提出的仿射变换近似算法 问题是在实现中还是在算法中?如果是,更正是什么?您可以使用以下方法检查您的计算。 以你为例,我明白了 H = 6 -2 -1 -2 2.666666667 -0.666666667 -1 -0.666666667 0.666666667 U = 1 0 0 0 0.957092026 -0.289784149 0 -0.289784149 -0.957092026 V = 1 0 0 0 0

在下面的代码中,我试图实现所提出的仿射变换近似算法


问题是在实现中还是在算法中?如果是,更正是什么?

您可以使用以下方法检查您的计算。 以你为例,我明白了

H =
6   -2  -1
-2  2.666666667 -0.666666667
-1  -0.666666667    0.666666667

U =
1   0   0
0   0.957092026 -0.289784149
0   -0.289784149    -0.957092026

V =
1   0   0
0   0.957092026 -0.289784149
0   -0.289784149    -0.957092026

R =
1 0 0
0 1 0
0 0 1

所以算法是正确的!可能你的H是错误的。

< P>我将尝试推导出java C++程序中的原始程序。基于此,我提出以下建议:

1) 我想你已经在t=c-R*c_条中切换了c和c_条

2) 这篇论文(你可以自由获得)认为共面点不常见,但事实上很有可能,因为这些点的质心被减去了,所以如果你把它们加起来,你就得到了一个零向量。因此,很可能会得到反射,而不是旋转,并且需要切换列符号,如等式(18)和我的Java中所示

    package uk.co.demon.mcdowella.apachemathuser;
/*

Affine transformation approximation of two triangles using Eigen SVD


In the code below, I am trying to implement the algorithm for affine transformation approximation presented here
*/

/*
#include <Eigen/Eigen>
#include <iostream>

using namespace Eigen;
using namespace std;
*/
import org.apache.commons.math.linear.ArrayRealVector;
import java.util.Arrays;
import org.apache.commons.math.linear.Array2DRowRealMatrix;
import org.apache.commons.math.linear.SingularValueDecompositionImpl;
import org.apache.commons.math.linear.RealMatrix;
import org.apache.commons.math.linear.RealVector;

public class FindRotation
{
  /** Utility function to return XY' */
  private static RealMatrix xyt(RealVector x, RealVector y)
  {
    Array2DRowRealMatrix xx = new Array2DRowRealMatrix(x.getData());
    return xx.multiply((
      new Array2DRowRealMatrix(y.getData())).transpose());
  }
  // int main(int argc, char **argv)
  public static void main(String[] s)
  {
    // Vector3f x1 (3.0f, 0.0f, 0.0f);
    ArrayRealVector x1 = new ArrayRealVector(new double[]
      {3.0f, 0.0f, 0.0f});
    // Vector3f x2 (0.0f, 2.0f, 0.0f);
    ArrayRealVector x2 = new ArrayRealVector(new double[]
      {0.0f, 2.0f, 0.0f});
    // Vector3f x3 (0.0f, 0.0f, 1.0f);
    ArrayRealVector x3 = new ArrayRealVector(new double[]
      {0.0f, 0.0f, 1.0f});

    // Vector3f translation(1.0f, -2.0f, 2.0f);
    ArrayRealVector translation = new ArrayRealVector(new double[]
      {1.0f, -2.0f, 2.0f});

    Array2DRowRealMatrix rot;
    if (true)
    { // test - do simple rotation
      rot = new Array2DRowRealMatrix(new double[][] {
        new double[] {1.0, 0.0,  0.0},
        new double[] {0.0, 0.0, -1.0},
        new double[] {0.0, 1.0,  0.0},
      });
      System.out.println("Rot determinant is " + rot.getDeterminant());
    }
    else
    {
      rot = new Array2DRowRealMatrix(new double[][] {
        new double[] {1.0, 0.0, 0.0},
        new double[] {0.0, 1.0, 0.0},
        new double[] {0.0, 0.0, 1.0},
      });
    }

    // Vector3f x_bar1 = x1 + translation;
    RealVector x_bar1 = rot.operate(x1).add(translation);
    // Vector3f x_bar2 = x2 + translation;
    RealVector x_bar2 = rot.operate(x2).add(translation);
    // Vector3f x_bar3 = x3 + translation;
    RealVector x_bar3 = rot.operate(x3).add(translation);

    // std::cerr << "x_bar1 = \n" << x_bar1 << std::endl;
    System.out.println("x_bar1 = ");
    System.out.println(x_bar1);
    // std::cerr << "x_bar2 = \n" << x_bar2 << std::endl;
    System.out.println("x_bar2 = ");
    System.out.println(x_bar2);
    // std::cerr << "x_bar3 = \n" << x_bar3 << std::endl;
    System.out.println("x_bar3 = ");
    System.out.println(x_bar3);

    // Vector3f c     = (x1+x2+x3)/3.0f;
    RealVector c     = x1.add(x2).add(x3).mapDivide(3.0f);

    // Vector3f c_bar = (x_bar1+x_bar2+x_bar3)/3.0f;
    RealVector c_bar     =
      x_bar1.add(x_bar2).add(x_bar3).mapDivide(3.0f);

    // Vector3f y1,y2,y3, y_bar1,y_bar2,y_bar3;
    // y1  = x1 - c;
    RealVector y1  = x1.subtract(c);
    // y2  = x2 - c;
    RealVector y2 = x2.subtract(c);
    // y3  = x3 - c;
    RealVector y3 = x3.subtract(c);
    // y_bar1 = x_bar1 - c_bar;
    RealVector y_bar1 = x_bar1.subtract(c_bar);
    // y_bar2 = x_bar2 - c_bar;
    RealVector y_bar2 = x_bar2.subtract(c_bar);
    // y_bar3 = x_bar3 - c_bar;
    RealVector y_bar3 = x_bar3.subtract(c_bar);

    System.out.println("Y1 " + y1 + " (Q1)");
    System.out.println("Y2 " + y2 + " (Q2)");
    System.out.println("Y3 " + y3 + " (Q3)");
    System.out.println("YB1 " + y_bar1);
    System.out.println("YB2 " + y_bar2);
    System.out.println("YB3 " + y_bar3);

    // Matrix3f H;
    // H =  y1*y_bar1.transpose()+y2*y_bar2.transpose()+y3*y_bar3.transpose();
    RealMatrix h = xyt(y1, y_bar1).add(xyt(y2,y_bar2)).add(
      xyt(y3, y_bar3));

    // JacobiSVD<Matrix3f> svd(H, ComputeFullU | ComputeFullV);
    SingularValueDecompositionImpl svd = 
      new SingularValueDecompositionImpl(h);
    System.out.println("Singular values are " + Arrays.toString(svd.getSingularValues()));
    // Matrix3f R; R = svd.matrixV()*svd.matrixU().transpose();
    RealMatrix r = svd.getV().multiply(svd.getUT());
    double rDeterminant = r.getDeterminant();
    System.out.println("Determinant " + rDeterminant);
    if (rDeterminant < 0.0)
    { // coplanar case - which is not surprising because Q in the original paper sum to 0.0
      // because centroid is subtracted from each of them. Try alternate r
      RealMatrix changeLastColumn = new Array2DRowRealMatrix(new double[][] {
        new double[] {1.0, 0.0, 0.0},
        new double[] {0.0, 1.0, 0.0},
        new double[] {0.0, 0.0, -1.0}});
      RealMatrix vd = svd.getV().multiply(changeLastColumn);
      r = vd.multiply(svd.getUT());
      rDeterminant = r.getDeterminant();
      System.out.println("Determinant at second go is " + rDeterminant);
    }
    // Vector3f t; t = c-R*c_bar;
    // Note - original transpose seems to be the wrong way round
    RealVector t = c_bar.subtract(r.operate(c));

    // std::cerr << "R = \n" << R << std::endl;
    System.out.println("R = ");
    System.out.println(r);
    // std::cerr << "t = \n" << t << std::endl;
    System.out.println("t = ");
    System.out.println(t);

    // Apply supposed answer
    RealVector z1 = r.operate(x1).add(t);   
    RealVector z2 = r.operate(x2).add(t);   
    RealVector z3 = r.operate(x3).add(t);   
    System.out.println("Z1  "+ z1);
    System.out.println("Z2  "+ z2);
    System.out.println("Z3  "+ z3);
  }

/*

But I get wrong answer:

R = 
 0.836735 -0.244898 -0.489796
-0.244898  0.632653 -0.734694
-0.489796 -0.734694 -0.469388
t = 
0.142857
3.71429
1.42857

Is the problem in the implementation or in the algorithm? If so, what is the correction?
*/
}
package uk.co.demon.mcdowella.apachemathuser;
/*
基于特征奇异值分解的两三角形仿射变换逼近
在下面的代码中,我试图实现这里介绍的仿射变换近似算法
*/
/*
#包括
#包括
使用名称空间特征;
使用名称空间std;
*/
导入org.apache.commons.math.linear.ArrayRealVector;
导入java.util.array;
导入org.apache.commons.math.linear.Array2DroArralMatrix;
导入org.apache.commons.math.linear.SingularValueDecompositionImpl;
导入org.apache.commons.math.linear.RealMatrix;
导入org.apache.commons.math.linear.RealVector;
公营货运站
{
/**返回XY'的实用函数*/
私有静态实矩阵xyt(实向量x,实向量y)
{
array2drorearalmatrix xx=新的array2drorearalmatrix(x.getData());
返回xx.multiply((
新的Array2DroRealMatrix(y.getData()).transpose());
}
//int main(int argc,字符**argv)
公共静态void main(字符串[]s)
{
//矢量3f-x1(3.0f,0.0f,0.0f);
ArrayRealVector x1=新的ArrayRealVector(新的双精度[]
{3.0f,0.0f,0.0f});
//向量3f x2(0.0f,2.0f,0.0f);
ArrayRealVector x2=新的ArrayRealVector(新的双精度[]
{0.0f,2.0f,0.0f});
//矢量3f x3(0.0f,0.0f,1.0f);
ArrayRealVector x3=新的ArrayRealVector(新的双精度[]
{0.0f,0.0f,1.0f});
//向量3f平移(1.0f,-2.0f,2.0f);
ArrayRealVector translation=新的ArrayRealVector(新的双精度[]
{1.0f,-2.0f,2.0f});
Array2drowarelmatrix腐病;
如果(真)
{//test-do简单旋转
rot=新阵列2DROREALMATRIX(新双精度[][]{
新的双[]{1.0,0.0,0.0},
新的双[]{0.0,0.0,-1.0},
新的双[]{0.0,1.0,0.0},
});
System.out.println(“Rot行列式为”+Rot.getdeterminate());
}
其他的
{
rot=新阵列2DROREALMATRIX(新双精度[][]{
新的双[]{1.0,0.0,0.0},
新的双[]{0.0,1.0,0.0},
新的双[]{0.0,0.0,1.0},
});
}
//向量3f x_bar1=x1+平移;
实向量x_bar1=rot.operate(x1).add(translation);
//向量3f x_bar2=x2+平移;
RealVector x_bar2=rot.operate(x2).add(translation);
//向量3f x_bar3=x3+平移;
RealVector x_bar3=rot.operate(x3).add(translation);

//cerr我也得到了一个与前面所说的完全相同的恒等式矩阵,但是当我尝试加入一个非恒等式的旋转时,我得到了一个反射而不是旋转在论文和对共面情况的描述中,我猜想在这种情况下,SVD可能会出现旋转或反射,这取决于实现或它选择的运气。谢谢!我将根据您的代码在代码中应用更改,看看我会从中得到什么…顺便说一句!您关于反射的论点离子问题是正确的,我没有考虑。
H =
6   -2  -1
-2  2.666666667 -0.666666667
-1  -0.666666667    0.666666667

U =
1   0   0
0   0.957092026 -0.289784149
0   -0.289784149    -0.957092026

V =
1   0   0
0   0.957092026 -0.289784149
0   -0.289784149    -0.957092026

R =
1 0 0
0 1 0
0 0 1
    package uk.co.demon.mcdowella.apachemathuser;
/*

Affine transformation approximation of two triangles using Eigen SVD


In the code below, I am trying to implement the algorithm for affine transformation approximation presented here
*/

/*
#include <Eigen/Eigen>
#include <iostream>

using namespace Eigen;
using namespace std;
*/
import org.apache.commons.math.linear.ArrayRealVector;
import java.util.Arrays;
import org.apache.commons.math.linear.Array2DRowRealMatrix;
import org.apache.commons.math.linear.SingularValueDecompositionImpl;
import org.apache.commons.math.linear.RealMatrix;
import org.apache.commons.math.linear.RealVector;

public class FindRotation
{
  /** Utility function to return XY' */
  private static RealMatrix xyt(RealVector x, RealVector y)
  {
    Array2DRowRealMatrix xx = new Array2DRowRealMatrix(x.getData());
    return xx.multiply((
      new Array2DRowRealMatrix(y.getData())).transpose());
  }
  // int main(int argc, char **argv)
  public static void main(String[] s)
  {
    // Vector3f x1 (3.0f, 0.0f, 0.0f);
    ArrayRealVector x1 = new ArrayRealVector(new double[]
      {3.0f, 0.0f, 0.0f});
    // Vector3f x2 (0.0f, 2.0f, 0.0f);
    ArrayRealVector x2 = new ArrayRealVector(new double[]
      {0.0f, 2.0f, 0.0f});
    // Vector3f x3 (0.0f, 0.0f, 1.0f);
    ArrayRealVector x3 = new ArrayRealVector(new double[]
      {0.0f, 0.0f, 1.0f});

    // Vector3f translation(1.0f, -2.0f, 2.0f);
    ArrayRealVector translation = new ArrayRealVector(new double[]
      {1.0f, -2.0f, 2.0f});

    Array2DRowRealMatrix rot;
    if (true)
    { // test - do simple rotation
      rot = new Array2DRowRealMatrix(new double[][] {
        new double[] {1.0, 0.0,  0.0},
        new double[] {0.0, 0.0, -1.0},
        new double[] {0.0, 1.0,  0.0},
      });
      System.out.println("Rot determinant is " + rot.getDeterminant());
    }
    else
    {
      rot = new Array2DRowRealMatrix(new double[][] {
        new double[] {1.0, 0.0, 0.0},
        new double[] {0.0, 1.0, 0.0},
        new double[] {0.0, 0.0, 1.0},
      });
    }

    // Vector3f x_bar1 = x1 + translation;
    RealVector x_bar1 = rot.operate(x1).add(translation);
    // Vector3f x_bar2 = x2 + translation;
    RealVector x_bar2 = rot.operate(x2).add(translation);
    // Vector3f x_bar3 = x3 + translation;
    RealVector x_bar3 = rot.operate(x3).add(translation);

    // std::cerr << "x_bar1 = \n" << x_bar1 << std::endl;
    System.out.println("x_bar1 = ");
    System.out.println(x_bar1);
    // std::cerr << "x_bar2 = \n" << x_bar2 << std::endl;
    System.out.println("x_bar2 = ");
    System.out.println(x_bar2);
    // std::cerr << "x_bar3 = \n" << x_bar3 << std::endl;
    System.out.println("x_bar3 = ");
    System.out.println(x_bar3);

    // Vector3f c     = (x1+x2+x3)/3.0f;
    RealVector c     = x1.add(x2).add(x3).mapDivide(3.0f);

    // Vector3f c_bar = (x_bar1+x_bar2+x_bar3)/3.0f;
    RealVector c_bar     =
      x_bar1.add(x_bar2).add(x_bar3).mapDivide(3.0f);

    // Vector3f y1,y2,y3, y_bar1,y_bar2,y_bar3;
    // y1  = x1 - c;
    RealVector y1  = x1.subtract(c);
    // y2  = x2 - c;
    RealVector y2 = x2.subtract(c);
    // y3  = x3 - c;
    RealVector y3 = x3.subtract(c);
    // y_bar1 = x_bar1 - c_bar;
    RealVector y_bar1 = x_bar1.subtract(c_bar);
    // y_bar2 = x_bar2 - c_bar;
    RealVector y_bar2 = x_bar2.subtract(c_bar);
    // y_bar3 = x_bar3 - c_bar;
    RealVector y_bar3 = x_bar3.subtract(c_bar);

    System.out.println("Y1 " + y1 + " (Q1)");
    System.out.println("Y2 " + y2 + " (Q2)");
    System.out.println("Y3 " + y3 + " (Q3)");
    System.out.println("YB1 " + y_bar1);
    System.out.println("YB2 " + y_bar2);
    System.out.println("YB3 " + y_bar3);

    // Matrix3f H;
    // H =  y1*y_bar1.transpose()+y2*y_bar2.transpose()+y3*y_bar3.transpose();
    RealMatrix h = xyt(y1, y_bar1).add(xyt(y2,y_bar2)).add(
      xyt(y3, y_bar3));

    // JacobiSVD<Matrix3f> svd(H, ComputeFullU | ComputeFullV);
    SingularValueDecompositionImpl svd = 
      new SingularValueDecompositionImpl(h);
    System.out.println("Singular values are " + Arrays.toString(svd.getSingularValues()));
    // Matrix3f R; R = svd.matrixV()*svd.matrixU().transpose();
    RealMatrix r = svd.getV().multiply(svd.getUT());
    double rDeterminant = r.getDeterminant();
    System.out.println("Determinant " + rDeterminant);
    if (rDeterminant < 0.0)
    { // coplanar case - which is not surprising because Q in the original paper sum to 0.0
      // because centroid is subtracted from each of them. Try alternate r
      RealMatrix changeLastColumn = new Array2DRowRealMatrix(new double[][] {
        new double[] {1.0, 0.0, 0.0},
        new double[] {0.0, 1.0, 0.0},
        new double[] {0.0, 0.0, -1.0}});
      RealMatrix vd = svd.getV().multiply(changeLastColumn);
      r = vd.multiply(svd.getUT());
      rDeterminant = r.getDeterminant();
      System.out.println("Determinant at second go is " + rDeterminant);
    }
    // Vector3f t; t = c-R*c_bar;
    // Note - original transpose seems to be the wrong way round
    RealVector t = c_bar.subtract(r.operate(c));

    // std::cerr << "R = \n" << R << std::endl;
    System.out.println("R = ");
    System.out.println(r);
    // std::cerr << "t = \n" << t << std::endl;
    System.out.println("t = ");
    System.out.println(t);

    // Apply supposed answer
    RealVector z1 = r.operate(x1).add(t);   
    RealVector z2 = r.operate(x2).add(t);   
    RealVector z3 = r.operate(x3).add(t);   
    System.out.println("Z1  "+ z1);
    System.out.println("Z2  "+ z2);
    System.out.println("Z3  "+ z3);
  }

/*

But I get wrong answer:

R = 
 0.836735 -0.244898 -0.489796
-0.244898  0.632653 -0.734694
-0.489796 -0.734694 -0.469388
t = 
0.142857
3.71429
1.42857

Is the problem in the implementation or in the algorithm? If so, what is the correction?
*/
}