《在纹线方向上进行平滑滤波,在纹线的垂直方向上进行锐化滤波》
                                         --Gabor增强的具体实践
    一、问题提出
            一般认为“Gabor小波感受野模拟线性滤波器,能对图像进行较好的智能收敛,从而智能增强图像。Gabor小波是智能收敛增强的物理模型”
             那么,问题是在实际过程中,如何实现“Gabor小波的智能收敛”,达到“智能增强效果”?
    二、解题思路
            使用工具,能够简单地得到Gabor增强的核;而对于想要增强效果的物体,首先要得到它的梯度数据,并且按照“在纹线方向上进行平滑滤波,在垂直方向上进行锐化滤波”的方式,按照不同方向选择不同Gabor增强核的方法进行图像增强。这样就能够得到“智能增强”。
    三、问题关键
             1、实现不同方向不同尺度的Gabor增强核,这个可以直接通过函数得到。在实际过程中,使用核心要经过量化的过程,否则将无法使用;
             2、得到原始图片的梯度数据。而这里的梯度数据,可以用方向场的方式保存下来;
             3、使用量化的Gabor核,依据梯度数据,对原始图像进行增强。
    四、解析过程
             1、Gabor核的生成(只描述数学结果,不做推导)
              Gabor函数是由高斯函数和三角(傅里叶)函数构成的,周期振荡函数。
             我们常见的一维Gabor函数为(基于正定傅里叶公式和高斯变换在实轴上投影):
          同时,二维的Gabor函数为:
 
那么,根据矩阵定义 :
全部带回Gabor函数二维表达式,得到
 
             2、固定方向的Gabor增强,就是用构建好的卷积核去做卷积。这样可以对核主要方向上体现出增强效果,对于垂直方向上,体现小波振荡效果。
                (图片为核心、原始图片和效果)
                
             从结果图片可以看到,在竖直方向上的纹理大多得到了一定的增强;但是在水平方向结果就非常差。
            (核心生成函数)
 // ks  核的大小
// sig σ:高斯函数的标准差 
// th  θ:Gabor核函数的方向 
// lm  λ:正弦函数波长;
// ps  ψ:相位偏移
// 本例中宽高比为1,也就是原始定义中的γ=1,这样得到的Gabor核的宽高是一致的
cv::Mat mkKernel(int ks, double sig, double th, double lm, double ps)
{
    int hks = (ks-1)/2;
    double theta = th*CV_PI/180;
    double psi = ps*CV_PI/180;
    double del = 2.0/(ks-1);
    double lmbd = lm;
    double sigma = sig/ks;
    double x_theta;
    double y_theta;
    cv::Mat kernel(ks,ks, CV_32F);
    for (int y=-hks; y<=hks; y++)
    {
        for (int x=-hks; x<=hks; x++)
        {
            x_theta = x*del*cos(theta)+y*del*sin(theta);
            y_theta = -x*del*sin(theta)+y*del*cos(theta);
            kernel.at<float>(hks+y,hks+x) = (float)exp(-0.5*(pow(x_theta,2)+pow(y_theta,2))/pow(sigma,2))* cos(2*CV_PI*x_theta/lmbd + psi);
        }
    }
    return kernel;

}

这个函数基本上是依据wikipad上面对于Gabor的定义编写的。注意里面的γ=1,这是没有实际说明的。但是这样得到的结果存在一个最主要的问题就是“只能对一个方向进行滤波”,而且考虑到之后可能会在原始图像的不同像素上面使用不同的核进行滤波,所以要采用其他的计算方式。
            “为了加速度,将Gabor函数做成模板,用模板来拟合Gabor函数”(为什么,没找到依据)

             3、判定得到原始图片的方向场;
             这是另一个问题,所谓方向场指的主要图像数据和法线之间的夹角。具体运算可以参考《精通visual c++指纹模式识别系统算法及实现》110页附近。
             4、依据方向场,在不同方向选择不同的Gabor核,对原始图像进行增强。
             利用Gabor小波函数,可以在方向场上对图像进行增强,以弥补图像中纹线的断裂等不足,在垂直的方向上,进行振荡增强。
