《在纹线方向上进行平滑滤波,在纹线的垂直方向上进行锐化滤波》
                                         --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. 在eclipse中创建一个Maven项目

    1. 首先判断eclipse有没有自带Maven Window –> Perferences 如果有Maven,那就是自带了maven插件,如果没有,需要自行安装. 2.配置maven 2.1. ...

  2. System.Data.SqlClient.SqlException: 在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。未找到或无法访问服务器。请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接。 (provider: SQL Network Interfaces, error: 26 - 定位指定的服务器/实例时出错)

    A network-related or instance-specific error occurred while establishing a connection to SQL Server. ...

  3. Selenium2学习-039-WebUI自动化实战实例-文件上传下载

    通常在 WebUI 自动化测试过程中必然会涉及到文件上传的自动化测试需求,而开发在进行相应的技术实现是不同的,粗略可划分为两类:input标签类(类型为file)和非input标签类(例如:div.a ...

  4. php常用关键字

    1.final关键字 <?php //final关键字修饰的类 是最终的类不能被继承 class demo{ //final关键字修饰的成员方法 是最终版本的方法不能被重写 final publ ...

  5. Python之路【第十八章】:Django基础

    Django基本配置 Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Se ...

  6. tomcat,zookeeper,activeMQ,Kafka设置jvm参数

    1,tomcat设置jvm参数 设置方法:   在tomcat bin 目录增加配置:setenv.sh   #add tomcat pid CATALINA_PID="$CATALINA_ ...

  7. (转载)Resin安装配置及使用教程

    Resin是一个提供高性能的,支持 Java/PHP 的应用服务器.目前有两个版本:一个是GPL下的开源版本,提供给一些爱好者.开发人员和低流量网站使用:一种是收费的专业版本,增加了一些更加适用于生产 ...

  8. RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.0 版新增系统参数管理

    欲了解V3.0版本的相关内容可查看下面的链接地址. RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.0 版本发布 在V3.0版本的Web(Mvc.WebForm)与WinF ...

  9. [Python] 删除指定目录下后缀为 xxx 的过期文件

    import os import time import datetime def should_remove(path, pattern, days): if not path.endswith(p ...

  10. ubuntu安装node.js+express+mongodb

    输入以下命令安装: sudo apt-get install nodejs 安装完成后,终端输入nodejs,就能进入node命令啦: 但是正常下应该是输入node进入命令而不是nodejs: 在Ub ...