为什么这个matlab和C ++代码产生不同的结果? [英] Why this matlab and C++ codes produces different results?

查看:587
本文介绍了为什么这个matlab和C ++代码产生不同的结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

+我想在C ++中实现一个matlab算法。



这是matlab代码:

  p = 
K = [3 4 5; 4 5 6; 7 8 9];
e = ones(p,1);
K2 = K-(1 / p)* K * ones(p)-1 / p +(1 / p ^ 2)* sum(K(:))
[V_K,D_K] = eig(K2);

虽然这是使用OpenCV的类似C ++代码:

  float data [] = {3,4,5,
4,5,6,
7,8,9}
cv :: Mat m(3,3,CV_32F,data);
float p = K.rows;
cv :: Mat CK = K - (1 / p)* K * cv :: Mat :: ones(p,p,CV_32F)-1 / p +(1 / std :: pow ))* cv :: sum(K)[0];
cv :: Mat eigenvalues(1,p,CK.type()),eigenvectors(p,p,CK.type());
cv :: eigen(CK,eigenvalues,eigenvectors);

matlab代码print:

  CK = 

4.3333 5.3333 6.3333
4.3333 5.3333 6.3333
4.3333 5.3333 6.3333

0.5774 0.6100 -0.1960
0.5774 -0.7604 -0.6799
0.5774 0.2230 0.7066

16.0000 0 0
0 -0.0000 0
0 0 0.0000

虽然C ++代码产生:

  CK = [4.3333335,5.33333335,6.333333; 
4.3333335,5.3333335,6.3333335;
4.333333,5.333333,6.333333]

eigenvectors = [0.53452265,0.56521076,0.62834883;
-0.41672006,0.8230716,-0.38587254;
0.73527533,0.05558794,-0.67548501]

eigenvalues = [17.417906;
-0.33612049;
-1.0817847]

正如你所看到的, em>不同(甚至 CK !)。为什么会发生这种情况,我该如何避免呢?



注意我不能完全确定我的C ++实现是否正确! >

我找到了这个问题相关,但他们似乎与略有差异相关,而这里的错误是巨大



UPDATE:



我已经尝试按照评论&答案。不幸的是,没有一个解决方案解决了这个问题。首先,我尝试使用 eigen 库和 float 精度。这是使用 Eigen :: Map 结构的代码这里

  //为了将OpenCV矩阵映射到Eigen, be continous 
assert(CK.isContinuous());
Eigen :: Map< Eigen :: Matrix< float,Eigen :: Dynamic,Eigen :: Dynamic,Eigen :: RowMajor> CKEigenMapped(CK.ptr< float>(),CK.rows,CK.cols);
Eigen :: Matrix< float,Eigen :: Dynamic,Eigen :: Dynamic,Eigen :: RowMajor> CKEigen = CKEigenMapped;
Eigen :: EigenSolver< Eigen :: Matrix< float,Eigen :: Dynamic,Eigen :: Dynamic,Eigen :: RowMajor> es(CKEigen,true);
std :: cout<<Eigenvalues:<< std :: endl< es.eigenvalues()<< std :: endl;
std :: cout<<Eigenvectors:<< std :: endl< es.eigenvectors()<< std :: endl;

然后我试图从 float double 通过 CK.convertTo(CK,CV_64F)

  //双精度
CK.convertTo(CK,CV_64F);
Eigen :: Map< Eigen :: Matrix< double,Eigen :: Dynamic,Eigen :: Dynamic,Eigen :: RowMajor> CKEigenMappedD(CK.ptr double(),CK.rows,CK.cols);
Eigen :: Matrix< double,Eigen :: Dynamic,Eigen :: Dynamic,Eigen :: RowMajor> CKEigenD = CKEigenMappedD;
Eigen :: EigenSolver< Eigen :: Matrix< double,Eigen :: Dynamic,Eigen :: Dynamic,Eigen :: RowMajor> esD(CKEigenD,true);
std :: cout<<Eigenvalues:<< std :: endl< esD.eigenvalues()<< std :: endl;
std :: cout<<Eigenvectors:<< std :: endl< esD.eigenvectors()<< std :: endl;

最后,我尝试使用 cv2eigen 函数(我认为 Eigen :: Map 可能是错误的)这里

  // Double precision,cv2eigen 
Eigen :: MatrixXd X = Eigen :: MatrixXd(CK.rows,CK.cols);
cv2eigen(CK,X);
Eigen :: EigenSolver< Eigen :: MatrixXd> esDD(X,true);
std :: cout<<Eigenvalues:<< std :: endl< esDD.eigenvalues()<< std :: endl;
std :: cout<<Eigenvectors:<< std :: endl< esDD.eigenvectors()<< std :: endl;

这些是对应于之前3个解决方案的结果:

 特征值:
