Gabor滤波简介与Opencv中的实现及参数变化实验

声明:本篇文章为转载,目的是便于以后查找学习

Gabor滤波是一种非常常见的特征提取算法,在人脸识别等领域有着很广泛的应用,在这里我主要介绍一下Gabor滤波器的公式及Opencv下的代码实现,以及我做的一些参数变化的实验。

一、Gabor滤波简介


注意,这里我介绍的Gabor算法与在人脸识别中使用的Gabor算法貌似是不太相同的,具体内容我没有深入了解。 
Gabor滤波的公式如下所示:

其中实数部分为:

虚数部分为: 

 

 这里面的参数: 
(1)x,y分别表示像素坐标位置; 
(2)λ表示滤波的波长; 
(3)θ表示Gabor核函数图像的倾斜角度; 
(4)ψ表示相位偏移量,取值范围是-180~180; 
(5)σ表示高斯函数的标准差; 
(6)γ表示长宽比,决定这Gabor核函数图像的椭圆率。 
这里的参数不了解不要紧,后面我将会针对这些参数进行一系列的实验,直观的展示出这些参数的作用。
 

二、Opencv中Gabor核函数的实现

在Opencv中的给出了实现核函数的代码,如下所示,这里我将我的理解作为注释加入到代码中:

//获取Gabor的核函数,并以Mat的形式返回
//ksize表示核函数窗口大小,sigma,theta,lambd,gamma和psi分别为前面提到的参数
//ktype表示需要获得的核函数矩阵的数据类型
cv::Mat cv::getGaborKernel( Size ksize, double sigma, double theta,
                            double lambd, double gamma, double psi, int ktype )
{
    //获取两个数学遍历sigma_x和sigma_y,方便后面的计算,没有特殊含义
    double sigma_x = sigma;
    double sigma_y = sigma/gamma;

    int nstds = 3;//为后面的当ksize出现负数时计算核函数窗口大小提供参数
    int xmin, xmax, ymin, ymax;
    double c = cos(theta), s = sin(theta);
    //当ksize的width和height没有负数时,取其一半给xmax和ymax
    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 );
    //核函数矩阵,ymax-ymin+1和xmax-xmin+1是为保证核函数矩阵是长和宽都是奇数
    Mat kernel(ymax - ymin + 1, xmax - xmin + 1, ktype);
    double scale = 1;
    //方便计算,可以自己带入到后面的v的计算公式中会发现Gabor滤波器的实数部分的公式
    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;
            //计算公式,Opencv这里获取的是Gabor滤波器的实数部分
            double v = scale*exp(ex*xr*xr + ey*yr*yr)*cos(cscale*xr + psi);
            if( ktype == CV_32F )
                kernel.at<float>(ymax - y, xmax - x) = (float)v;
            else
                kernel.at<double>(ymax - y, xmax - x) = v;
        }

    return kernel;
}

这里Opencv只是获得了Gabor的实数部分,为何没有虚数部分我暂时还不太清楚,如果有人清楚请留言指出,谢谢!

三、Gabor参数实验

1、λλ(波长)变化:

//注意:为了演示方便这里采用的核函数窗口大小比较大,一般情况下不会采用这么大的核函数窗口
//另外,如要保存核函数结果,记得先把图像归一化到0~255以后再保存,否则可能只有黑色
int main()
{
    Mat kernel1 = getGaborKernel(Size(311, 311), 10, 0, 5, 0.5, 0, CV_32F);
    Mat kernel2 = getGaborKernel(Size(311, 311), 10, 0, 10, 0.5, 0, CV_32F);
    Mat kernel3 = getGaborKernel(Size(311, 311), 10, 0, 15, 0.5, 0, CV_32F);
    Mat kernel4 = getGaborKernel(Size(311, 311), 10, 0, 20, 0.5, 0, CV_32F);
    imshow("lambda: 5", kernel1);
    imshow("lambda: 10", kernel2);
    imshow("lambda: 15", kernel3);
    imshow("lambda: 20", kernel4);
    waitKey();
    return 0;
}

è¿éåå¾çæè¿°

可以看出波长越大,黑白相间的间隔越大 
(2)θ变化: 

//注意:角度要转换为弧度
int main()
{
    Mat kernel1 = getGaborKernel(Size(311, 311), 10, 0, 10, 0.5, 0, CV_32F);
    Mat kernel2 = getGaborKernel(Size(311, 311), 10, CV_PI * 0.25, 10, 0.5, 0, CV_32F);
    Mat kernel3 = getGaborKernel(Size(311, 311), 10, CV_PI * 0.5, 10, 0.5, 0, CV_32F);
    Mat kernel4 = getGaborKernel(Size(311, 311), 10, CV_PI * 0.75, 10, 0.5, 0, CV_32F);
    imshow("theta: 0", kernel1);
    imshow("theta: 45", kernel2);
    imshow("theta: 90", kernel3);
    imshow("theta: 135", kernel4);
    waitKey();
    return 0;
}

è¿éåå¾çæè¿°

(3)ψ的变化: 

è¿éåå¾çæè¿°

当ψ为0时以白条为中心,当ψ为180时,以黑条为中心  

(4)σ的变化:

int main()
{
    Mat kernel1 = getGaborKernel(Size(311, 311), 5, 0, 10, 0.5, 0, CV_32F);
    Mat kernel2 = getGaborKernel(Size(311, 311), 10, 0, 10, 0.5, 0, CV_32F);
    Mat kernel3 = getGaborKernel(Size(311, 311), 15, 0, 10, 0.5, 0, CV_32F);
    Mat kernel4 = getGaborKernel(Size(311, 311), 20, 0, 10, 0.5, 0, CV_32F);
    imshow("sigma: 5", kernel1);
    imshow("sigma: 10", kernel2);
    imshow("sigma: 15", kernel3);
    imshow("sigma: 20", kernel4);
    waitKey();
    return 0;
}

è¿éåå¾çæè¿°

可以看出,随着σ的增大,条纹数量越多 
(5)γ的变化: 

int main()
{
    Mat kernel1 = getGaborKernel(Size(311, 311), 10, 0, 10, 0.5, 0, CV_32F);
    Mat kernel2 = getGaborKernel(Size(311, 311), 10, 0, 10, 1.0, 0, CV_32F);
    Mat kernel3 = getGaborKernel(Size(311, 311), 10, 0, 10, 1.5, 0, CV_32F);
    Mat kernel4 = getGaborKernel(Size(311, 311), 10, 0, 10, 2.0, 0, CV_32F);
    imshow("gamma: 0.5", kernel1);
    imshow("gamma: 1.0", kernel2);
    imshow("gamma: 1.5", kernel3);
    imshow("gamma: 2.0", kernel4);
    waitKey();
    return 0;
}

è¿éåå¾çæè¿°

可以看出,随着γγ的增大,核函数图像形状会发生改变,γγ越小,核函数图像会越高,随着其增大,图像会变的越矮。

四、Gabor滤波的使用


再得到Gabor核函数以后,其使用方法就比较简单了,其实就是使用该核函数窗口对图像进行卷积操作,参考小魏的修行路【图像处理】Gabor滤波器中使用Gabor滤波和图像归一化的方法。

注:Opencv中Gabor滤波只使用实数部分,同时wiki中Gabor filter中的介绍和实现示例也同样只使用了实数部分,《基于 Gabor 滤波器的特征抽取技术》一文中提到,Gabor滤波中使用了复数,计算量会比较大,而已经有很多应用只使用实数部分近似得到了不错的结果,所以可能因此这里使用了实数部分。
 

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值