基于Gabor+PCA+SVM的性别识别(2)

基于上一篇博文提取的人脸图像,本文运用Gabor小波对人脸图像提取特征,再运用PCA对其降维处理,最后用SVM训练一个性别分类器。这里不再深入介绍Gabor小波和PCA的原理。很多博文讲解的很详细。

可参考:http://blog.csdn.net/jinshengtao/article/details/17797641

           http://www.cnblogs.com/emouse/p/3611256.html

           http://blog.csdn.net/yutianzuijin/article/details/10823985

 

基于Gabor+PCA+SVM的性别识别(1):  http://www.cnblogs.com/xiaoming123abc/p/5078411.html

基于Gabor+PCA+SVM的性别识别(3):  http://www.cnblogs.com/xiaoming123abc/p/5079116.html 

这里只简单说一下自己的理解:

一维Gabor小波的实质是一个带通滤波器,具有频率选择性。

对于二维Gabor小波,它不仅具有频率选择性,还有频率方向的选择性;这时,可以理解Gabor是个空域的模板,匹配与模板频率大小和频率方向相同的成分。也就是说,图像中的频率大小和频率方向与该Gabor的频率大小和频率方向相同,则经过Gabor滤波后,响应会比较大,这样就把特征提取出来了。

二维Gabor小波是由二维Gabor滤波器函数 G(ω,θ)(Gabor滤波器有很多参数,为了方便理解,这里只写了两个)通过尺度伸缩和旋转生成的一组滤波器,其参数的选择通常在频率空间进行考虑。为了对一幅图像的整个频域进行采样,可以采用具有多个中心频率和方向的Gabor滤波器组来描述图像。参数 ω,θ的不同选择分别体现了二维Gabor小波在频率和方向空间的采样方式。

整个频率空间可以是0到无穷大的任意值,由于一幅图像实际的频率分布是有限的范围,所以,对于图像的局部特征来说,参数 ω只能在一个很小的范围内选取。由于图像的纹理是随机分布的, θ的取值范围为0到2*pi ,考虑到Gabor滤波器的对称性, 的实际取值范围为0到pi 。本文采用5个中心频率和8个方向组成40个Gabor滤波器。

 

基于Gabor+PCA+SVM的性别识别(2)_第1张图片

40个Gabor滤波器,由于每一个Gabor滤波器都由实部和虚部组成。所以一共有80个Gabor模板。

Gabor小波提取特征的过程就是拿着这些Gabor模板与图像卷积,得出40个实部响应图和40个实部响应图。实部与虚部合并,形成40个总响应图(18X21),最后把每一个响应图(18X21)拉直,既18X21的矩阵变成1X378的向量(这只是本人用的方法,其他方法也应该可以)。这样每幅人脸(18X21)的特征个数(40X378),运用PCA对(40X378)降维。

 

基于Gabor+PCA+SVM的性别识别(2)_第2张图片

 

 

PCA

PCA(Principal Component Analysis)是一种常用的数据分析方法。PCA通过线性变换将原始数据变换为一组各维度线性无关的表示,可用于提取数据的主要特征分量,常用于高维数据的降维。

PCA的算法步骤:

设有m条n维数据。

1)   将原始数据按列组成n行m列矩阵X;

2)   将X的每一行(代表一个属性字段)进行零均值化,即减去这一行的均值;

3)   求出协方差矩阵 ;求出协方差矩阵的特征值及对应的特征向量;

4)   将特征向量按对应特征值大小从上到下按行排列成矩阵,取前k行组成矩阵P;

5)   Y=PX即为降维到k维后的数据

本程序实现了Gabor特征提取,PCA降维,SVM分类。由于每一幅图像要与80个Gabor模板卷积。man样本与woman样本一共600多个。可能需要运行一段时间,最后得到一个SVM分类器。

main.cpp

#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
#include <opencv2/ml/ml.hpp>
#include "GaborFR.h"

using namespace std;
using namespace cv;

