为什么这个matlab和C ++代码产生不同的结果? [英] Why this matlab and C++ codes produces different results?
问题描述
+我想在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)
你可以注意到:
- 没有一个符合Matlab的结果
- 使用
double
和float
与 - 使用
Eigen :: Map
和cv2eigen
没有区别。
有区别
请注意我在 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:
- None of them correspond to the Matlab results ( :'( )
- There is a difference between using
double
andfloat
- There is no difference between using
Eigen::Map
andcv2eigen
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屋!