应用PCA算法提取特征脸,重构人脸图像,并利用SVM算法进行人脸识别

//--应用PCA进行特征提取,并重构人脸图像--//

#include<highgui.h>
#include<cv.h>
#include<windows.h>
#include<iostream>
#include<stdio.h>
#include<cxcore.h>
#include<ml.h>

using namespace cv;
using namespace std;

char adr[100];
vector<Mat>pFrameMat;
Mat pDataMat;
CvMat *pData;    
CvMat *pAvgMat;
CvMat *pEigValueMat;
CvMat *pEigVectorMat;

float labels[200];
CvMat labelsMat; 

Mat ReadFaces(const vector<Mat>&pSrcImage,int pType);
vector<Mat> LoadFacesSample();
Mat NormImage_0_255(const Mat&pFrame);


int main(int argc,char**argv)
{
	cvNamedWindow("原始人脸图像",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("平均脸图像",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("主成分1人脸图像",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("主成分2人脸图像",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("重构人脸图像1",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("重构人脸图像2",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("重构人脸图像3",CV_WINDOW_AUTOSIZE);

	IplImage *pImage =cvLoadImage("F:\\人脸识别\\ORL人脸数据库\\s1\\1.bmp",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);

	for(int i=0;i<200;i++)
	{
		labels[i] =(float)(i/5);		        	
	}
	labelsMat =cvMat(200,1,CV_32FC1,labels);   //所有训练人脸样本数据的分类标记,共40类,0-39

	pFrameMat =LoadFacesSample();    //获取所有人脸样本组成的矩阵
	pDataMat =ReadFaces(pFrameMat,CV_32FC1);    //获取每个人脸样本转换成列向量的图像矩阵

	CvMat *pData =cvCreateMat(pDataMat.rows,pDataMat.cols,CV_32FC1);   //转换后的所有人脸样本的矩阵
	CvMat *pAvgMat =cvCreateMat(1,pDataMat.cols,CV_32FC1);   //所有人脸样本的平均向量
	CvMat *pEigValueMat =cvCreateMat(1,min(pDataMat.rows,pDataMat.cols),CV_32FC1);   //人脸样本的特征值
	CvMat *pEigVectorMat =cvCreateMat(min(pDataMat.rows,pDataMat.cols),pDataMat.cols,CV_32FC1);  //人脸样本的特征向量
	CvMat temp =pDataMat;
	cvCopy(&temp,pData);   //将Mat类型的图像矩阵转换成CvMat类型
	cvCalcPCA( pData, pAvgMat, pEigValueMat, pEigVectorMat, CV_PCA_DATA_AS_ROW );   //计算出平均脸,特征值,特征向量
	CvMat *pEigResults1 =cvCreateMat(pDataMat.rows,50,CV_32FC1);   //选取前50个特征向量
	CvMat *pEigResults2 =cvCreateMat(pDataMat.rows,100,CV_32FC1);   //选取前100个特征向量
	CvMat *pEigResults3 =cvCreateMat(pDataMat.rows,150,CV_32FC1); //选取前150个特征向量
	cvProjectPCA( pData,pAvgMat,pEigVectorMat,pEigResults1);  
	cvProjectPCA( pData,pAvgMat,pEigVectorMat,pEigResults2); 
	cvProjectPCA( pData,pAvgMat,pEigVectorMat,pEigResults3);   //计算PCA变换后的投影系数(降维的人脸样本) 系数个数=特征向量个数
	CvMat *pReconMat1=cvCreateMat(pDataMat.rows,pDataMat.cols,CV_32FC1);
	CvMat *pReconMat2=cvCreateMat(pDataMat.rows,pDataMat.cols,CV_32FC1);
	CvMat *pReconMat3=cvCreateMat(pDataMat.rows,pDataMat.cols,CV_32FC1);
	cvBackProjectPCA( pEigResults1,pAvgMat,pEigVectorMat,pReconMat1); 
	cvBackProjectPCA( pEigResults2,pAvgMat,pEigVectorMat,pReconMat2); 
	cvBackProjectPCA( pEigResults3,pAvgMat,pEigVectorMat,pReconMat3);    //计算所有经过PCA变换后的重构人脸矩阵

	Mat a(pAvgMat,true);
	Mat pAvg =NormImage_0_255(a.row(0)).reshape(1, pFrameMat[0].rows);
	IplImage imgAvgTmp = pAvg;
    IplImage *pAvgImage = cvCloneImage(&imgAvgTmp);  //将平均脸向量转换成IplImage型的图像

	Mat b(pEigVectorMat,true);
	Mat pEig1 =NormImage_0_255(b.row(0).reshape(1,pFrameMat[0].rows));
	Mat pEig2 =NormImage_0_255(b.row(1).reshape(1,pFrameMat[0].rows));
	IplImage imgEigTmp1 = pEig1;
	IplImage imgEigTmp2 = pEig2;
	IplImage *pEigImage1 = cvCloneImage(&imgEigTmp1);  //将第一个主成分脸转换成IplImage型的图像
	IplImage *pEigImage2 = cvCloneImage(&imgEigTmp2); //将第二个主成分脸转换成IplImage型的图像

	Mat c(pReconMat1,true);
	Mat pRecon1 =NormImage_0_255(c.row(0).reshape(1,pFrameMat[0].rows));
	IplImage imgRecTmp1 =pRecon1;
	IplImage *pReconImage1 = cvCloneImage(&imgRecTmp1); //选取50个特征向量重构第一个人脸样本的图像
	Mat d(pReconMat2,true);
	Mat pRecon2 =NormImage_0_255(d.row(0).reshape(1,pFrameMat[0].rows));
	IplImage imgRecTmp2 =pRecon2;
	IplImage *pReconImage2 = cvCloneImage(&imgRecTmp2);    //选取100个特征向量重构第一个人脸样本的图像
	Mat h(pReconMat3,true);
	Mat pRecon3 =NormImage_0_255(h.row(0).reshape(1,pFrameMat[0].rows));
	IplImage imgRecTmp3 =pRecon3;
	IplImage *pReconImage3 = cvCloneImage(&imgRecTmp3);    //选取150个特征向量重构第一个人脸样本的图像

	CvSVMParams params;
	params.svm_type    = CvSVM::C_SVC;
    //params.kernel_type = CvSVM::LINEAR;  //线性核函数
	params.kernel_type = CvSVM::RBF;   //径向基核函数
    params.term_crit   = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6); // 迭代条件
	CvSVM SVM;
	SVM.train(pEigResults1,&labelsMat,NULL,NULL,params);
	Mat e(pEigResults1,true);    
	float reponse =SVM.predict(e.row(60));
	cout<<"分类前样本所属类别:"<<12<<endl;     
	cout<<"分类前样本所属类别:"<<reponse<<endl;   //用支持向量机分类器对测试样本进行分类,显示分类标签号

	cvShowImage("原始人脸图像",pImage);
	cvShowImage("平均脸图像",pAvgImage);  
	cvShowImage("主成分1人脸图像",pEigImage1); 
	cvShowImage("主成分2人脸图像",pEigImage2); 
	cvShowImage("重构人脸图像1",pReconImage1); 
	cvShowImage("重构人脸图像2",pReconImage2); 
	cvShowImage("重构人脸图像3",pReconImage3);  //显示人脸图像

	cvWaitKey(0);

	cvReleaseImage(&pImage);
	cvReleaseImage(&pAvgImage);
	cvReleaseImage(&pEigImage1);  
	cvReleaseImage(&pEigImage2); 
	cvReleaseImage(&pReconImage1); 
	cvReleaseImage(&pReconImage2);  
	cvReleaseImage(&pReconImage3);  //释放内存
	cvDestroyWindow("原始人脸图像");
	cvDestroyWindow("平均脸图像");
	cvDestroyWindow("主成分1人脸图像"); 
	cvDestroyWindow("主成分2人脸图像");  
	cvDestroyWindow("重构人脸图像1");   
	cvDestroyWindow("重构人脸图像2");  
	cvDestroyWindow("重构人脸图像3");    //销毁窗口

	return 0;
}

	


//--将样本矩阵转换成行向量,把所有样本人脸转换成矩阵--//
Mat ReadFaces(const vector<Mat>&pSrcImage,int pType)
{
	size_t n =pSrcImage.size();  //获取样本个数
	if(n==0) return Mat();
	size_t pDim =pSrcImage[0].total();  //获取样本维数

	Mat pData =Mat(n,pDim,pType);  //建n行pData列空矩阵

	for(int i=0;i<n;i++)
	{
		if(pSrcImage[i].empty()) 
            {
            string error_message = format("Image number %d was empty, please check your input data.", i);
            CV_Error(CV_StsBadArg, error_message);
            }
        // 确保数据能被reshape
        if(pSrcImage[i].total() != pDim) 
            {
            string error_message = format("Wrong number of elements in matrix #%d! Expected %d was %d.", i, pDim, pSrcImage[i].total());
            CV_Error(CV_StsBadArg, error_message);
            }

		Mat pRowData =pData.row(i);
		if(pSrcImage[i].isContinuous())
		{
			pSrcImage[i].reshape(1,1).convertTo(pRowData,pType,1,0);
		}
		else
		{
			pSrcImage[i].clone().reshape(1,1).convertTo(pRowData,pType,1,0);
		}
	}

	return pData;

}

//--将多个样本人脸转换成向量--//
vector<Mat> LoadFacesSample()
{
	
	vector<Mat> pImageMat;
	for(int i=1;i<=40;i++)
	{
		for(int j=1;j<=5;j++)
		{
			sprintf(adr,"F:\\人脸识别\\ORL人脸数据库\\s%d\\%d.bmp",i,j);
			pImageMat.push_back(imread(adr,IMREAD_GRAYSCALE));
		}
	}
	return pImageMat;
}


//--将图像归一化为8位深度的图像--//
Mat NormImage_0_255(const Mat&pFrame)
{
	Mat pDst;
	switch(pFrame.channels())
	{

	case 1:
		normalize(pFrame,pDst,0,255,NORM_MINMAX,CV_8UC1);
		break;
	case 3:
		normalize(pFrame,pDst,0,255,NORM_MINMAX,CV_8UC3);
		break;
	default:
		pFrame.copyTo(pDst);
		break;
	}
	return pDst;

}

猜你喜欢

转载自blog.csdn.net/jyy555555/article/details/79833381
今日推荐