OpenCV+Qt:基于PCA主成分分析的人脸识别例程

在模式识别领域中,PCA是一种常用的数据集降维手段,在此基础上,保留数据集中对方差贡献最大的特征从而进行模式分类。OpenCV中提供PCA的类,因此可以方便地使用PCA来进行人脸识别研究。在学习了网上的相关实现和代码,在以下开发平台跑通了代码:win8.1+OpenCV2.4.9+Qt5.3.2。

一、基本步骤

关于PCA的一些理论,,可参照: 以下是实现PCA的基本思路:

1.把原始数据中每个样本用一个向量表示,然后把所有样本组合起来构成一个矩阵。这里为了避免样本单位对后续处理的影响,样本集需要标准化。

2.求样本的散布矩阵。事实上,散布矩阵是样本协方差矩阵的(n-1)倍

3.对第二步中得到的散布矩阵求相应的特征值和特征向量。

4.将求出的特征向量按照特征值的大小进行组合形成一个映射矩阵,并根据指定的PCA保留的特征个数取出映射矩阵的前n行或者前n列作为最终的映射矩阵。

5.最后,用第四步的映射矩阵对原始数据进行映射,达到数据降维的目的,得到的新向量是两两不相关的。

在本次实验实现的过程中,需要用到opencv的这些函数,下面简单介绍下这些函数。

二、OpenCV中需要用到的几个函数

