一:Gabor滤波器介绍
Gabor滤波器是OpenCV中非常强大一种滤波器,广泛应用在纹理分割、对象检测、图像分维、文档分析、边缘检测、生物特征识别、图像编码与内容描述等方面。Gabor在空间域可以看做是一个特定频率与方向的正弦平面加上一个应用在正弦平面波上的高斯核
在实际计算中,一般情况下会根据输入的theta与lambd的不同,得到一系列的Gabor的滤波器组合,然后把它们的结果相加输出,得到最终的输出结果,在纹理提取,图像分割、纹理分类中特别有用,Gabor滤波器的任意组合提供了非常强大的图像分类能力,被认为是最接近于现代深度学习方式进行图像分类的算法之一。Gabor滤波器应用也非常广泛,几乎从图像处理、分割、分类、对象匹配、人脸识别、文字OCR等领域都有应用。
二:OpenCV中的代码实现
OpenCV中已经实现了Gabor滤波器的核函数生成,有了卷积核函数,一切都好办多啦,通过filter2D卷积函数使用Gabor核即可完成Gabor滤波,Gabor核生成的API函数与参数解释如下:
cv::Mat cv::getGaborKernel( Size ksize, double sigma, double theta,double lambd, double gamma, double psi, int ktype )
{
double sigma_x = sigma;
double sigma_y = sigma/gamma;
int nstds = 3;
int xmin, xmax, ymin, ymax;
double c = cos(theta), s = sin(theta);
if( ksize.width > 0 )
xmax = ksize.width/2;
else
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 );
Mat kernel(ymax - ymin + 1, xmax - xmin + 1, ktype);
double scale = 1;
double ex = -0.5/(sigma_x*sigma_x);
double ey = -0.5/(sigma_y*sigma_y);
double cscale = CV_PI*2/lambd;
for( int y = ymin; y <= ymax; y++ )
for( int x = xmin; x <= xmax; x++ )
{
double xr = x*c + y*s;
double yr = -x*s + y*c;
double v = scale*std::exp(ex*xr*xr + ey*yr*yr)*cos(cscale*xr + psi);
if( ktype == CV_32F )
kernel.at(ymax - y, xmax - x) = (float)v;
else
kernel.at(ymax - y, xmax - x) = v;
}
return kernel;
}
三:使用Gabor filter提取纹理
使用四个gabor filter实现各种纹理提取,代码实现布匹纹理检测、墙体裂纹检测、斑马线检测。先看效果:
1.布匹纹理检测
# include
# include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
cv::Mat cv::getGaborKernel( Size ksize, double sigma, double theta,double lambd, double gamma, double psi, int ktype )
{
double sigma_x = sigma;
double sigma_y = sigma/gamma;
int nstds = 3;
int xmin, xmax, ymin, ymax;
double c = cos(theta), s = sin(theta);
if( ksize.width > 0 )
xmax = ksize.width/2;
else
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 );
Mat kernel(ymax - ymin + 1, xmax - xmin + 1, ktype);
double scale = 1;
double ex = -0.5/(sigma_x*sigma_x);
double ey = -0.5/(sigma_y*sigma_y);
double cscale = CV_PI*2/lambd;
for( int y = ymin; y <= ymax; y++ )
for( int x = xmin; x <= xmax; x++ )
{
double xr = x*c + y*s;
double yr = -x*s + y*c;
double v = scale*std::exp(ex*xr*xr + ey*yr*yr)*cos(cscale*xr + psi);
if( ktype == CV_32F )
kernel.at(ymax - y, xmax - x) = (float)v;
else
kernel.at(ymax - y, xmax - x) = v;
}
return kernel;
}
int main()
{
Mat src = imread("F://ZQX//nor2.jpg", IMREAD_GRAYSCALE);
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
Mat src_f;
src.convertTo(src_f, CV_32F);
// 参数初始化
int kernel_size = 3;
double sigma = 1.0, lambd = CV_PI/8, gamma = 0.5, psi = 0;
vector destArray;
double theta[4];
Mat temp;
// theta 法线方向
theta[0] = 0;
theta[1] = CV_PI/4;
theta[2] = CV_PI / 2;
theta[3] = CV_PI - CV_PI / 4;
// gabor 纹理检测器,可以更多,
// filters = number of thetas * number of lambd
// 这里lambad只取一个值,所有4个filter
for (int i = 0; i<4; i++)
{
Mat kernel1;
Mat dest;
kernel1 = cv::getGaborKernel(cv::Size(kernel_size, kernel_size), sigma, theta[i], lambd, gamma, psi, CV_32F);
filter2D(src_f, dest, CV_32F, kernel1);
destArray.push_back(dest);
}
// 显示与保存
Mat dst1, dst2, dst3, dst4;
convertScaleAbs(destArray[0], dst1);
imwrite("gabor1.jpg", dst1);
convertScaleAbs(destArray[1], dst2);
imwrite("gabor2.jpg", dst2);
convertScaleAbs(destArray[2], dst3);
imwrite("gabor3.jpg", dst3);
convertScaleAbs(destArray[3], dst4);
imwrite("gabor4.jpg", dst4);
// 合并结果
add(destArray[0], destArray[1], destArray[0]);
add(destArray[2], destArray[3], destArray[2]);
add(destArray[0], destArray[2], destArray[0]);
Mat dst;
convertScaleAbs(destArray[0], dst, 0.2, 0);
// 二值化显示
Mat gray, binary;
// cvtColor(dst, gray, COLOR_BGR2GRAY);
threshold(dst, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
imshow("result", dst);
imshow("binary", binary);
imwrite("result_01.png", binary);
waitKey(0);
return 0;
}