(-4.17233e-07,0)
(16,0)
(-3.37175e-07, 0)
特征向量:
(-0.885296,0)(0.57735,0)(-0.88566,0)
(0.328824,0)(0.57735,0)(0.277518,0)
(0.328824,0)(0.57735,0)(0.372278,0)
特征值:
(16,0)
(8.9407e-08,0)
1.88417e-16,0)
特征向量:
(0.57735,0)(0.480589,0)(0.408248,0)
(0.57735,0)(0.480589,0)(-0.816497, 0)
(0.57735,0)(-0.733531,0)(0.408248,0)
特征值:
(16,0)
(8.9407e-08,0) b $ b(-1.88417e-16,0)
特征向量:
(0.57735,0)(0.480589,0)(0.408248,0)
(0.57735,0)(0.480589,0 )(-0.816497,0)
(0.57735,0)(-0.733531,0)(0.408248,0)

你可以注意到:


  1. 没有一个符合Matlab的结果
  2. 使用 double float

  3. 有区别
  4. 使用 Eigen :: Map cv2eigen
  5. 没有区别。

请注意我在 Eigen 中不是专家, code> Eigen :: EigenSolver 错误。



UPDATE 2:

这开始是一团糟!这是使用Amradillo的代码。 注意 A 的值与 K2 CK 在C ++中):

  arma :: mat A(3,3) 
A<< 4.333333333333333< 5.333333333333333< 6.333333333333333<< arma :: endr
<< 4.333333333333333< 5.333333333333333< 6.333333333333333<< arma :: endr
<< 4.333333333333333< 5.333333333333333< 6.333333333333333<<< arma :: endr;
arma :: cx_vec eigval;
arma :: cx_mat eigvec;
eig_gen(eigval,eigvec,A);
std :: cout <<eigval =<< std :: endl<< eigval<< std :: endl<<eigvec =<< std :: endl& < eigvec<< std :: endl;

这些是打印的值:

  eigval = 
(+ 1.600e + 01,+ 0.000e + 00)
(-4.010e-17,+ 3.435e-16)
(-4.010e-17,-3.435e-16)

eigvec =
(+ 5.774e-01,+ 0.000e + 00)(-5.836e-02,+ 3.338e -01)(-5.836e-02,-3.338e-01)
(+ 5.774e-01,+ 0.000e + 00)(+ 7.174e-01,+ 0.000e + 00) -01,-0.000e + 00)
(+ 5.774e-01,+ 0.000e + 00)(-5.642e-01,-2.284e-01)(-5.642e-01,+ 2.284e- 01)

很明显,这些库有什么问题?他们甚至彼此不一致!

解决方案

cv :: eigen 假设输入矩阵 symetric ,而您的不是。这就是为什么差别在那里。



我相信openCV不支持非对称矩阵的特征向量,可能需要使用另一个库。



更新: PCA(主成分分析)是特征向量分解,因此您可以方式,但最好是使用一些特定的数学库,如EIGEN或ARMADILLO。


+I'm trying to implement a matlab algorithm in C++.

This is the matlab code:

p = 3;
K = [3 4 5; 4 5 6; 7 8 9];
e = ones(p,1);
K2 = K - (1/p)*K*ones(p) - 1/p + (1/p^2)*sum(K(:))
[V_K,D_K] = eig(K2);

While this is the analogous C++ code using OpenCV:

float data[] = {3, 4, 5,
                4, 5, 6,
                7, 8, 9};
cv::Mat m(3, 3, CV_32F, data);
float p = K.rows;
cv::Mat CK = K - (1/p)*K*cv::Mat::ones(p,p,CV_32F) - 1/p + (1/std::pow(p,2))*cv::sum(K)[0];
cv::Mat eigenvalues(1,p,CK.type()), eigenvectors(p,p,CK.type());
cv::eigen(CK,eigenvalues,eigenvectors);

The matlab code print:

CK =

4.3333    5.3333    6.3333
4.3333    5.3333    6.3333
4.3333    5.3333    6.3333

0.5774    0.6100   -0.1960
0.5774   -0.7604   -0.6799
0.5774    0.2230    0.7066

16.0000         0         0
      0   -0.0000         0
      0         0    0.0000

While the C++ code produces:

CK=[4.3333335, 5.3333335, 6.3333335;
 4.3333335, 5.3333335, 6.3333335;
 4.333333, 5.333333, 6.333333]

eigenvectors=[0.53452265, 0.56521076, 0.62834883;
 -0.41672006, 0.8230716, -0.38587254;
 0.73527533, 0.05558794, -0.67548501]

eigenvalues=[17.417906;
 -0.33612049;
 -1.0817847]

As you can see, the values are completely differents (even the ones of CK!). Why this happens and how can I avoid it?

Note that I'm not completely sure that my C++ implementation is correct!

I found this and this question related, but they seem related to slightly differences, while here the error is huge!

UPDATE:

I've tried to follow to suggestions in comments & answers. Unfortunately, none of the solution proposed solved the problem. First of all I tried to use the Eigen library with float precision. This is the code using the Eigen::Map structure as described here:

