开发者社区> 优惠券发放> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

指纹模式识别算法及其测试方法

简介: 指纹模式识别算法及其测试方法 指纹算法需求 指纹特征值生成、比对API库需求: 可输出指纹图像。图像格式为bmp,小于等于500DPI,不大于50K。 可输出指纹模板。生成模板需要至少采集几次指纹需说明,建议不超过三次。
+关注继续查看

指纹模式识别算法及其测试方法

指纹算法需求

指纹特征值生成、比对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

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
接口测试平台172:并发模式
接口测试平台172:并发模式
21 0
测试流程--测试发版规范
为了保证系统稳定性,对软件项目的上线过程进行规范,确保项目符合产品需求。对于已经开发完毕的系统,需要正式部署到生产环境前必须严格按照以下流程规范实施。 规范发版的流程,指定发版的相关输出,相关信息的收集,并通知相关业务方了解发版信息。防止或减少因发版造成的系统抖动对业务产生的影 响,并有利于追溯发版过程,方便后续优化迭代。
135 0
测试流程规范--准入准出规则
为了加强测试部软件测试的质量控制及与测试相关部门、人员更好理解测试各阶段的准入/准出条件而建立的准入/准出规范。
199 0
面试 | 你会使用哪些测试设计方法?
你平常会使用哪些测试设计方法? 这个问题该如何回答呢?
21 0
排序算法测试程序入口
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; using System.Diagnostics; namespace Sort { class Program { static vo
600 0
排序算法测试程序入口
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; using System.Diagnostics; namespace Sort { class Program { static void
935 0
白盒测试技术经验
代码走读经验 代码走读的重要性就不说了,我想谈谈对代码走读的总体认识。首先代码走读前,代码必须编译通过,强类型检查的语言(比如JAVA)自带的编译器就够了,如果是弱类型检查的语言(比如C/C++)应该用辅助的静态检查工具(比如lint)进行检查,毕竟机器发现问题的效率要比人眼和人脑要高的多,机器能做的事情让机器去做。
1016 0
什么是算法及其特征
算法是在有限步骤内求解某一问题所使用的一组定义明确的规则。通俗点说,就是计算机解题的过程。在这个过程中,无论是形成解题思路还是编写程序,都是在实施某种算法。
747 0
界面测试总结
一:如何针对文本框进行测试?    a、输入正常的字母或数字;   b、输入已存在的文件的名称;   c、输入超长字符;   例如在“名称”框中输入超过允许边界个数的字符,检查程序能否正确处理;   d、输入默认值,空白,空格,特殊符号;   e、若只允许输入字母,尝试输入数字;反...
713 0
+关注
优惠券发放
阿里云优惠码阿里云推荐券bieryun.com
456
文章
25
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载