#define manNO 409     //man样本个数
#define womanNO 287    //woman样本个数
int iSize=20;//  Gabor的scale
int main()
{
    	int DescriptorDim=200;  
		
		string ImgName;//图片名(绝对路径)
		ifstream finMan("man.txt");//man样本图片的文件名列表
		ifstream finWoman("woman.txt");//woman样本图片的文件名列表
		 Mat ROI;
		Mat Gabor_feature;
		Mat PCA_feature;
		Mat sampleFeatureMat;//所有训练样本的特征向量组成的矩阵,行数等于所有样本的个数,列数等于Gabor描述子维数	
		Mat sampleLabelMat; //训练样本的类别向量,行数等于所有样本的个数,列数等于1;1表示man,-1表示woman
		Vector<Mat> GaborReal;
		Vector<Mat> GaborImag;
	//生成Gabor 模板
		for(int i=0;i<8;i++)
	        {
		      for(int j=0;j<5;j++)
		     {
			   Mat M1= GaborFR::getRealGaborKernel(Size(iSize,iSize),
				                                 2*CV_PI,
												 i*CV_PI/8+CV_PI/2,
												 j,
												 1);
		       Mat M2 = GaborFR::getImagGaborKernel(Size(iSize,iSize),
				                                 2*CV_PI,
												 i*CV_PI/8+CV_PI/2,
												 j,
												 1);   
			   GaborReal.push_back(M1);
			   GaborImag.push_back(M2);

			}
		}
	//依次读取man样本图片
		for(int num=0; num<manNO && getline(finMan,ImgName); num++)
		{
	        cout<<"处理:"<<ImgName<<endl;
		    ImgName = "D:\\Mycode\\mantrain_cut\\" + ImgName+".png";
		    ROI= imread(ImgName,0);//读取图片
            if(ROI.data ==0)
	        {
              printf("[error] 没有图片\n");
              return -5;
            }
       //Gabor变换提取特征*************************
			for(int i=0;i<8;i++)
	        {
		      for(int j=0;j<5;j++)
		     {
			  Mat outR,outI,M_Magnitude;
		
			 GaborFR::getFilterRealImagPart(ROI,GaborReal[i*5+j],GaborImag[i*5+j],outR,outI);
	         M_Magnitude=GaborFR::getMagnitude(outR,outI);
		     //cartToPolar( outR, outI, M_Magnitude, Angle, false );   //计算幅值和相角
			  normalize(M_Magnitude,M_Magnitude,0,1,CV_MINMAX,CV_32F);
			 Mat line= M_Magnitude.reshape(0,1);
			
		    Gabor_feature.push_back(line);
		}
	  }
       //PCA降维************************************************************
            PCA pca(Gabor_feature, cv::Mat(), CV_PCA_DATA_AS_ROW,5);
	        Mat dst=pca.project(Gabor_feature) ;
	        Mat line =dst.reshape(0,1);

            //处理第一个样本时初始化特征向量矩阵和类别矩阵,因为只有知道了特征向量的维数才能初始化特征向量矩阵
			if( 0 == num )
			{
			//初始化所有训练样本的特征向量组成的矩阵,行数等于所有样本的个数,列数等于Gabor降维后描述子维数sampleFeatureMat
			sampleFeatureMat = Mat::zeros(manNO+womanNO, DescriptorDim, CV_32FC1);
			//初始化训练样本的类别向量,行数等于所有样本的个数,列数等于1;1表示有人,0表示无人
			sampleLabelMat = Mat::zeros(manNO+womanNO, 1, CV_32FC1);
			}
			//将计算好的Gabor降维后描述子复制到样本特征矩阵sampleFeatureMat
		    for(int i=0; i<DescriptorDim; i++) 
			sampleFeatureMat.at<float>(num,i) = line.at<float>(0,i);//第num个样本的特征向量中的第i个元素
			sampleLabelMat.at<float>(num,0) = 1;//man样本类别为1
		}

       //依次读取woman样本图片,生成Gabor描述子并降维
		for(int num=0; num<womanNO && getline(finWoman,ImgName); num++)
		{
			cout<<"处理:"<<ImgName<<endl;
		    ImgName = "D:\\Mycode\\womantrain_cut\\" + ImgName+".png";
		    ROI= imread(ImgName,0);//读取图片
            if(ROI.data ==0)
	        {
              printf("[error] 没有图片\n");
              return -5;
            }
			//Gabor变换提取特征*************************
			for(int i=0;i<8;i++)
	        {
		      for(int j=0;j<5;j++)
		     {
			   
			
			Mat outR,outI,M_Magnitude;

			GaborFR::getFilterRealImagPart(ROI,GaborReal[i*5+j],GaborImag[i*5+j],outR,outI);
	        M_Magnitude=GaborFR::getMagnitude(outR,outI);
			//cartToPolar( outR, outI, M_Magnitude, Angle, false );   //计算幅值和相角
			normalize(M_Magnitude,M_Magnitude,0,1,CV_MINMAX,CV_32F);
			Mat line= M_Magnitude.reshape(0,1);	
		    Gabor_feature.push_back(line);

		   }
	      }

//PCA降维************************************************************
            PCA pca( Gabor_feature, cv::Mat(), CV_PCA_DATA_AS_ROW,5);
	        Mat dst=pca.project(Gabor_feature) ;
	        Mat line =dst.reshape(0,1);

			for(int i=0; i<DescriptorDim; i++)
			sampleFeatureMat.at<float>(num+manNO,i) = line.at<float>(0,i);//第PosSamNO+num个样本的特征向量中的第i个元素
		
			sampleLabelMat.at<float>(num+manNO,0) = -1;//woman样本类别为-1
		}

		//训练SVM分类器
		//迭代终止条件,当迭代满1000次或误差小于FLT_EPSILON时停止迭代
		CvSVM svm;          //SVM分类器
		CvTermCriteria criteria = cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 1000, FLT_EPSILON);
		//SVM参数:SVM类型为C_SVC;线性核函数;松弛因子C=0.01
		CvSVMParams param(CvSVM::C_SVC, CvSVM::LINEAR, 0, 1, 0, 0.01, 0, 0, 0, criteria);
		cout<<"开始训练SVM分类器"<<endl;
		svm.train(sampleFeatureMat, sampleLabelMat, Mat(), Mat(), param);//训练分类器
		cout<<"训练完成"<<endl;
		svm.save("SVM_PCA.xml");//将训练好的SVM模型保存为xml文件
	     waitKey();//注意:imshow之后必须加waitKey,否则无法显示图像
	    system("pause");
		
}

 GarborFR.hpp 

