《learning opencv》ex7-4 解决方案
opencv 提供了方便的借口以实现矩阵的奇异值分解,本篇文章将会利用opencv对矩阵的奇异值分解的步骤逐步实现,并与opencv提供的SVD()
方法相对比。
其实现步骤如下:
对于如下矩阵:
- 计算方阵 的特征值()和特征向量(,利用特征值和特征向量,计算(.
- 计算矩阵和, 如下公式所示:
- 定义矩阵
4.利用如下公式
验证奇异值分解,并与cv::SVD::compute()
方法比较
根据以上,实现代码如下:
#include
#include
#include
using namespace cv;
/*
Beginning with the following matrix:
1 0
A = 0 1
-1 1
a. First compute,by hand,the matrix ATA,Find the eigenvalues(e1,e2),and eigenvectors(v1,v2),
of ATA,From the eigenvalues,compute the singular values(delta1,delta2)=(sqrt(e1),sqrt(e2))
b. Compute the matrices V=[v1,v2],and U=[u1,u2,u3],Recall that u1=1/delta1*Av1,u2=1/delta2*Av2,
and u3 is a vector orthogonal to both u1 and u2.Hint:recall that the cross product of two vectors
is always orthogonal to both terms in the cross product.
c. The matrix sigma is defined(given this particular values of A) to be
delta1 0
sigma = 0 delta2
0 0
Using this definition of sigma, and the preceding results for V and U,verify A=U*Sigma*V.T
by direct multiplication.
d. Using the cv::SVD object,compute the preceding matrices Sigma,U and V,and verify that the results
you computed by hand are correct.Do you get exactly what you expected? if not,explain.
*/
int main()
{
Mat A = (Mat_(3, 2) << 1, 0, 0, 1, -1, 1);
Mat ATA = A.t() * A;
//std::cout << A << std::endl;
//计算特征值和特征向量
Mat eigenvalues;
Mat eigenvectors;
eigen(ATA, eigenvalues, eigenvectors);
//对特征值进行平方根处理
float delta1 = sqrt(eigenvalues.at(0,0));
float delta2 = sqrt(eigenvalues.at(1,0));
Matx12f delta(delta1, delta2);
Mat eigenvectors_1 = eigenvectors.col(0);
Mat eigenvectors_2 = eigenvectors.col(1);
//b
Mat u_1 = 1.0 / delta1 * A * eigenvectors_1;
Mat u_2 = 1.0 / delta2 * A * eigenvectors_2;
Mat u_3 = u_1.cross(u_2);
//c
Mat Sigma = (Mat_(3, 2) << delta1, 0, 0, delta2, 0, 0);
Mat u_temp,U,V;
hconcat(u_1,u_2,u_temp);
hconcat(u_temp, u_3, U);
hconcat(eigenvectors_1, eigenvectors_2, V);
std::cout << eigenvectors_1.size() << std::endl;
//verify A = U*Sigma*V.T
Mat A_verify = Mat(U*Sigma * V.t());
std::cout << A_verify << std::endl;
//SVD with cv::SVD::compute()
Mat U_svd, Sigma_svd, V_svd;
SVD::compute(A, U_svd, Sigma_svd, V_svd);
return 0;
}