int  g_DDSite[12][7][2] = {
    -3, 0,  -2, 0,  -1, 0,   0, 0,   1, 0,   2, 0,   3, 0,
    -3,-1,  -2,-1,  -1, 0,   0, 0,   1, 0,   2, 1,   3, 1,
    -3,-2,  -2,-1,  -1,-1,   0, 0,   1, 1,   2, 1,   3, 2,
    -3,-3,  -2,-2,  -1,-1,   0, 0,   1, 1,   2, 2,   3, 3,
    -2,-3,  -1,-2,  -1,-1,   0, 0,   1, 1,   1, 2,   2, 3,
    -1,-3,  -1,-2,   0,-1,   0, 0,   0, 1,   1, 2,   1, 3,
     0,-3,   0,-2,   0,-1,   0, 0,   0, 1,   0, 2,   0, 3,
    -1, 3,  -1, 2,   0, 1,   0, 0,   0,-1,   1,-2,   1,-3,
    -2, 3,  -1, 2,  -1, 1,   0, 0,   1,-1,   1,-2,   2,-3,
    -3, 3,  -2, 2,  -1, 1,   0, 0,   1,-1,   2,-2,   3,-3,
    -3, 2,  -2, 1,  -1, 1,   0, 0,   1,-1,   2,-1,   3,-2,
    -3, 1,  -2, 1,  -1, 0,   0, 0,   1, 0,   2,-1,   3,-1
};
 
//将 173- 8 = 165分为11等分
int DDIndex(int angle)
{
    /////////////////////////////////////////////////////////////////////////
    //    angle: [in] 角度 (0 - 180)
    /////////////////////////////////////////////////////////////////////////
    if(angle >= 173 || angle < 8)
    {
        return 0;
    }
    else
    {
        return ((angle-8)/15 + 1);
    }

}

 
//org是方向场 dst是输入输出结果
void orientEnhance(Mat org,Mat& dst)
{
    int x, y;
    int i;
    int d = 0;
    int sum = 0;
    // 纹线方向上进行平滑滤波的平滑滤波器
    int Hw[7] = {1, 1, 1, 1, 1, 1, 1};
    // 纹线方向的垂直方向上进行锐化滤波的锐化滤波器
    int Vw[7] = {-3, -1, 3, 9, 3, -1, -3};
    int hsum = 0;
    int vsum = 0;
    int temp = 0;
    int IMGW = org.cols;
    int IMGH = org.rows;
 
    BYTE  *lpSrc = NULL;
    BYTE  *lpDir = NULL;
 
    BYTE *g_lpOrient = org.ptr<uchar>(0);
    BYTE *g_lpOrgFinger = dst.ptr<uchar>(0);
    BYTE *g_lpTemp = dst.ptr<uchar>(0);
    //BYTE *g_lpTemp = new BYTE[IMGW * IMGH];
 
    // 纹线方向上进行平滑滤波
    temp = 0;
    for(y = 0; y < IMGH; y++)
    {
        for(x = 0; x < IMGW; x++)
        {
            lpDir = g_lpOrient + temp + x;
            lpSrc = g_lpOrgFinger + temp + x;
            // 纹线方向的索引
            // 找到划分的等分
            d = DDIndex(*lpDir); //求的方向
            sum = 0;
            hsum = 0;
            for(i = 0; i < 7; i++)
            { 
                //x对应0 y对应1
                if(y+g_DDSite[d][i][1] < 0 || y+g_DDSite[d][i][1] >= IMGH ||
                    x+g_DDSite[d][i][0] < 0 || x+g_DDSite[d][i][0] >= IMGW)
                {
                    continue;
                }
                sum += Hw[i]*(*(lpSrc + g_DDSite[d][i][1]*IMGW + g_DDSite[d][i][0]));
                hsum += Hw[i];
            }
            if(hsum != 0)
            {
                *(g_lpTemp + temp + x) = (BYTE)(sum/hsum);
            }
            else
            {
                *(g_lpTemp + temp + x) = 255;
            }
        }
        temp += IMGW;
    }
 
    // 纹线方向的垂直方向上进行锐化滤波
    temp = 0;
    for(y = 0; y < IMGH; y++)
    {
        for(x = 0; x < IMGW; x++)
        {
            lpDir = g_lpOrient + temp + x;
            lpSrc = g_lpTemp + temp + x;
 
            // 纹线方向的垂直方向的索引
            // 横过来计算
            d = (DDIndex(*lpDir)+6) % 12;
 
            sum = 0;
            vsum = 0;
            for(i = 0; i < 7; i++)
            {
                if(y+g_DDSite[d][i][1] < 0 || y+g_DDSite[d][i][1] >= IMGH ||
                    x+g_DDSite[d][i][0] < 0 || x+g_DDSite[d][i][0] >= IMGW)
                {
                    continue;
                }
                sum += Vw[i]*(*(lpSrc + g_DDSite[d][i][1]*IMGW + g_DDSite[d][i][0]));
                vsum += Vw[i];
            }
            if(vsum > 0)
            {
                sum /= vsum;
                if(sum > 255)
                {
                    *(g_lpOrgFinger + temp + x) = 255;
                }
                else if(sum < 0)
                {
                    *(g_lpOrgFinger + temp + x) = 0;
                }
                else
                {
                    *(g_lpOrgFinger + temp + x) = (BYTE)sum;
                }
            }
            else
            {
                *(g_lpOrgFinger + temp + x) = 255;
            }
        }
        temp += IMGW;
    }
 

}

