二维Gabor小波核定义如下:
根据上述定义式,可以编写代码实现:
// *****************************************
// Copyright (c) 2016 Jingshuang Hu
// @filename:GaborFeature.cpp
// @datetime:2016.06.20
// @author:hjs
// @e-mail:jingshuang_hu@163.com
// @blog:http://blog.csdn.net/hujingshuang
// @GitHub:https://github.com/hujingshuang
// *****************************************
// φ_uv(z) = (|K_uv| ^ 2 / (sigma ^ 2)) * exp(-(|K_uv|^2 * |z|^2) / (2 * sigma^2)) * (exp(i * K_uv) - exp(-sigma^2 / 2))
// K_uv = K_v * exp(i * Phi_u) //Phi_u ---> φ_u
// K_v = K_max / (f ^ v)
// Phi_u = u * pi / 8
// K_max = pi / 2
// f = sqrt(2)
// sigma = 2 * pi
void GaborFeature(const Mat img)
{
assert(img.channels() == 1); //single channel
double sigma = 2 * CV_PI;
double f = sqrt(2.0);
double K_max = CV_PI / 2;
for (int v = 0; v < 5; ++v) // scale
{
for (int u = 0; u < 8; ++u) // orientation
{
int mask_width = cvRound(6 * sigma * pow(f, v) / K_max) + 1; //width of gabor filter
double Phi_u = CV_PI * u / 8;
double K_v = K_max / pow(f, v);
Mat imgMaskReal = Mat::zeros(mask_width, mask_width, CV_64FC1);
Mat imgMaskIm = Mat::zeros(mask_width, mask_width, CV_64FC1);
Mat imgReal, imgIm, imgMac;
for (int i = 0; i < mask_width; ++i)
{
for (int j = 0; j < mask_width; ++j)
{
int x = i - (mask_width - 1) / 2; // offset
int y = j - (mask_width - 1) / 2;
double K_uv = K_v * (cos(Phi_u) * x + sin(Phi_u) * y);
double part1 = ((K_v * K_v) / (sigma * sigma)) * exp(-(K_v * K_v) * (x * x + y * y) / (2 * sigma * sigma));
double part2 = cos(K_uv) - exp(-sigma * sigma / 2);
double part3 = sin(K_uv);
double realPart = part1 * part2; // real part
double imPart = part1 * part3; // imaginary part
imgMaskReal.at<double>(i, j) = realPart;
imgMaskIm.at<double>(i, j) = imPart;
}
}
#define GABOR_MODE 0 // switch one of gabor mode
#if GABOR_MODE == 1
filter2D(img, imgReal, CV_32F, imgMaskReal, Point((mask_width - 1) / 2, (mask_width - 1) / 2)); // real filter
Mat imgDst(imgReal);
#elif GABOR_MODE == 2
filter2D(img, imgIm, CV_32F, imgMaskIm, Point((mask_width - 1) / 2, (mask_width - 1) / 2)); // imaginary filter
Mat imgDst(imgIm);
#else
// magnitude filter
filter2D(img, imgReal, CV_32F, imgMaskReal, Point((mask_width - 1) / 2, (mask_width - 1) / 2));
filter2D(img, imgIm, CV_32F, imgMaskIm, Point((mask_width - 1) / 2, (mask_width - 1) / 2));
cv::pow(imgReal, 2, imgReal);
cv::pow(imgIm, 2, imgIm);
cv::add(imgReal, imgIm, imgMac);
cv::pow(imgMac, 0.5, imgMac);
Mat imgDst(imgMac);
#endif
Mat imgGabor;
normalize(imgDst, imgDst, 255, 0, NORM_MINMAX); // normalize value of pixel from 0 to 255
convertScaleAbs(imgDst, imgGabor, 1, 0 ); // 8-bit unsigned integers
imshow("gabor response", imgGabor); waitKey(0); // show the image
} // end of for
} // end of for
} // end of function
好的,代码就是酱紫啦。下面来看看一些效果吧。
二维gabor响应的实部(也就是实部的5 x 8 = 40个滤波器):
以上就是5个尺度,8个方向上的二维gabor滤波器响应的实部,我们用这40个滤波器来与图像进行卷积,下面我们以这位92 x 112尺寸且一本正经的帅小哥为例。
ok,到此为止我们已经提取到了一幅图像的gabor特征了。不过维数为92 x 112 x 40维,网上有好多降维的方法,也可以和LBP结合起来提取特征来达到降维的目的。
参考文献:
[1] 牟海军, 基于Gabor特征的人脸识别方法[D], 2013.