天天看點

精通visual c++指紋模式識别系統算法及實作

精通visual c++指紋模式識别系統算法及實作

通過學習,掌握以下幾個問題:

1、核心算法,并且向GVF衍生;

2、核心庫封裝的方法

2016年11月16日06:52:51

昨日實作了梯度場和頻率場的計算。最大的感覺就是建立基礎代碼庫的重要性。

如果使用opencv或者别的代碼庫,可能它也能實作一些功能,特别對于建立在感官上的效果,差别不大。但是,如果是用于數學計算的,特别是對于我現在還不是很清楚過程,也不是很清楚結果的算法來說,精确的、容易比對的代碼更重要。在這種時候,我更願意采取原始的、按照定義實作的計算方法。

在昨天的頻度場計算中,我突破好幾天的困擾,直接按照定義修改代碼,比如計算頻度場

int main( int argc, char** 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  vx, vy, lvx, lvy;

    unsigned char   *lpSrc = NULL;

    unsigned char   *lpOri = NULL;

    long    angle, num;

    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 = -r; i <= r; i++)    // 為提高速度,步長為

            {

                if(y+i<1 || y+i>=IMGH-1) continue;

                for(j = -r; j <= r; j++)    // 為提高速度,步長為

                {

                    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庫,用于收集這方面的代碼。

精通visual c++指紋模式識别系統算法及實作

雖然這本書很精彩,裡面的代碼對于我來說都是右開創性的;但是不可否認很多地方,他的代碼寫的還是比較繁瑣、備援的,給閱讀移植帶來了不少困難。

使用的情況是這樣的

    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);

    imshow("dst",smo);

    waitKey(0);

原始圖像

梯度圖像,可以看到,在指紋比較密集的地方,梯度很強,而在背景區域,比較幹淨。

通過梯度場,可以背景前景分離。

精通visual c++指紋模式識别系統算法及實作

方向場。基本上是表示了指紋線段角度的變化。特别觀察中間的位置,由255跳躍至0,是因為在中間的部分,指紋幾乎是水準的。

精通visual c++指紋模式識别系統算法及實作
精通visual c++指紋模式識别系統算法及實作

gaobor增強,現在在細節部分還有一點問題,但是已經基本展現出來特點了。

精通visual c++指紋模式識别系統算法及實作

這是我第一次自己寫代碼實作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,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++)

                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;

    // 紋線方向的垂直方向上進行銳化濾波

            lpSrc = g_lpTemp + temp + x;

            // 紋線方向的垂直方向的索引

            d = (DDIndex(*lpDir)+6) % 12;

            vsum = 0;

                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;

                *(g_lpOrgFinger + temp + x) = 255;

了現在的代碼,下一步就可以思考如何對自然環境下的許多圖像進行增強了。

來自為知筆記(Wiz)

目前方向:圖像拼接融合、圖像識别

聯系方式:[email protected]

繼續閱讀