• 精通visual c++指纹模式识别系统算法及实现


    通过学习,掌握以下几个问题:
    1、核心算法,并且向GVF衍生;
    2、核心库封装的方法
    2016年11月16日06:52:51
    昨日实现了梯度场和频率场的计算。最大的感觉就是建立基础代码库的重要性。
    如果使用opencv或者别的代码库,可能它也能实现一些功能,特别对于建立在感官上的效果,差别不大。但是,如果是用于数学计算的,特别是对于我现在还不是很清楚过程,也不是很清楚结果的算法来说,精确的、容易比对的代码更重要。在这种时候,我更愿意采取原始的、按照定义实现的计算方法。
    在昨天的频度场计算中,我突破好几天的困扰,直接按照定义修改代码,比如计算频度场
    int mainint argcchar** argv )
    {
        Mat src = imread2gray("E:\template\1.bmp");
        src.convertTo(src,CV_8U);//255的运算
        pyrDown(src,src);
        Mat dst;//结果
        dst.create(src.size(),src.type());   
     
        int IMGH =src.rows;    
        int IMGW =src.cols;  
        int gradSum;
        int grad;
        long  vxvylvxlvy;
     
        unsigned char   *lpSrc = NULL;
        unsigned char   *lpOri = NULL;
        long    anglenum;
        double  fAngle;
        int r = 6;
        int i;int j;
        for (int y = 0;y<IMGH-1;y++)
        {
            for (int x=0;x<IMGW-1;x++)
            {
                lpOri = dst.ptr<uchar>(0) + y*IMGW + x;
                lvx = 0;
                lvy = 0;
                num = 0;
                for(i = -ri <= ri++)    // 为提高速度,步长为
                {
                    if(y+i<1 || y+i>=IMGH-1) continue;
                    for(j = -rj <= rj++)    // 为提高速度,步长为
                    {
                        if(x+j<1 || x+j>=IMGW-1) continue;
                        lpSrc = src.ptr<uchar>(0) + (y+i)*(IMGW) + x+j;
                        //求x方向偏导
                        vx = *(lpSrc + IMGW + 1) - *(lpSrc + IMGW - 1) +
                            *(lpSrc + 1)*2 - *(lpSrc - 1)*2 +
                            *(lpSrc - IMGW + 1) - *(lpSrc - IMGW - 1);
                        //求y方向偏导
                        vy = *(lpSrc + IMGW - 1) - *(lpSrc - IMGW - 1) +
                            *(lpSrc + IMGW)*2 - *(lpSrc - IMGW)*2 +
                            *(lpSrc + IMGW + 1) - *(lpSrc - IMGW + 1);
     
                        lvx += vx * vy * 2;//sin(2sita)
                        lvy += vx*vx - vy*vy;//cos(2sita)
                        num++;
                    }
                }
     
                if(num == 0) num = 1;
                // 求弧度
                fAngle = atan2((float)lvy, (float)lvx);
                // 变换到(0 - 2*pi)
                if(fAngle < 0)    fAngle += 2*PI;
     
                // 求纹线角度
                fAngle = (fAngle*EPI*0.5 + 0.5);
                angle = (long)fAngle;
     
                // 因为采用sobel算子,所以角度偏转了度,所以要旋转求得的角度
                angle -= 135;
                // 角度变换到(-180)
                if(angle <= 0)    angle += 180;
     
                angle = 180-angle;
                // 最终纹线角度
                *lpOri = (unsigned char)angle;
                *(lpOri + 1) = (unsigned char)angle;
                *(lpOri + IMGW) = (unsigned char)angle;
                *(lpOri + IMGW + 1) = (unsigned char)angle;
            }
        }
         
        pyrUp(dst,dst);
        imwrite("e:/sandbox/n1dst.bmp",dst);
        return 0;
    }
    这样从结果的面上来看,已经是非常接近书中给出的效果了。
    下一步,专门成立GOGVF项目作为GOCVHelper的一个部分,逐步地改造现有代码库,实现书中的效果。并且向GOGVF的按照定义实现做出努力。
     
    2016年11月16日06:52:51 已经逐步移植代码,从梯度一直做到了增强。虽然现在的代码还有一些问题,但是基本不影响使用。并且生成了专门的GOGVF库,用于收集这方面的代码。
    虽然这本书很精彩,里面的代码对于我来说都是右开创性的;但是不可否认很多地方,他的代码写的还是比较繁琐、冗余的,给阅读移植带来了不少困难。
    使用的情况是这样的
    int mainint argcchar** argv )
    {
        Mat src = imread2gray("E:\template\2.bmp");
        Mat grad = getGrads(src); //梯度场
        Mat org = getOrientMap(src); //方向场
        Mat seg;
        segment(grad,seg); //对梯度场进行阈值,seg为分割结果
        segment_clearEdge(src,org,seg);//反馈到src和org中了,这种方法倒也是方便
        Mat equ = src.clone();
        //cv::equalizeHist(src,equ);
        equalize(src,equ);
        Mat gauss = src.clone();
        GaussSmooth(equ,gauss,0.4);
        Mat smo = src.clone();
        smooth(gauss,smo,1,1);
        orientEnhance(org,smo);
        orientEnhance(org,smo);
        imshow("dst",smo);
        waitKey(0);
        return 0;
    }
    原始图像
    梯度图像,可以看到,在指纹比较密集的地方,梯度很强,而在背景区域,比较干净。
    通过梯度场,可以背景前景分离。
    方向场。基本上是表示了指纹线段角度的变化。特别观察中间的位置,由255跳跃至0,是因为在中间的部分,指纹几乎是水平的。
      
    gaobor增强,现在在细节部分还有一点问题,但是已经基本体现出来特点了。
    这是我第一次自己写代码实现gabor的效果,也是深入理解gabor的一次。回头思考,指纹识别其实是很好的算法平台,因为采集到的图片,本身背景前景分割还是比较干净的;在以前,如果处理这样的图片,我可能会选择阈值分割这种直观的方法;在实现了frangi算法之后,很多时候我会拿frangi来实验一下,看看效果。但是这次试用gabor增强,应该说是给我增加了一种新的思路,以后的眼界会更宽阔。。
    gaobor增强的核心,是对前面计算出来的梯度场中的“纹线方向进行平滑滤波,纹线的竖直方向进行锐化滤波
    。那么首先就是要计算处正确的梯度场来。在本例中,图片质量比较好,能够通过几乎是定义计算的方法计算出正确稳定的梯度场(但是在其他很多地方,可能不能这样使用?用什么计算出正确的梯度场,作为一个专门的话题)。然后就是通过对梯度进行增强。这里才是实现gaobor的地方。这里贴出的是实现的代码,推导过程分帖说明。关键就是“量化“。
    int DDIndex(int angle)
    {
        /////////////////////////////////////////////////////////////////////////
        //    angle: [in] 角度 (0 - 180)
        /////////////////////////////////////////////////////////////////////////
        if(angle >= 173 || angle < 8)
        {
            return 0;
        }
        else
        {
            return ((angle-8)/15 + 1);
        }
    }
     
    void orientEnhance(Mat org,Matdst)
    {
        int xy;
        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 < IMGHy++)
        {
            for(x = 0; x < IMGWx++)
            {
                lpDir = g_lpOrient + temp + x;
                lpSrc = g_lpOrgFinger + temp + x;
                // 纹线方向的索引
                d = DDIndex(*lpDir);
                sum = 0;
                hsum = 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 += 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 < IMGHy++)
        {
            for(x = 0; x < IMGWx++)
            {
                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;
        }
     
    }
    了现在的代码,下一步就可以思考如何对自然环境下的许多图像进行增强了。
     
     
     
     





  • 相关阅读:
    记一次gogs迁徙
    Spark集群模式安装
    Spark单机模式安装
    SparkSQL入门
    SparkSql API
    Spark和HBase整合
    SparkStreaming与Kafka整合
    SparkStreaming基础案例
    Spark 自定义分区及区内二次排序demo
    Sqoop安装及指令
  • 原文地址:https://www.cnblogs.com/jsxyhelu/p/6080651.html
Copyright © 2020-2023  润新知