//in order to map OpenCV matrices to Eigen, they need to be continous
assert(CK.isContinuous());
Eigen::Map<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> CKEigenMapped (CK.ptr<float>(), CK.rows, CK.cols);
Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> CKEigen = CKEigenMapped;
Eigen::EigenSolver<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> es (CKEigen,true);
std::cout<<"Eigenvalues:"<<std::endl<< es.eigenvalues() << std::endl;
std::cout<<"Eigenvectors:"<<std::endl<< es.eigenvectors() << std::endl;

Then I tried to convert from float to double through CK.convertTo(CK, CV_64F):

//Double precision
CK.convertTo(CK, CV_64F);
Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> CKEigenMappedD (CK.ptr<double>(), CK.rows, CK.cols);
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> CKEigenD = CKEigenMappedD;
Eigen::EigenSolver<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> esD (CKEigenD,true);
std::cout<<"Eigenvalues:"<<std::endl<< esD.eigenvalues() << std::endl;
std::cout<<"Eigenvectors:"<<std::endl<< esD.eigenvectors() << std::endl;

Finally I tried to use the cv2eigen function (I thought that Eigen::Map could have been wrong) as described here:

//Double precision, cv2eigen
Eigen::MatrixXd X=Eigen::MatrixXd(CK.rows,CK.cols);
cv2eigen(CK,X);
Eigen::EigenSolver<Eigen::MatrixXd> esDD (X,true);
std::cout<<"Eigenvalues:"<<std::endl<< esDD.eigenvalues() << std::endl;
std::cout<<"Eigenvectors:"<<std::endl<< esDD.eigenvectors() << std::endl;

And these are the results corresponding to the 3 previous solutions:

Eigenvalues:
(-4.17233e-07,0)
          (16,0)
(-3.37175e-07,0)
Eigenvectors:
(-0.885296,0)   (0.57735,0)  (-0.88566,0)
 (0.328824,0)   (0.57735,0)  (0.277518,0)
 (0.328824,0)   (0.57735,0)  (0.372278,0)
Eigenvalues:
          (16,0)
  (8.9407e-08,0)
(-1.88417e-16,0)
Eigenvectors:
  (0.57735,0)  (0.480589,0)  (0.408248,0)
  (0.57735,0)  (0.480589,0) (-0.816497,0)
  (0.57735,0) (-0.733531,0)  (0.408248,0)
Eigenvalues:
          (16,0)
  (8.9407e-08,0)
(-1.88417e-16,0)
Eigenvectors:
  (0.57735,0)  (0.480589,0)  (0.408248,0)
  (0.57735,0)  (0.480589,0) (-0.816497,0)
  (0.57735,0) (-0.733531,0)  (0.408248,0)

As you can notice:

  1. None of them correspond to the Matlab results ( :'( )
  2. There is a difference between using double and float
  3. There is no difference between using Eigen::Map and cv2eigen

Please note that I'm not expert in Eigen and I could have used Eigen::EigenSolver in a wrong way.

UPDATE 2:

This is starting to be a mess! This is the code using Amradillo. Notice that A has the same values of K2 (CK in C++):

arma::mat A(3,3);
A   << 4.333333333333333 << 5.333333333333333 << 6.333333333333333 <<arma::endr
    << 4.333333333333333 << 5.333333333333333 << 6.333333333333333 <<arma::endr
    << 4.333333333333333 << 5.333333333333333 << 6.333333333333333 <<arma::endr;
arma::cx_vec eigval;
arma::cx_mat eigvec;
eig_gen(eigval,eigvec,A);
std::cout<<"eigval="<<std::endl<<eigval<<std::endl<<"eigvec="<<std::endl<<eigvec<<std::endl;

And these are the printed values:

eigval=
    (+1.600e+01,+0.000e+00)
    (-4.010e-17,+3.435e-16)
    (-4.010e-17,-3.435e-16)

eigvec=
    (+5.774e-01,+0.000e+00)    (-5.836e-02,+3.338e-01)    (-5.836e-02,-3.338e-01)
    (+5.774e-01,+0.000e+00)    (+7.174e-01,+0.000e+00)    (+7.174e-01,-0.000e+00)
    (+5.774e-01,+0.000e+00)    (-5.642e-01,-2.284e-01)    (-5.642e-01,+2.284e-01)

Seriously, what's wrong with all these libraries? They don't even closely agree with each other!

解决方案

cv::eigen assumes that the input matrix is symetric, and yours is not. that is why the difference is there.

I believe openCV does not have support for eigenvectors of non-symmetric matrices, you may need to use another library.

Update: PCA (principal component analysis) is an eigenvector decomposition, so you may be able to go that way, but the best would be to use some specific math library, such as EIGEN or ARMADILLO.

这篇关于为什么这个matlab和C ++代码产生不同的结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