天天看點

指紋模式識别算法及其測試方法指紋模式識别算法及其測試方法

指紋模式識别算法及其測試方法

指紋算法需求

指紋特征值生成、比對API庫需求:

  1. 可輸出指紋圖像。圖像格式為bmp,小于等于500DPI,不大于50K。
  2. 可輸出指紋模闆。生成模闆需要至少采集幾次指紋需說明,建議不超過三次。模闆大小不超過1K。模闆生成時間不大于1秒。
  3. 可輸出指紋特征值(可以是非字元串格式)。特征值大小不超過512B。
  4. 可輸出指紋特征值字元串。字元串為可見字元,長度不超1024。
  5. 指紋比對時,支援輸入指紋特征值字元串比對。
  6. 指紋比對時,支援輸入指紋圖像進行比對。
  7. 指紋比對API支援多線程模式,支援大并發調用。
  8. 指紋比對支援1:1,即指紋驗證。
  9. 指紋比對支援1:N,即指紋辨識。
  10. 指紋比對時每枚比對速度要求小于0.1秒。
  11. 認假率小于0.0001% 。
  12. 拒真率小于0.75% 。
  13. 庫要求32位,但支援在64位作業系統運作。
  14. 可提供dll、jar兩種形式API的庫。
  • 環境要求

系統清單
Windows 2003 server/xp/win7
Linux >=核心2.6
Aix unix >=5.2
Android

廢話不多說,直接上幹貨,先附上一張指紋算法項目的思路流程圖:

點選這裡:

指紋項目的算法及其測試完整Github連結

一、先講解一下指紋算法源碼的思路

從指紋圖像中提取指紋特征:

int __stdcall Analyze(BYTE *lpImage, int Width, int Height, BYTE *lpFeature, int *lpSize)

{

///////////////////////////////////////////////////////////////////////

// Width: [in] 指紋圖像寬度

// Height: [in] 指紋圖像高度

// lpImage: [in] 指紋圖像資料指針

// Resolution: [in] 指紋圖像分辨率,預設500

// lpFeature: [out] 提取的指紋特征資料指針

// lpSize: [out] 指紋特征資料大小

// TODO: Add your implementation code here

VF_RETURN re;

// 導入指紋圖像資料

VF_ImportFinger(lpImage, Width, Height);

// 處理指紋圖像,提取指紋特征

re = VF_Process();

if (re != VF_OK)

return re;

// 對指紋特征進行編碼

re = VF_FeatureEncode(&g_Feature, lpFeature, lpSize);

if (re != VF_OK)

return re;

return 0;

}

對兩個指紋進行特征比對:

int __stdcall PatternMatch(BYTE *lpFeature1, BYTE *lpFeature2, int *lpScore)

{

// lpFeature1: [in] 第一個指紋特征

// lpFeature2: [in] 第二個指紋特征

// lpScore: [out] 比對的相似度

// FastMode: [in] 是否進行快速模式比對

VF_RETURN re1,re2;

MATCHRESULT mr;

FEATURE feat1, feat2;

// 第一個指紋特征的解碼

re1 = VF_FeatureDecode(lpFeature1, &feat1);

if (re1 != VF_OK)

{

printf("圖像1解碼失敗\n");

return 0;

//return re1;

}

// 第二個指紋特征的解碼

re2 = VF_FeatureDecode(lpFeature2, &feat2);

if (re2 != VF_OK)

{

printf("圖像2解碼失敗\n");

return 0;

//return re2;

}

*lpScore = 0;

bool FastMode = true;

if (FastMode)

{

// 快速模式的比對

VF_VerifyMatch(&feat1, &feat2, &mr, VF_MATCHMODE_IDENTIFY);

}

else

{

// 精确模式的比對

VF_VerifyMatch(&feat1, &feat2, &mr, VF_MATCHMODE_VERIFY);

}

// 比對的相似度

//*lpScore = mr.Similarity/10;

*lpScore = mr.Similarity;

/*if (mr.MMCount < 8)

{

*lpScore = 0;

}

else

{

*lpScore = mr.Similarity;

}*/

return 0;

}

二、怎麼調用該源碼算法庫

在此不進行過多重複叙述,請移步我的另外一篇博文:

https://blog.csdn.net/yanxiaolx/article/details/78730291

三、測試該算法識别率的測試demo

測試指紋算法的效果好壞,有3個名額:拒真率,認假率和識别率

測試的指紋庫github已經上傳:

點選這裡

正樣本:所有指紋全部來自同一手指

