Gabor的用於人臉檢測的OpenCV程式碼
阿新 • • 發佈:2019-01-04
最近弄人臉識別,用到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左右,但沒看到他們描述過卷積核的大小。