PCA简介:
主成分分析(Principal Component Analysis, 简称PCA)是一种常用的基于变量协方差矩阵对信息进行处理、压缩和抽提的有效方法。PCA方法由于其在降维和特征提取方面的有效性,在人脸识别领域得到了广泛的应用。PCA方法的基本原理是:利用K-L变换抽取人脸的主要成分,构成特征脸空间,识别时将测试图像投影到此空间,得到一个投影系数矩阵,再通过分类器进行分类识别。
PCA主要用途:
PCA主要用于数据降维,在一个图像矩阵中,有些元素特征不明显,不能用来做识别,而有些元素特征很明显,表现在方差很大(某个元素的方差可以度量其相对于整个样本的离散性),这些元素常常作为图像识别的依据。PCA的作用就是去除那些方差较小,特征不明显的维,保留方差较大,有利于识别的维。这样降低了图像矩阵的维数,减小了运算量。
PCA降维的过程:
协方差矩阵公式:
协方差(i,j)=(第i维的所有元素-第i维的均值)*(第j维的所有元素-第j维的均值)
假设:样本集有5张图片,每张图片尺寸为270*200=54000。
A(54000*5): 每一列表示一张图片的所有列的串联,共5列。
E(54000*54000): A按维度计算的协方差组成的矩阵。
V(54000*5): E的特征向量组成的矩阵,每一列表示一个特征向量,且按对应的特征值从大到小排列。E*V=a*V,a为特征值。
U(54000*4): V的前四列组成的矩阵,即保留四个主成分。
UT(4*54000): U的转置矩阵。
D(4*5): 降维后的矩阵,D(4*5)= UT(4*54000)*A(54000*5),从样本空间映射到协方差矩阵特征向量空间。
PCA降维C++代码及测试:
源代码下载路径(Qt工程):http://download.csdn.net/detail/u013752202/9225027
#include "opencv2\opencv.hpp"
#include <QApplication>
#include <QDebug>
using namespace cv;
/*把多张同样大小的图像平铺到一张图像上*/
void mergeImage(vector<Mat> src,Mat &srcAll,int cols)
{
Mat src0=src[0];
int line=src.size()/cols;
src.size()%cols?line++:line;
srcAll.create(src0.rows*line,src0.cols*cols,src0.type());
for(int i=0;i<src.size();i++){
Mat temp=src[i];
int x=(i%cols)*temp.cols;
int line=i/cols;
int y=line*temp.rows;
int w=temp.cols;
int h=temp.rows;
Mat ROI=srcAll(Rect(x,y,w,h));
temp.copyTo(ROI);
}
}
int main(int argc,char **argv)
{
vector<Mat> src;
//加载样本集
Mat src1=imread("huang.jpg",0);
Mat src2=imread("yang.jpg",0);
Mat src3=imread("zheng.jpg",0);
Mat src4=imread("he.jpg",0);
Mat src5=imread("fan.jpg",0);
src.push_back(src1);
src.push_back(src2);
src.push_back(src3);
src.push_back(src4);
src.push_back(src5);
//mat数组用来存放读取进来的所有图片的数据,其中mat的每一列对应1张图片,该实现在下面的for函数中
//把src[i]的所有列串联起来并保存在mat中的第i列
int total=src1.rows*src1.cols;
Mat mat(total,src.size(),CV_32FC1);
for(int i=0; i<src.size();i++){
Mat colIMG = mat.col(i);
src[i].reshape(1,total).col(0).convertTo(colIMG,CV_32FC1,1/255.0);
}
//构造pca数据结构
//pca.eigenvectors中的每一行代表输入数据协方差矩阵一个特征向量,
//且是按照该协方差矩阵的特征值从大到小进行排序的
int features = 5;//保留协方差矩阵特征向量的个数,即经过PCA后的维数
PCA pca(mat,Mat(),CV_PCA_DATA_AS_COL,features);
qDebug()<<"pca.eigenvectors.rows"<<pca.eigenvectors.rows
<<"pca.eigenvectors.cols"<<pca.eigenvectors.cols;
Mat featureFace1t;
normalize(pca.eigenvectors.row(0),featureFace1t,1.0,0.0,NORM_MINMAX);
Mat featureFace1=featureFace1t.reshape(1, src[0].rows);//第一个特征向量脸
Mat featureFace2t;
normalize(pca.eigenvectors.row(1),featureFace2t,1.0,0.0,NORM_MINMAX);
Mat featureFace2=featureFace2t.reshape(1, src[0].rows);//第二个特征向量脸
Mat featureFace3t;
normalize(pca.eigenvectors.row(2),featureFace3t,1.0,0.0,NORM_MINMAX);
Mat featureFace3=featureFace3t.reshape(1, src[0].rows);//第三个特征向量脸
Mat featureFace4t;
normalize(pca.eigenvectors.row(3),featureFace4t,1.0,0.0,NORM_MINMAX);
Mat featureFace4=featureFace4t.reshape(1, src[0].rows);//第四个特征向量脸
Mat featureFace5t;
normalize(pca.eigenvectors.row(4),featureFace5t,1.0,0.0,NORM_MINMAX);
Mat featureFace5=featureFace5t.reshape(1, src[0].rows);//第五个特征向量脸
//求降维后的矩阵
Mat pcaDst=pca.project(mat);
qDebug()<<"pcaDst.rows: "<<pcaDst.rows
<<"pcaDst.cols: "<<pcaDst.cols;
//转换并显示
Mat featureFace1s(src1.size(),src1.type());
featureFace1.convertTo(featureFace1s,src1.type(),255,0);
src.push_back(featureFace1s);
Mat featureFace2s(src1.size(),src1.type());
featureFace2.convertTo(featureFace2s,src1.type(),255,0);
src.push_back(featureFace2s);
Mat featureFace3s(src1.size(),src1.type());
featureFace3.convertTo(featureFace3s,src1.type(),255,0);
src.push_back(featureFace3s);
Mat featureFace4s(src1.size(),src1.type());
featureFace4.convertTo(featureFace4s,src1.type(),255,0);
src.push_back(featureFace4s);
Mat featureFace5s(src1.size(),src1.type());
featureFace5.convertTo(featureFace5s,src1.type(),255,0);
src.push_back(featureFace5s);
Mat srcAll;
mergeImage(src,srcAll,5);
imshow("FaceShow",srcAll);
waitKey(0);
return 0;
}<strong>
</strong>
运行结果分析:
第一行:样本图片,共5张
第二行:协方差矩阵特征向量的前5个,按对应的特征值大小排列。
从第二行可以看出,越前面的特征是越大的特征向量特征越明显,区分度越高!