#include "opencv2\opencv.hpp"
#include <vector>
using namespace std;
using namespace cv;
class GaborFR
{
public:
	GaborFR();
	static Mat	getImagGaborKernel(Size ksize, double sigma, double theta, 
									double nu,double gamma=1, int ktype= CV_32F);
	static Mat	getRealGaborKernel( Size ksize, double sigma, double theta, 
									double nu,double gamma=1, int ktype= CV_32F);
	static Mat	getPhase(Mat &real,Mat &imag);
	static Mat	getMagnitude(Mat &real,Mat &imag);
	static void getFilterRealImagPart(Mat& src,Mat& real,Mat& imag,Mat &outReal,Mat &outImag);
	static Mat	getFilterRealPart(Mat& src,Mat& real);
	static Mat	getFilterImagPart(Mat& src,Mat& imag);
  /*
	void		Init(Size ksize=Size(19,19), double sigma=2*CV_PI,
					double gamma=1, int ktype=CV_32FC1);
  */
private:
	//vector<Mat> gaborRealKernels;
	//vector<Mat> gaborImagKernels;
	bool isInited;
};

  Gabor.cpp

//#include "StdAfx.h"
#include "GaborFR.h"
GaborFR::GaborFR()
{
	isInited = false;
}
/*
void GaborFR::Init(Size ksize, double sigma,double gamma, int ktype)
{
	gaborRealKernels.clear();
	gaborImagKernels.clear();
	double mu[8]={0,1,2,3,4,5,6,7};
	double nu[5]={0,1,2,3,4};
	int i,j;
	for(i=0;i<5;i++)
	{
		for(j=0;j<8;j++)
		{
			gaborRealKernels.push_back(getRealGaborKernel(ksize,sigma,mu[j]*CV_PI/8,nu[i],gamma,ktype));
			gaborImagKernels.push_back(getImagGaborKernel(ksize,sigma,mu[j]*CV_PI/8,nu[i],gamma,ktype));
		}
	}
	isInited = true;
}

*/
Mat GaborFR::getImagGaborKernel(Size ksize, 
	                           double sigma, 
							   double theta, 
							   double nu,
							   double gamma, 
							   int ktype)   
{
	double	sigma_x		= sigma;
	double	sigma_y		= sigma/gamma;
	int		nstds		= 3;
	double	kmax		= CV_PI/2;
	double	f			= cv::sqrt(2.0);
	int xmin, xmax, ymin, ymax;
	double c = cos(theta), s = sin(theta);
	if( ksize.width > 0 )
	{
		xmax = ksize.width/2;
	}
	else//这个和matlab中的结果一样,默认都是19 !
	{
		xmax = cvRound(std::max(fabs(nstds*sigma_x*c), fabs(nstds*sigma_y*s)));
	}
	if( ksize.height > 0 )
	{
		ymax = ksize.height/2;
	}
	else
	{
		ymax = cvRound(std::max(fabs(nstds*sigma_x*s), fabs(nstds*sigma_y*c)));
	}
	xmin = -xmax;
	ymin = -ymax;
	CV_Assert( ktype == CV_32F || ktype == CV_64F );
	float*	pFloat;
	double*	pDouble;
	Mat kernel(ymax - ymin + 1, xmax - xmin + 1, ktype); //初始化gabor的尺寸
	double k		=	kmax/pow(f,nu);
	double scaleReal=	k*k/sigma_x/sigma_y;
	for( int y = ymin; y <= ymax; y++ )
	{
		if( ktype == CV_32F )
		{
			pFloat = kernel.ptr<float>(ymax-y);
		}
		else
		{
			pDouble = kernel.ptr<double>(ymax-y);
		}
		for( int x = xmin; x <= xmax; x++ )
		{
			double xr = x*c + y*s;
			double v = scaleReal*exp(-(x*x+y*y)*scaleReal/2);
			double temp=sin(k*xr);
			v	=  temp*v;
			if( ktype == CV_32F )
			{
				pFloat[xmax - x]= (float)v;
			}
			else
			{
				pDouble[xmax - x] = v;
			}
		}
	}
	return kernel;
}
//sigma一般为2*pi
Mat GaborFR::getRealGaborKernel( Size ksize,
	                            double sigma,
								double theta, 
	                            double nu,
								double gamma, 
								int ktype)
{
	
	double	sigma_x		= sigma;
	double	sigma_y		= sigma/gamma;
	int		nstds		= 3;
	double	kmax		= CV_PI/2;
	double	f			= cv::sqrt(2.0);
	int xmin, xmax, ymin, ymax;
	double c = cos(theta), s = sin(theta);
	if( ksize.width > 0 )
	{
		xmax = ksize.width/2;
	}
	else//这个和matlab中的结果一样,默认都是19 !
	{
		xmax = cvRound(std::max(fabs(nstds*sigma_x*c), fabs(nstds*sigma_y*s)));
	}

	if( ksize.height > 0 )
		ymax = ksize.height/2;
	else
		ymax = cvRound(std::max(fabs(nstds*sigma_x*s), fabs(nstds*sigma_y*c)));
	xmin = -xmax;
	ymin = -ymax;
	CV_Assert( ktype == CV_32F || ktype == CV_64F );
	float*	pFloat;
	double*	pDouble;
	Mat kernel(ymax - ymin + 1, xmax - xmin + 1, ktype);
	double k		=	kmax/pow(f,nu);
	double exy		=	sigma_x*sigma_y/2;
	double scaleReal=	k*k/sigma_x/sigma_y;
	int	   x,y;
	for( y = ymin; y <= ymax; y++ )
	{
		if( ktype == CV_32F )
		{
			pFloat = kernel.ptr<float>(ymax-y);
		}
		else
		{
			pDouble = kernel.ptr<double>(ymax-y);
		}
		for( x = xmin; x <= xmax; x++ )
		{
			double xr = x*c + y*s;
			double v = scaleReal*exp(-(x*x+y*y)*scaleReal/2);
			double temp=cos(k*xr) - exp(-exy);
			v	=	temp*v;
			if( ktype == CV_32F )
			{
				pFloat[xmax - x]= (float)v;
			}
			else
			{
				pDouble[xmax - x] = v;
			}
		}
	}
	return kernel;
}


Mat GaborFR::getMagnitude(Mat &real,Mat &imag)
{
	CV_Assert(real.type()==imag.type());
	CV_Assert(real.size()==imag.size());
	int ktype=real.type();
	int row = real.rows,col = real.cols;
	int i,j;
	float*	pFloat,*pFloatR,*pFloatI;
	double*	pDouble,*pDoubleR,*pDoubleI;
	Mat		kernel(row, col, real.type());
	for(i=0;i<row;i++)
	{
		if( ktype == CV_32FC1 )
		{
			pFloat = kernel.ptr<float>(i);
			pFloatR= real.ptr<float>(i);
			pFloatI= imag.ptr<float>(i);
		}
		else
		{
			pDouble = kernel.ptr<double>(i);
			pDoubleR= real.ptr<double>(i);
			pDoubleI= imag.ptr<double>(i);
		}
		for(j=0;j<col;j++)
		{
			if( ktype == CV_32FC1 )
			{
				pFloat[j]= sqrt(pFloatI[j]*pFloatI[j]+pFloatR[j]*pFloatR[j]);
			}
			else
			{
				pDouble[j] = sqrt(pDoubleI[j]*pDoubleI[j]+pDoubleR[j]*pDoubleR[j]);
			}
		}
	}
	return kernel;
}
Mat GaborFR::getPhase(Mat &real,Mat &imag)
{
	CV_Assert(real.type()==imag.type());
	CV_Assert(real.size()==imag.size());
	int ktype=real.type();
	int row = real.rows,col = real.cols;
	int i,j;
	float*	pFloat,*pFloatR,*pFloatI;
	double*	pDouble,*pDoubleR,*pDoubleI;
	Mat		kernel(row, col, real.type());
	for(i=0;i<row;i++)
	{
		if( ktype == CV_32FC1 )
		{
			pFloat = kernel.ptr<float>(i);
			pFloatR= real.ptr<float>(i);
			pFloatI= imag.ptr<float>(i);
		}
		else
		{
			pDouble = kernel.ptr<double>(i);
			pDoubleR= real.ptr<double>(i);
			pDoubleI= imag.ptr<double>(i);
		}
		for(j=0;j<col;j++)
		{
			if( ktype == CV_32FC1 )
			{
// 				if(pFloatI[j]/(pFloatR[j]+pFloatI[j]) > 0.99)
// 				{
// 					pFloat[j]=CV_PI/2;
// 				}
// 				else
// 				{
//					pFloat[j] = atan(pFloatI[j]/pFloatR[j]);
				pFloat[j] = asin(pFloatI[j]/sqrt(pFloatR[j]*pFloatR[j]+pFloatI[j]*pFloatI[j]));
/*				}*/
//				pFloat[j] = atan2(pFloatI[j],pFloatR[j]);
			}//CV_32F
			else
			{
				if(pDoubleI[j]/(pDoubleR[j]+pDoubleI[j]) > 0.99)
				{
					pDouble[j]=CV_PI/2;
				}
				else
				{
					pDouble[j] = atan(pDoubleI[j]/pDoubleR[j]);
				}
//				pDouble[j]=atan2(pDoubleI[j],pDoubleR[j]);
			}//CV_64F
		}
	}
	return kernel;
}
Mat GaborFR::getFilterRealPart(Mat& src,Mat& real)
{
	//CV_Assert(real.type()==src.type());
	Mat dst;
	Mat kernel;
	flip(real,kernel,-1);//中心镜面
//	filter2D(src,dst,CV_32F,kernel,Point(-1,-1),0,BORDER_CONSTANT);
	filter2D(src,dst,CV_32F,kernel,Point(-1,-1),0,BORDER_REPLICATE);
	return dst;
}
Mat GaborFR::getFilterImagPart(Mat& src,Mat& imag)
{
	//CV_Assert(imag.type()==src.type());
	Mat dst;
	Mat kernel;
	flip(imag,kernel,-1);//中心镜面
//	filter2D(src,dst,CV_32F,kernel,Point(-1,-1),0,BORDER_CONSTANT);
	filter2D(src,dst,CV_32F,kernel,Point(-1,-1),0,BORDER_REPLICATE);
	return dst;
}



void GaborFR::getFilterRealImagPart(Mat& src,Mat& real,Mat& imag,Mat &outReal,Mat &outImag)
{
	outReal=getFilterRealPart(src,real);
	outImag=getFilterImagPart(src,imag);
}

  本人能力有限,错误在所难免。敬请赐教

 程序下载:http://download.csdn.net/detail/u012507022/9378491

(VS2010+opencv2.4.11)

你可能感兴趣的:(基于Gabor+PCA+SVM的性别识别(2))