结果
但是,图像的大小应该是有限制的,如果图像过大,现在选择的参数就应该不正确,得到类似下面的结果
 
如果想在其它图像上使用,关键是要得到和本例中同样的方向场
所以,如果用在其它地方,首先是要把图像的尺度缩放正确,可以得到以下结果
自然指纹
血管
 
 
    五、结果小结
            1、善用资源。很多实现,在wikipad上面就已经有很好的结果了,略加修改就可以得到目的;
            2、不断读书,书本中有很多灵感;多动笔墨,在书写中思考;
            3、攻坚克难,一定要把经典吃透,能够获得的远远比表面的问题多得多。
 
感谢阅读至此,如果需要继续交流请Email 1755311380@qq.com
 

《在纹线方向上进行平滑滤波,在纹线的垂直方向上进行锐化滤波》 --Gabor增强的具体实践的更多相关文章

  1. Android RecyclerViewSwipeDismiss:水平、垂直方向的拖曳删除item

     Android RecyclerViewSwipeDismiss:水平.垂直方向的拖曳删除item RecyclerViewSwipeDismiss是一种支持RecyclerView的水平.垂直 ...

  2. HTML-移动端如何使用css让百分比布局的弹窗水平和垂直方向上居中

    pc端让一个弹窗水平和垂直方向居中,在知道弹窗宽高的情况下很好计算,只需要用如下css即可: #date{ width: 300px; height: 300px; position: absolut ...

  3. div里面的元素在【垂直 方向】上水平分布 使用calc()函数动态计算

    1==>如何让div里面的元素在[垂直 方向]上水平分布.important-dec{ height: 121px; //必须固定高度 flex-direction: column; //垂直排 ...

  4. 行盒(line box)垂直方向的属性详解:从font-size、line-height到vertical-align

    视觉格式化模型 在一个文档中,每个元素都被表示为0.1或多个矩形的盒子.确定这些盒子的尺寸, 属性 --- 像它的颜色,背景,边框方面 --- 和位置是渲染引擎的目标.① 在CSS中,使用标准盒模型描 ...

  5. C#下如何用NPlot绘制期货股票K线图(2):读取数据文件让K线图自动更新

    [内容介绍]上一篇介绍了K线图的基本绘制方法,但很不完善,本篇增加了它直接读取数据的功能,这对于金融市场的数据量大且又需要动态刷新功能的实现很重要. [实现方法] 1.需要一个数据文件,这里用的是直接 ...

  6. vue 弹性布局 实现长图垂直居上,短图垂直居中

    vue 弹性布局 实现长图垂直居上,短图垂直居中 大致效果如下图,只考虑垂直方向.长图可以通过滚动条看,短图居中效果,布局合理 html代码(vue作用域内): <div class=" ...

  7. ArcGis For Silverlight API,地图显示Gis,绘制点,线,绘制图等--绘制点、线、圆,显示提示信息

    ArcGis For Silverlight API,地图显示Gis,绘制点,线,绘制图等--绘制点.线.圆,显示提示信息 /// <summary> /// 绘制界面上的点和线 ///  ...

  8. 【OpenCV】邻域滤波:方框、高斯、中值、双边滤波

    原文:http://blog.csdn.net/xiaowei_cqu/article/details/7785365 邻域滤波(卷积)   邻域算子值利用给定像素周围像素的值决定此像素的最终输出.如 ...

  9. CSS居中问题:块级元素和行级元素在水平方向以及垂直方向的居中问题

    元素的居中问题是每个初学者碰到的第一个大问题,在此我总结了下各种块级 行级 水平 垂直 的居中方法,并尽量给出代码实例. 首先请先明白块级元素和行级元素的区别 块级元素 块级元素水平居中 1:marg ...

随机推荐

  1. 另一种在WINFORM中使用XNA的方法

    之前在写化学分子模型制作程序的时候,使用一种方法,将WINFORM控件嵌入到XNA窗体中,从而实现了即使用WINFORM窗体控件又使用XNA.最近在写另一个物理运动学课件制作程序,同样使用XNA,但从 ...

  2. JQ first-child与:first的区别以及nth-child(index)与eq(index)的区别

    1.first-child和:first区别 first-child  是指选取每个父元素的第一个子元素 如$("div:first-child")指每个父级里的第一个div孩子 ...

  3. SQLServer一次性删除重复的数据

    delete from [GCPCore].[GCP.Product].[CityMall] where  AreaID in(select AreaID from [GCPCore].[GCP.Pr ...

  4. 启用CentOS6.5 64位安装时自带的MySQL数据库服务器

    本人在虚拟机上又安装了一台linux机器,作为MySQL数据库服务器用,在安装时选择了系统自带的MySQL服务器端,以下是启用步骤. 首先开启mysqld服务 #service mysqld star ...

  5. Sqlserver 导出数据脚本

    编写数据压缩选项的脚本 true 要编写脚本的数据的类型 仅限数据

  6. Oracle --获取绑定变量的值.

    SELECT * FROM DBA_HIST_SQLBIND WHERE SNAP_ID>67073 AND SNAP_ID<=67079 AND SQL_ID='3DR3410F086P ...

  7. cookie、session与token

    一.详述概念 1.Cookie机制 cookie机制是采用在客户端保持状态的方案(cookie的作用就是为了解决HTTP协议无状态的缺陷所作的努力).cookie的使用是由浏览器按照一定的原则在后台自 ...

  8. [原创]-bash: iostat: command not found解决办法

    [root@testhost ~]# iostat-bash: iostat: command not found IOSTAT 命令不可用,首先确认sysstat包是否安装,sysstat包中包括i ...

  9. iOS 版 MWeb 发布到自建 Wordpress 和 Metaweblog API 使用指南

    MWeb 的发布服务的使用方法是先增加发布服务,再使用.在 iOS 中,要增加发布服务,可以在首页中,点左上角的 "设置" 按钮,进入设置界面,并滑动到底部,就会看到增加发布服务的 ...

  10. c语言第8次作业

    #include<stdio.h> int main() { ]={}; int m; ; ;m<;m++) { a[m]=m+; !=&&a[m]%!=) n++; ...