1. 程式人生 > >Gabor的用於人臉檢測的OpenCV程式碼

Gabor的用於人臉檢測的OpenCV程式碼

最近弄人臉識別,用到Gabor卷積核,但網上的程式碼似乎沒有和我心意的,於是參考了自己寫了下!參考了Zhou Mian以及matlab的Gabor實現程式碼的程式碼。雖然OpenCV的imporc下面有個gabor.cpp,但那個是一般形式的公式,不是用來做人臉識別的,可以參考文獻A review on Gabor wavelets for face recognition,又說到。上程式碼和連結地址!下載地址~

   目前程式碼未經過更多的測試,不少功能為加入,但可以滿足許多人的使用和參考了吧,很多人肯定非常非常需要,先開源下,歡迎指出錯誤之處。

Gabor.h

#pragma once  
#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);
	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);
}


main

// Win32TestPure.cpp : 定義控制檯應用程式的入口點。
#include "stdafx.h"
#include <vector>
#include <deque>
#include <iomanip>
#include <stdexcept>
#include <string>
#include <iostream>
#include <fstream>
#include <direct.h>//_mkdir()
#include "opencv2\opencv.hpp"
#include "GaborFR.h"
using namespace std;
using namespace cv;
int main()
{ 
	//Mat M = getGaborKernel(Size(9,9),2*CV_PI,u*CV_PI/8, 2*CV_PI/pow(2,CV_PI*(v+2)/2),1,0);
	Mat saveM;
	//s8-4
	//s1-5
	//s1中年男人
	Mat I=imread("H:\\pic\\s1-5.bmp",-1);
	normalize(I,I,1,0,CV_MINMAX,CV_32F);
	Mat showM,showMM;Mat M,MatTemp1,MatTemp2;
	Mat line;
	int iSize=50;//如果數值比較大,比如50則接近論文中所述的情況了!估計大小和處理的源影象一樣!
	for(int i=0;i<8;i++)
	{
		showM.release();
		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);
			//加了CV_PI/2才和大部分文獻的圖形一樣,不知道為什麼!
			Mat outR,outI;
			GaborFR::getFilterRealImagPart(I,M1,M2,outR,outI);
//			M=GaborFR::getPhase(M1,M2);
//			M=GaborFR::getMagnitude(M1,M2);
//			M=GaborFR::getPhase(outR,outI);
//			M=GaborFR::getMagnitude(outR,outI);
 //			M=GaborFR::getMagnitude(outR,outI);
// 			MatTemp2=GaborFR::getPhase(outR,outI);
// 			M=outR;
			 M=M1;
			// 		resize(M,M,Size(100,100));
			normalize(M,M,0,255,CV_MINMAX,CV_8U);
			showM.push_back(M);
			line=Mat::ones(4,M.cols,M.type())*255;
			showM.push_back(line);
		}
		showM=showM.t();
		line=Mat::ones(4,showM.cols,showM.type())*255;
		showMM.push_back(showM);
		showMM.push_back(line);
	}
	showMM=showMM.t();
//	bool flag=imwrite("H:\\out.bmp",showMM);
	imshow("saveMM",showMM);waitKey(0);
	return 0;
}//endof   main()



以下圖片可能和程式實際執行結果有點不同,圖片只是示意圖,程式碼暫時沒問題。需要考慮的是iSize大小問題,首先iSize要用奇數,然後大部分文獻iSize都比較大,好像是100左右,但沒看到他們描述過卷積核的大小。