精通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;
    }
 
}
了現在的代碼,下一步就可以思考如何對自然環境下的許多圖像進行增強了。
 
 
 
 






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM