指纹算法需求

指纹特征值生成、比对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链接
<https://github.com/yaoyaoyanxiao/fingerprint/tree/master/%E6%8C%87%E7%BA%B9%E6%B5%8B%E8%AF%95%E8%B5%84%E6%96%99/SyntFingerDLL>

一、先讲解一下指纹算法源码的思路

从指纹图像中提取指纹特征:
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
<https://blog.csdn.net/yanxiaolx/article/details/78730291>

三、测试该算法识别率的测试demo

测试指纹算法的效果好坏,有3个指标:拒真率,认假率和识别率

测试的指纹库github已经上传:点击这里
<https://github.com/yaoyaoyanxiao/fingerprint/tree/master/%E6%8C%87%E7%BA%B9%E6%B5%8B%E8%AF%95%E8%B5%84%E6%96%99/SyntFingerDLL/%E6%B5%8B%E8%AF%95%E5%88%86%E7%B1%BB%E6%8C%87%E7%BA%B9%E5%BA%93%E5%9B%BE%E7%89%87>

正样本:所有指纹全部来自同一手指

负样本:所有指纹均来自不同手指

拒真率:正样本测试不通过的比率

认假率:负样本测试通过的比率

识别率: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达到最优峰值。

下面举例聊聊指纹算法在银行的业务应用流程:

* 指纹采集
(1)柜员到支行以上的部门进行指纹集中采集;

(2)采集时需要同时运行并打开平台、客户端、设备,同时完成联接;

(3)采集时至少采集柜员的三枚手指,优先采集左手手指,同时优先采集食指、中指、大拇指;

(4)采集指纹功能由客户端、设备完成。指纹在设备上获取后,由客户端完成模板的处理,再由客户端上传平台;

(5)平台将客户端上传的柜员号、指纹图像、指纹特征值模板、指头标记进行处理,完成平台用户、柜员、指纹的绑定。



     2.指纹比对

(一)柜员签到流程

(1)柜员签到过程中的指纹验证是在系统平台上完成;

(2)首先从终端柜面输入柜员号,然后柜员将注册过的手指在设备上按压来实时采集指纹;

(3)设备对实时采集的指纹图像进行处理并生成指纹特征值,同时上传到平台;

(4)平台将指纹特征值与已采集的指纹模板进行比对,判断合法性;

(5)比对不成功,则返回错误值。比对成功,则平台将柜员关联的用户密码返回给终端;终端柜面根据此密码登录前端系统。



(二)业务授权流程

(1)柜员授权过程中的指纹验证是在系统平台上完成;

(2)在等待输入授权柜员号时,具有授权权限的柜员将注册过的手指按压到设备进行采集指纹;

(3)设备对实时采集的指纹图像进行处理并生成指纹特征值,同时上传到平台;

(4)平台将指纹特征值与已采集的指纹模板进行比对,判断合法性;

(5)比对不成功,则返回错误值。比对成功,则平台将柜员关联的用户密码返回给终端,终端柜面根据此密码完成授权过程。



该项目是传统指纹识别算法,当然识别率不是最优的,至于更优的指纹识别算法版本出于商业机密,暂时不能开源,哈哈,好气是不是,不要打我。

未完待续,空了再继续完善博文

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信