指紋模式識别算法及其測試方法
指紋算法需求
指紋特征值生成、比對API庫需求:
- 可輸出指紋圖像。圖像格式為bmp,小于等于500DPI,不大于50K。
- 可輸出指紋模闆。生成模闆需要至少采集幾次指紋需說明,建議不超過三次。模闆大小不超過1K。模闆生成時間不大于1秒。
- 可輸出指紋特征值(可以是非字元串格式)。特征值大小不超過512B。
- 可輸出指紋特征值字元串。字元串為可見字元,長度不超1024。
- 指紋比對時,支援輸入指紋特征值字元串比對。
- 指紋比對時,支援輸入指紋圖像進行比對。
- 指紋比對API支援多線程模式,支援大并發調用。
- 指紋比對支援1:1,即指紋驗證。
- 指紋比對支援1:N,即指紋辨識。
- 指紋比對時每枚比對速度要求小于0.1秒。
- 認假率小于0.0001% 。
- 拒真率小于0.75% 。
- 庫要求32位,但支援在64位作業系統運作。
- 可提供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