PCA主成分分析 特征降维 opencv实现
最近对PCA主成分分析做了一定的了解,对PCA基础和简单的代码做了小小的总结
有很多博客都做了详细的介绍,这里也参考了这些大神的成果:
http://blog.sina.com.cn/s/blog_75e063c101014aob.html 这个博客opencv简单实现了PCA,对PCA关键技术做了详细的分析
http://blog.sina.com.cn/s/blog_4b9b714a0100hc8o.html 这篇文章介绍了opencv实现PCA的相关函数
http://blog.csdn.net/huangxy10/article/details/7912189 这篇文章给出了一个PCA的opencv代码实现的例子
http://blog.csdn.net/augusdi/article/details/9005276/ 讲的比较详细
先把实验的代码贴出来(主要是参考上面博客的代码)
1 #include <iostream> 2 #include <opencv2/highgui/highgui.hpp> 3 #include <opencv2/core/core.hpp> 4 #include <opencv/cv.hpp> 5 6 using namespace std; 7 using namespace cv; 8 9 float Coordinates[50]={2.5,0.5,2.2,1.9,3.1,2.3,2.0,1.0,1.5,1.1, 10 2.4,0.7,2.9,2.2,3.0,2.7,1.6,1.1,1.6,0.9, 11 2.1,0.4,2.7,2.2,3.4,2.5,1.3,1.2,1.5,0.8, 12 2.0,0.2,2.4,2.3,3.1,2.3,1.4,1.9,1.1,1.8, 13 1.9,0.3,2.8,2.2,1.1,2.7,4.4,1.5,1.8,1.8 14 }; 15 16 void PrintMatrix(CvMat *Matrix,int Rows,int Cols); 17 18 int main() 19 { 20 CvMat *Vector1; 21 CvMat *AvgVector; 22 CvMat *EigenValue_Row; 23 CvMat *EigenVector; 24 25 Vector1=cvCreateMat(5,10,CV_32FC1); 26 cvSetData(Vector1,Coordinates,Vector1->step); //给vector1赋值(样本矩阵) 27 AvgVector=cvCreateMat(1,10,CV_32FC1); //这个用处还不知道 28 EigenValue_Row=cvCreateMat(1,5,CV_32FC1); //每个数表示一个特征值,5是选取的样本数和维度中较小的数 29 EigenVector=cvCreateMat(5,10,CV_32FC1); //每一行表示一个特征向量,5是选取的样本数和维度中较小的数 30 31 //PCA的实现函数 32 cvCalcPCA(Vector1,AvgVector,EigenValue_Row,EigenVector,CV_PCA_DATA_AS_ROW); 33 34 CvMat *Vector2 = cvCreateMat(5,5,CV_32FC1); 35 //cvProjectPCA(Vector1,AvgVector,EigenVector,Vector2); //选择前面的特征向量(主成分) 36 37 printf("原始样本矩阵:\n"); 38 PrintMatrix(Vector1,Vector1->rows,Vector1->cols); 39 printf("----------------------\n"); 40 printf("----------------------\n"); 41 printf("特征值:\n"); 42 PrintMatrix(EigenValue_Row,EigenValue_Row->rows,EigenValue_Row->cols); 43 printf("----------------------\n"); 44 printf("特征向量:\n"); 45 PrintMatrix(EigenVector,EigenVector->rows,EigenVector->cols); 46 47 system("pause"); 48 return 0; 49 } 50 void PrintMatrix(CvMat *Matrix,int Rows,int Cols) 51 { 52 for(int i=0;i<Rows;i++) 53 { 54 for(int j=0;j<Cols;j++) 55 { 56 printf("%.4f ",cvGet2D(Matrix,i,j).val[0]); 57 } 58 printf("\n"); 59 } 60 }
上面的主要的函数是cvCalcPCA(Vector1,AvgVector,EigenValue_Row,EigenVector,CV_PCA_DATA_AS_ROW);功能是计算特征值和特征向量
CV_PCA_DATA_AS_ROW:是以列为主的资料的排列
Vector1:所有样本组成的矩阵(这里有5个样本,每个样本是10维的特征向量)
AvgVector:空的平均数向量(不懂)
EigenValue_Row:存放求出的特征值
EigenVector:存放特征向量
另外,函数cvProjectPCA()和函数cvBackProjectPCA(),可以通过矩阵的乘法实现样本特征的降维和重新转回原来维度的坐标系。
PCA的技术介绍:
PCA是主成分分析,主要用于降噪和去冗余(降维),对于一系列sample(n个样本)的feature(m维)组成的多维向量,多维向量里的某些元素本身没有区分性,比如某个元素在所有的sample中都为1,或者与1相差不大,那么这个元素本身就没有区分性,用它来做特征区分,贡献非常小。所以我们的目的是找那些变化大的元素,即方差大的那些维,而去除变化不大的维,从而使feature留下的都是区分能力强的,而且计算量也变小了。
协方差矩阵:
协方差用来描述二维数据,要想描述多维的数据就把所有维度进行两两求协方差,也就组成了协方差矩阵。协方差矩阵度量的是维度与维度之间的关系,而不是样本与样本的关系。
可见协方差矩阵是一个对称的矩阵,对角线上是各个维度的方差。是各个维度拥有的能量。降噪:是把协方差矩阵对角化。去冗余:取出对角化之后最大特征值上的维度。如果对角线上值比较小,说明在所有样本上变化不明显,对区分不同样本作用不大,是冗余的。
因为协方差矩阵的特征值的大小代表了这个维度上的能量,找出最大的特征值即为主分量。
协方差矩阵对角线上表示每一维的方差(可以表示这一维的能量),非对角线上的值就是每两个维度之间的相关性。去除噪声就是要减小相关性把非对角线的值减小。通过矩阵对角化来完成。对角化后的矩阵,对角线上的值是协方差矩阵的特征值:它是每个维度上的新方差(表示能量),这样就把各维度间的相关性减到最小。
利用特征向量矩阵进行降维:
如果选取了p个特征值可以表示所有的99%以上(或者超过95%等都行,看自己的要求),那么最大的p个特征值的特征向量就组成了m*p的矩阵。我们知道样本是m维的,拿样本向量与这个m*p的矩阵相乘,就得到一个p维的特征,这就完成了降维。