負樣本:所有指紋均來自不同手指

拒真率:正樣本測試不通過的比率

認假率:負樣本測試通過的比率

識别率:1 -(拒真率 + 認假率) / 2

第一個函數,對兩個指紋圖檔的識别進行測試:

void test3()

{

char ImagePathName1[100] = "D:\\c++code\\test\\1 (1).BMP";

char ImagePathName2[100] = "D:\\c++code\\test\\1 (1).BMP";

BYTE lpFeature1[500] = { 0 };

BYTE lpFeature2[500] = { 0 };

int lpSize1 = 0, lpSize2 = 0, score = 0;

int iReturn = 0;

sprintf(ImagePathName1, "D:\\c++code\\test\\1 (13).BMP");

sprintf(ImagePathName2, "D:\\c++code\\test\\1 (14).BMP");

iReturn = AnalyzeFromFile(ImagePathName1, lpFeature1, &lpSize1);

if (iReturn != 0)

{

printf("從BMP檔案中讀取圖像1失敗\n");

}

iReturn = AnalyzeFromFile(ImagePathName2, lpFeature2, &lpSize2);

if (iReturn != 0)

{

printf("從BMP檔案中讀取圖像2失敗\n");

}

PatternMatch(lpFeature1, lpFeature2, &score);//對指紋進行比對

if (score >35)//原來是60

{

printf("Same Fingerprint! \n");

}

else

{

printf("Different Fingerprint! \n");

}

return;

}

測試認假率:

int count1 = 0, Arr_score1[11476] = { 0 };

void test1(double *Arr1)//測試認假率

{

char ImagePathName1[100] = "E:\\c++code\\指紋測試資料\\SyntFingerDLL\\測試分類指紋庫圖檔\\0.正常\\1 (1).BMP";

char ImagePathName2[100] = "E:\\c++code\\指紋測試資料\\SyntFingerDLL\\測試分類指紋庫圖檔\\0.正常\\1 (1).BMP";

BYTE lpFeature1[500] = { 0 };

BYTE lpFeature2[500] = { 0 };

int lpSize1=0, lpSize2=0, score=0;

int iReturn = 0;

//DWORD start_time = GetTickCount();

for (int i = 1; i <152; i++)//注意修改循環後面的值

{

sprintf(ImagePathName1, "E:\\c++code\\指紋測試資料\\SyntFingerDLL\\測試分類指紋庫圖檔\\0.正常\\1 (%d).BMP", i);

for (int j = i+1; j <=152; j++)//盡量保證假樣本多,(n-1)*n/2

{

sprintf(ImagePathName2, "E:\\c++code\\指紋測試資料\\SyntFingerDLL\\測試分類指紋庫圖檔\\0.正常\\1 (%d).BMP", j);

iReturn = AnalyzeFromFile(ImagePathName1, lpFeature1, &lpSize1);

if (iReturn != 0)

{

printf("從BMP檔案中讀取圖像%d失敗\n", i);

break;

}

iReturn = AnalyzeFromFile(ImagePathName2, lpFeature2, &lpSize2);

if (iReturn != 0)

{

printf("從BMP檔案中讀取圖像%d失敗\n", j);

continue;

}

PatternMatch(lpFeature1, lpFeature2, &score);//對指紋進行比對

Arr_score1[count1] = score;

count1++;

cout << count1 <<",i=" << i << ",j=" << j << endl;

}

}

//DWORD end_time = GetTickCount();

//cout << "The run time is:" << (end_time - start_time)/23436 << "ms!" << endl;

FILE *f;

f = fopen("D:\\c++code\\指紋測試資料\\認假test1\\score.txt", "w");

if (f == NULL)

{

printf("ERROR!");

return;

}

for (int i = 1; i <= 1000; i++)

{

int Y_count = 0, N_count = 0;

for (int j = 0; j < count1; j++)

{

if (Arr_score1[j]>=i-1)

{

Y_count++;

}

else

{

N_count++;

}

}

fprintf(f, "序号=%d,Y_count=%d,N_count=%d,sum=%d,認假率=%lf\n", i, Y_count, N_count, Y_count + N_count, Y_count*1.0 / (Y_count + N_count));

Arr1[i - 1] = Y_count*1.0 / (Y_count + N_count);

}

for (int j = 0; j < count1; j++)

{

fprintf(f, "序号=%d,score=%d\n", j + 1, Arr_score1[j]);

}

fclose(f);

return ;

}

測試拒真率:

int count2 = 0;

int Arr_score2[12000] = { 0 };