PCA::PCA(InputArray data,// 输入一个矩阵InputArray mean,maxComponents=0) // 计算PCA时保留的最大主成分的个数// 该函数将输入数据投影到PCA主成分空间中去// 返回每一个样本主成分特征组成的矩阵cv::Mat PCA::project(InputArray vec) constcv::Mat PCA::backProject(InputArray vec) const

另外PCA类中还有几个重要的成员变量:

mean// 原始数据的均值eigenvectors // 散布矩阵(协方差矩阵)的特征值eigenvalues // 散布矩阵(协方差矩阵)的特征向量

三、相关代码

根据网上提供的代码,修改成可以在开发平台上使用的版本:

cv;#include <QDialog>namespace Ui {class PCAFace;}class PCAFace : public QDialog{Q_OBJECTpublic:explicit PCAFace(QWidget *parent = 0);~PCAFace();Mat normalize(const Mat& src);protected:void changeEvent(QEvent *e);private slots:void on_startButton_clicked();void on_closeButton_clicked();private:Ui::PCAFace *ui;Mat src_face1, src_face2, src_face3;Mat project_face1, project_face2, project_face3;Mat dst;Mat pca_face1, pca_face2, pca_face3;vector<Mat> src;int total;};#endif // PCAFACE_Hnamespace std;QDir dir;QString runPath = dir.currentPath();PCAFace::PCAFace(QWidget *parent) :QDialog(parent),ui(new Ui::PCAFace){ui->setupUi(this);src_face1 = imread(“C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/images/1.pgm”, 0);//下面的代码为设置图片显示区域自适应图片的大小ui->face1Browser->setFixedHeight(src_face1.rows+1);ui->face1Browser->setFixedWidth(src_face1.cols+1);ui->face2Browser->setFixedHeight(src_face1.rows+1);ui->face2Browser->setFixedWidth(src_face1.cols+1);ui->face3Browser->setFixedHeight(src_face1.rows+1);ui->face3Browser->setFixedWidth(src_face1.cols+1);ui->face4Browser->setFixedHeight(src_face1.rows+1);ui->face4Browser->setFixedWidth(src_face1.cols+1);ui->face5Browser->setFixedHeight(src_face1.rows+1);ui->face5Browser->setFixedWidth(src_face1.cols+1);ui->face6Browser->setFixedHeight(src_face1.rows+1);ui->face6Browser->setFixedWidth(src_face1.cols+1);ui->face7Browser->setFixedHeight(src_face1.rows+1);ui->face7Browser->setFixedWidth(src_face1.cols+1);ui->face8Browser->setFixedHeight(src_face1.rows+1);ui->face8Browser->setFixedWidth(src_face1.cols+1);ui->face9Browser->setFixedHeight(src_face1.rows+1);ui->face9Browser->setFixedWidth(src_face1.cols+1);for(int i = 1; i <= 15; i++){stringstream str;string num;str<<i;// 将整数i读入字符串流str>>num;// 将字符串流中的数据传入num,这2句代码即把数字转换成字符string image_name = (“C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/images/” + num + “.pgm”);//需要读取的图片全名src.push_back(imread(image_name, 0));}total= src[0].rows*src[0].cols;}PCAFace::~PCAFace(){delete ui;}void PCAFace::changeEvent(QEvent *e){QDialog::changeEvent(e);switch (e->type()) {case QEvent::LanguageChange:ui->retranslateUi(this);break;default:break;}}// 将Mat内的内容归一化到0~255,归一化后的类型为8位无符号整型单通道Mat PCAFace::normalize(const Mat& src){Mat norm_src;cv::normalize(src, norm_src, 0, 255, NORM_MINMAX, CV_8UC1);return norm_src;}void PCAFace::on_startButton_clicked(){//先显示3张原图ui->face1Browser->append(“<img src=C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/images/5.pgm>”);ui->face2Browser->append(“<img src=C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/images/7.pgm>”);ui->face3Browser->append(“<img src=C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/images/14.pgm>”);//mat数组用来存放读取进来的所有图片的数据,其中mat的每一列对应1张图片,该实现在下面的for函数中Mat mat(total, src.size(), CV_32FC1);for(int i = 0; i < src.size(); i++){Mat col_tmp = mat.col(i);src[i].reshape(1, total).col(0).convertTo(col_tmp, CV_32FC1, 1/255.);}int number_principal_compent = 12;//保留最大的主成分数//构造pca数据结构PCA pca(mat, Mat(), CV_PCA_DATA_AS_COL, number_principal_compent);//pca.eigenvectors中的每一行代表输入数据协方差矩阵一个特征向量,且是按照该协方差矩阵的特征值进行排序的pca_face1 = normalize(pca.eigenvectors.row(0)).reshape(1, src[0].rows);//第一个主成分脸imwrite(“C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/result/pca_face1.jpg”, pca_face1);//显示主成分特征脸1ui->face7Browser->append(“<img src=C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/result/pca_face1.jpg>”);pca_face2 = normalize(pca.eigenvectors.row(1)).reshape(1, src[0].rows);//第二个主成分脸imwrite(“C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/result/pca_face2.jpg”, pca_face2);//显示主成分特征脸2ui->face8Browser->append(“<img src=C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/result/pca_face2.jpg>”);pca_face3 = normalize(pca.eigenvectors.row(2)).reshape(1, src[0].rows);//第三个主成分脸imwrite(“C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/result/pca_face3.jpg”, pca_face3);//显示主成分特征脸3ui->face9Browser->append(“<img src=C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/result/pca_face3.jpg>”);//将原始数据通过PCA方向投影,即通过特征向量的前面几个作用后的数据,因此这里的dst的尺寸变小了dst = pca.project(mat);//通过方向投影重构原始人脸图像project_face1 = normalize(pca.backProject(dst).col(0)).reshape(1, src[0].rows);imwrite(“C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/result/project_face1.jpg”, project_face1);ui->face4Browser->append(“<img src=C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/result/project_face1.jpg>”);project_face2 = normalize(pca.backProject(dst).col(1)).reshape(1, src[0].rows);imwrite(“C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/result/project_face2.jpg”, project_face2);ui->face5Browser->append(“<img src=C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/result/project_face2.jpg>”);project_face3 = normalize(pca.backProject(dst).col(2)).reshape(1, src[0].rows);imwrite(“C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/result/project_face3.jpg”, project_face3);ui->face6Browser->append(“<img src=C:/Users/peng__000/Desktop/PR.proj05/OpenCV4PCA/PCA_Face/result/project_face3.jpg>”);}void PCAFace::on_closeButton_clicked(){close();}main(int argc, char *argv[]){QApplication a(argc, argv);PCAFace w;w.show();return a.exec();}

其中第一行的3张人脸分别为ORL人脸库其中的3张,分别取3个不同的人。

第二行中显示的3张人脸分别为第一行中人脸经过PCA投影函数Project后,又调用反向投影函数backProject变换回来的人脸图像。

第三行的人脸图为取的原始数据计算散布矩阵的特征向量的最前面3个,使用这3个向量所得到的输出最能代表人脸特征。

最后感谢代码原文介绍:

陪我们走过一段别人无法替代的记忆。

OpenCV+Qt:基于PCA主成分分析的人脸识别例程

相关文章:

你感兴趣的文章:

标签云: