《在纹线方向上进行平滑滤波,在纹线的垂直方向上进行锐化滤波》
                                         --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. 简易版C语言程序设计语法

    源程序 → 外部声明 | 子程序(外部声明) 外部声明   → 函数定义| 函数声明 函数定义 → 类型标识符(复合句) 标识符类型 → 无类型 | 字符型 | 整型 | 浮点型 整型→ 长整型 | ...

  2. DataTable/集合 转 Json

    前端用的jqueryUI框架获取json格式数据绑定显示表格. 后端通过WebService获取的数据是DataTable. 现将获取DataTable转Json,也支持将数据集合转Json. 一.项 ...

  3. Ueditor百度网页编辑器开发者版java utf-8的使用

    index.jsp主要代码: <html> <head> <title>网页编辑器</title> <script type="text ...

  4. 指定的架构无效。错误: CLR 类型到 EDM 类型的映射不明确

    在使用WebService开发时,同时使用了EF和linq,查询数据时,使用linq(查询订单)可以正常拉出数据, 但是使用EF(查询用户)却会报以下错误: {"指定的架构无效.错误: \r ...

  5. SpringBoot RESTful 应用中的异常处理小结

    转载:https://segmentfault.com/a/1190000006749441 @ControllerAdvice 和 @ExceptionHandler 的区别 ExceptionHa ...

  6. Windows Server 2008 R2组策略设置计算机配置和用户配置

    一.认识Windows Server 2008 R2域控组策略管理 1.域控服务器zhuyu.com的组策略管理默认会读取AD用户和计算机目录下创建的OU容器(组织单元), 在对应的OU容器创建对应的 ...

  7. spark 简介

    spark 是基于内存计算的 大数据分布式计算框架,spark基于内存计算,提高了在大数据环境下处理的实时性,同时保证了高容错性和高可伸缩性,允许用户将spark部署在大量廉价的硬件上,形成集群. 1 ...

  8. RDIFramework.NET平台代码生成器V3.1版本全新发布-更新于2016-10-29(提供下载)

    本次主要更新内容: 1.增加对Oracle表创建语句的查看. 2.新增对MySql的代码生成支持. 3.全面重构对多线程的支持,改变以前会无故退出的现象. RDIFramework.NET代码生成器V ...

  9. js时间格式化

    const formatDate = timestamp => { const date = new Date(timestamp); const m = date.getMonth() + 1 ...

  10. sql存储过程异常捕获并输出例子还有不输出过程里面判断异常 例子

    编程的异常处理很重要,当然Sql语句中存储过程的异常处理也很重要,明确的异常提示能够快速的找到问题的根源,节省很多时间. 下面,我就以一个插入数据为例来说明Sql Server中的存储过程怎么捕获异常 ...