void test2(double *Arr2)//測試拒真率

{

char ImagePathName1[100] = "D:\\c++code\\指紋測試資料\\指紋采集2014.7.3-bmp\\1 (1)\\1 (1).BMP";

char ImagePathName2[100] = "D:\\c++code\\指紋測試資料\\指紋采集2014.7.3-bmp\\1 (1)\\1 (1).BMP";

BYTE lpFeature1[500] = { 0 };

BYTE lpFeature2[500] = { 0 };

int lpSize1 = 0, lpSize2 = 0, score = 0;

int iReturn = 0;

int N=10;//修改檔案夾友善

//DWORD start_time = GetTickCount();

for (int k =1; k <= 232; k++)

{

for (int i = 1; i <= N; i++)//注意修改循環後面的值

{

sprintf(ImagePathName1, "D:\\c++code\\指紋測試資料\\指紋采集2014.7.3-bmp\\1 (%d)\\1 (%d).BMP", k, i);

for (int j = i; j <= N; j++)//不考慮比對過的重複,盡量保證真樣本多,n*(n+1)/2

{

//count++;

sprintf(ImagePathName2, "D:\\c++code\\指紋測試資料\\指紋采集2014.7.3-bmp\\1 (%d)\\1 (%d).BMP", k, j);

iReturn = AnalyzeFromFile(ImagePathName1, lpFeature1, &lpSize1);

if (iReturn != 0)

{

printf("從BMP檔案中讀取圖像%d失敗\n", i);

break;

}

iReturn = AnalyzeFromFile(ImagePathName2, lpFeature2, &lpSize2);

if (iReturn != 0)

{

printf("從BMP檔案中讀取圖像%d失敗\n", j);

continue;

}

PatternMatch(lpFeature1, lpFeature2, &score);//對指紋進行比對

Arr_score2[count2] = score;

count2++;

cout << count2 << ",k=" << k << ",i="<<i<<",j=" << j << endl;

}

}

}

//DWORD end_time = GetTickCount();

FILE *f;

f = fopen("D:\\c++code\\指紋測試資料\\拒真test2\\score.txt", "w");

if (f == NULL)

{

printf("ERROR!");

return ;

}

for (int i = 1; i <= 1000; i++)

{

int Y_count = 0, N_count = 0;

for (int j = 0; j < count2; j++)

{

if (Arr_score2[j]>=i-1)

{

Y_count++;

}

else

{

N_count++;

}

}

fprintf(f, "score=%d,Y_count=%d,N_count=%d,sum=%d,拒真率=%lf\n", i, Y_count, N_count, Y_count + N_count, N_count*1.0 / (Y_count + N_count));

Arr2[i - 1] = N_count*1.0 / (Y_count + N_count);

}

for (int j = 0; j < count2; j++)

{

fprintf(f, "序号=%d,score=%d\n", j + 1, Arr_score2[j]);

}

fclose(f);

return ;

}

最後輸出各種識别率,存在記事本中:

int main()

{

double Arr1[1000] = { 0 }, Arr2[1000] = { 0 }, Arr3[1000] = { 0 };

test2(Arr2);//測試拒真率

test1(Arr1);//測試認假率

for (int i = 0; i < 1000; i++)

{

Arr3[i] = 1 - (Arr1[i] + Arr2[i]) / 2;

}

FILE *f;

f = fopen("D:\\c++code\\指紋測試資料\\識别率4.txt", "w");

if (f == NULL)

{

printf("ERROR!");

return 0;

}

for (int i = 0; i <1000; i++)

{

fprintf(f, "score=%d,認假率=%lf,拒真率=%lf,識别率=%lf\n", i , Arr1[i],Arr2[i],Arr3[i]);

printf("score=%d,認假率=%lf,拒真率=%lf,識别率=%lf\n", i , Arr1[i], Arr2[i], Arr3[i]);

}

fclose(f);

//test3();

system("pause");

return 0;

}

本人一共測試了正副樣本大概各10萬對左右,在不同的門檻值下,指紋的識别率分布大概呈現正态分布,其中score表示門檻值,如下圖資料記錄:

由上圖可以看出,當score=19時,識别率=0.965707達到最優峰值。

該項目是傳統指紋識别算法,當然識别率不是最優的,至于更優的指紋識别算法版本出于商業機密,暫時不能開源,哈哈,好氣是不是,不要打我。

未完待續,空了再繼續完善博文

原文位址

https://blog.csdn.net/yanxiaolx/article/details/82192343

繼續閱讀