Gabor的OpenCV代码

最近弄人脸识别,用到Gabor卷积核,但网上的代码似乎没有和我心意的,于是参考了自己写了下!参考了 Zhou Mian以及matlab的Gabor实现代码的代码。虽然OpenCV的imporc下面有个gabor.cpp,但那个是一般形式的公式,不是用来做人脸识别的,可以参考文献A review on Gabor wavelets for face recognition,又说到。上代码和链接地址!下载地址~

   目前代码未经过更多的测试,不少功能为加入,但可以满足许多人的使用和参考了吧,很多人肯定非常非常需要,先开源下,欢迎指出错误之处。

#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;
};

#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左右,但没看到他们描述过卷积核的大小。

Gabor的OpenCV代码_第1张图片

Gabor的OpenCV代码_第2张图片

Gabor的OpenCV代码_第3张图片

你可能感兴趣的:(Gabor的OpenCV代码)