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

简介: 指纹模式识别算法及其测试方法 指纹算法需求 指纹特征值生成、比对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链接

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

从指纹图像中提取指纹特征:



   
   
  1. int __ stdcall Analyze(BYTE *lpImage, int Width, int Height, BYTE *lpFeature, int *lpSize)
  2. {
  3. ///////////////////////////////////////////////////////////////////////
  4. // Width: [in] 指纹图像宽度
  5. // Height: [in] 指纹图像高度
  6. // lpImage: [in] 指纹图像数据指针
  7. // Resolution: [in] 指纹图像分辨率,默认500
  8. // lpFeature: [out] 提取的指纹特征数据指针
  9. // lpSize: [out] 指纹特征数据大小
  10. // TODO: Add your implementation code here
  11. VF_RETURN re;
  12. // 导入指纹图像数据
  13. VF_ImportFinger(lpImage, Width, Height);
  14. // 处理指纹图像,提取指纹特征
  15. re = VF_Process();
  16. if (re != VF_OK)
  17. return re;
  18. // 对指纹特征进行编码
  19. re = VF_FeatureEncode(&g_Feature, lpFeature, lpSize);
  20. if (re != VF_OK)
  21. return re;
  22. return 0;
  23. }

对两个指纹进行特征比对:



   
   
  1. int __ stdcall PatternMatch(BYTE *lpFeature1, BYTE *lpFeature2, int *lpScore)
  2. {
  3. // lpFeature1: [in] 第一个指纹特征
  4. // lpFeature2: [in] 第二个指纹特征
  5. // lpScore: [out] 比对的相似度
  6. // FastMode: [in] 是否进行快速模式比对
  7. VF_RETURN re1,re2;
  8. MATCHRESULT mr;
  9. FEATURE feat1, feat2;
  10. // 第一个指纹特征的解码
  11. re1 = VF_FeatureDecode(lpFeature1, &feat1);
  12. if (re1 != VF_OK)
  13. {
  14. printf( "图像1解码失败\n");
  15. return 0;
  16. //return re1;
  17. }
  18. // 第二个指纹特征的解码
  19. re2 = VF_FeatureDecode(lpFeature2, &feat2);
  20. if (re2 != VF_OK)
  21. {
  22. printf( "图像2解码失败\n");
  23. return 0;
  24. //return re2;
  25. }
  26. *lpScore = 0;
  27. bool FastMode = true;
  28. if (FastMode)
  29. {
  30. // 快速模式的比对
  31. VF_VerifyMatch(&feat1, &feat2, &mr, VF_MATCHMODE_IDENTIFY);
  32. }
  33. else
  34. {
  35. // 精确模式的比对
  36. VF_VerifyMatch(&feat1, &feat2, &mr, VF_MATCHMODE_VERIFY);
  37. }
  38. // 匹配的相似度
  39. //*lpScore = mr.Similarity/10;
  40. *lpScore = mr.Similarity;
  41. /*if (mr.MMCount < 8)
  42. {
  43. *lpScore = 0;
  44. }
  45. else
  46. {
  47. *lpScore = mr.Similarity;
  48. }*/
  49. return 0;
  50. }

 

二、怎么调用该源码算法库

在此不进行过多重复叙述,请移步我的另外一篇博文:https://blog.csdn.net/yanxiaolx/article/details/78730291

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

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

测试的指纹库github已经上传:点击这里

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

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

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

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

识别率:1 -(拒真率 + 认假率) / 2

第一个函数,对两个指纹图片的识别进行测试:



   
   
  1. void test3()
  2. {
  3. char ImagePathName1[ 100] = "D:\\c++code\\test\\1 (1).BMP";
  4. char ImagePathName2[ 100] = "D:\\c++code\\test\\1 (1).BMP";
  5. BYTE lpFeature1[ 500] = { 0 };
  6. BYTE lpFeature2[ 500] = { 0 };
  7. int lpSize1 = 0, lpSize2 = 0, score = 0;
  8. int iReturn = 0;
  9. sprintf(ImagePathName1, "D:\\c++code\\test\\1 (13).BMP");
  10. sprintf(ImagePathName2, "D:\\c++code\\test\\1 (14).BMP");
  11. iReturn = AnalyzeFromFile(ImagePathName1, lpFeature1, &lpSize1);
  12. if (iReturn != 0)
  13. {
  14. printf( "从BMP文件中读取图像1失败\n");
  15. }
  16. iReturn = AnalyzeFromFile(ImagePathName2, lpFeature2, &lpSize2);
  17. if (iReturn != 0)
  18. {
  19. printf( "从BMP文件中读取图像2失败\n");
  20. }
  21. PatternMatch(lpFeature1, lpFeature2, &score); //对指纹进行比对
  22. if (score > 35) //原来是60
  23. {
  24. printf( "Same Fingerprint! \n");
  25. }
  26. else
  27. {
  28. printf( "Different Fingerprint! \n");
  29. }
  30. return;
  31. }

测试认假率:



   
   
  1. int count1 = 0, Arr_score1[ 11476] = { 0 };
  2. void test1(double *Arr1)//测试认假率
  3. {
  4. char ImagePathName1[ 100] = "E:\\c++code\\指纹测试资料\\SyntFingerDLL\\测试分类指纹库图片\\0.正常\\1 (1).BMP";
  5. char ImagePathName2[ 100] = "E:\\c++code\\指纹测试资料\\SyntFingerDLL\\测试分类指纹库图片\\0.正常\\1 (1).BMP";
  6. BYTE lpFeature1[ 500] = { 0 };
  7. BYTE lpFeature2[ 500] = { 0 };
  8. int lpSize1= 0, lpSize2= 0, score= 0;
  9. int iReturn = 0;
  10. //DWORD start_time = GetTickCount();
  11. for ( int i = 1; i < 152; i++) //注意修改循环后面的值
  12. {
  13. sprintf(ImagePathName1, "E:\\c++code\\指纹测试资料\\SyntFingerDLL\\测试分类指纹库图片\\0.正常\\1 (%d).BMP", i);
  14. for ( int j = i+ 1; j <= 152; j++) //尽量保证假样本多,(n-1)*n/2
  15. {
  16. sprintf(ImagePathName2, "E:\\c++code\\指纹测试资料\\SyntFingerDLL\\测试分类指纹库图片\\0.正常\\1 (%d).BMP", j);
  17. iReturn = AnalyzeFromFile(ImagePathName1, lpFeature1, &lpSize1);
  18. if (iReturn != 0)
  19. {
  20. printf( "从BMP文件中读取图像%d失败\n", i);
  21. break;
  22. }
  23. iReturn = AnalyzeFromFile(ImagePathName2, lpFeature2, &lpSize2);
  24. if (iReturn != 0)
  25. {
  26. printf( "从BMP文件中读取图像%d失败\n", j);
  27. continue;
  28. }
  29. PatternMatch(lpFeature1, lpFeature2, &score); //对指纹进行比对
  30. Arr_score1[count1] = score;
  31. count1++;
  32. cout << count1 << ",i=" << i << ",j=" << j << endl;
  33. }
  34. }
  35. //DWORD end_time = GetTickCount();
  36. //cout << "The run time is:" << (end_time - start_time)/23436 << "ms!" << endl;
  37. FILE *f;
  38. f = fopen( "D:\\c++code\\指纹测试资料\\认假test1\\score.txt", "w");
  39. if (f == NULL)
  40. {
  41. printf( "ERROR!");
  42. return;
  43. }
  44. for ( int i = 1; i <= 1000; i++)
  45. {
  46. int Y_count = 0, N_count = 0;
  47. for ( int j = 0; j < count1; j++)
  48. {
  49. if (Arr_score1[j]>=i -1)
  50. {
  51. Y_count++;
  52. }
  53. else
  54. {
  55. N_count++;
  56. }
  57. }
  58. 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));
  59. Arr1[i - 1] = Y_count* 1.0 / (Y_count + N_count);
  60. }
  61. for ( int j = 0; j < count1; j++)
  62. {
  63. fprintf(f, "序号=%d,score=%d\n", j + 1, Arr_score1[j]);
  64. }
  65. fclose(f);
  66. return ;
  67. }

测试拒真率:



   
   
  1. int count2 = 0;
  2. int Arr_score2[ 12000] = { 0 };
  3. void test2(double *Arr2)//测试拒真率
  4. {
  5. char ImagePathName1[ 100] = "D:\\c++code\\指纹测试资料\\指纹采集2014.7.3-bmp\\1 (1)\\1 (1).BMP";
  6. char ImagePathName2[ 100] = "D:\\c++code\\指纹测试资料\\指纹采集2014.7.3-bmp\\1 (1)\\1 (1).BMP";
  7. BYTE lpFeature1[ 500] = { 0 };
  8. BYTE lpFeature2[ 500] = { 0 };
  9. int lpSize1 = 0, lpSize2 = 0, score = 0;
  10. int iReturn = 0;
  11. int N= 10; //修改文件夹方便
  12. //DWORD start_time = GetTickCount();
  13. for ( int k = 1; k <= 232; k++)
  14. {
  15. for ( int i = 1; i <= N; i++) //注意修改循环后面的值
  16. {
  17. sprintf(ImagePathName1, "D:\\c++code\\指纹测试资料\\指纹采集2014.7.3-bmp\\1 (%d)\\1 (%d).BMP", k, i);
  18. for ( int j = i; j <= N; j++) //不考虑比对过的重复,尽量保证真样本多,n*(n+1)/2
  19. {
  20. //count++;
  21. sprintf(ImagePathName2, "D:\\c++code\\指纹测试资料\\指纹采集2014.7.3-bmp\\1 (%d)\\1 (%d).BMP", k, j);
  22. iReturn = AnalyzeFromFile(ImagePathName1, lpFeature1, &lpSize1);
  23. if (iReturn != 0)
  24. {
  25. printf( "从BMP文件中读取图像%d失败\n", i);
  26. break;
  27. }
  28. iReturn = AnalyzeFromFile(ImagePathName2, lpFeature2, &lpSize2);
  29. if (iReturn != 0)
  30. {
  31. printf( "从BMP文件中读取图像%d失败\n", j);
  32. continue;
  33. }
  34. PatternMatch(lpFeature1, lpFeature2, &score); //对指纹进行比对
  35. Arr_score2[count2] = score;
  36. count2++;
  37. cout << count2 << ",k=" << k << ",i="<<i<< ",j=" << j << endl;
  38. }
  39. }
  40. }
  41. //DWORD end_time = GetTickCount();
  42. FILE *f;
  43. f = fopen( "D:\\c++code\\指纹测试资料\\拒真test2\\score.txt", "w");
  44. if (f == NULL)
  45. {
  46. printf( "ERROR!");
  47. return ;
  48. }
  49. for ( int i = 1; i <= 1000; i++)
  50. {
  51. int Y_count = 0, N_count = 0;
  52. for ( int j = 0; j < count2; j++)
  53. {
  54. if (Arr_score2[j]>=i -1)
  55. {
  56. Y_count++;
  57. }
  58. else
  59. {
  60. N_count++;
  61. }
  62. }
  63. 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));
  64. Arr2[i - 1] = N_count* 1.0 / (Y_count + N_count);
  65. }
  66. for ( int j = 0; j < count2; j++)
  67. {
  68. fprintf(f, "序号=%d,score=%d\n", j + 1, Arr_score2[j]);
  69. }
  70. fclose(f);
  71. return ;
  72. }

最后输出各种识别率,存在记事本中:



   
   
  1. int main()
  2. {
  3. double Arr1[ 1000] = { 0 }, Arr2[ 1000] = { 0 }, Arr3[ 1000] = { 0 };
  4. test2(Arr2); //测试拒真率
  5. test1(Arr1); //测试认假率
  6. for ( int i = 0; i < 1000; i++)
  7. {
  8. Arr3[i] = 1 - (Arr1[i] + Arr2[i]) / 2;
  9. }
  10. FILE *f;
  11. f = fopen( "D:\\c++code\\指纹测试资料\\识别率4.txt", "w");
  12. if (f == NULL)
  13. {
  14. printf( "ERROR!");
  15. return 0;
  16. }
  17. for ( int i = 0; i < 1000; i++)
  18. {
  19. fprintf(f, "score=%d,认假率=%lf,拒真率=%lf,识别率=%lf\n", i , Arr1[i],Arr2[i],Arr3[i]);
  20. printf( "score=%d,认假率=%lf,拒真率=%lf,识别率=%lf\n", i , Arr1[i], Arr2[i], Arr3[i]);
  21. }
  22. fclose(f);
  23. //test3();
  24. system( "pause");
  25. return 0;
  26. }

本人一共测试了正副样本大概各10万对左右,在不同的阈值下,指纹的识别率分布大概呈现正态分布,其中score表示阈值,如下图数据记录:

 

由上图可以看出,当score=19时,识别率=0.965707达到最优峰值。

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

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

原文地址https://blog.csdn.net/yanxiaolx/article/details/82192343

相关文章
|
2月前
|
测试技术 API 项目管理
API测试方法
【10月更文挑战第18天】API测试方法
46 1
|
2月前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
45 3
|
2月前
|
安全 测试技术
北大李戈团队提出大模型单测生成新方法,显著提升代码测试覆盖率
【10月更文挑战第1天】北京大学李戈教授团队提出了一种名为“统一生成测试”的创新方法,有效提升了大模型如GPT-2和GPT-3在单一测试中的代码生成覆盖率,分别从56%提升至72%和从61%提升至78%。这种方法结合了模糊测试、变异测试和生成对抗网络等多种技术,克服了传统测试方法的局限性,在大模型测试领域实现了重要突破,有助于提高系统的可靠性和安全性。然而,该方法的实现复杂度较高且实际应用效果仍需进一步验证。论文可从此链接下载:【https://drive.weixin.qq.com/s?k=ACAAewd0AA48Z2kXrJ】
63 1
|
2月前
|
测试技术 UED
软件测试中的“灰盒”方法:一种平衡透明度与效率的策略
在软件开发的复杂世界中,确保产品质量和用户体验至关重要。本文将探讨一种被称为“灰盒测试”的方法,它结合了白盒和黑盒测试的优点,旨在提高测试效率同时保持一定程度的透明度。我们将通过具体案例分析,展示灰盒测试如何在实际工作中发挥作用,并讨论其对现代软件开发流程的影响。
|
25天前
|
Java 测试技术 Maven
Java一分钟之-PowerMock:静态方法与私有方法测试
通过本文的详细介绍,您可以使用PowerMock轻松地测试Java代码中的静态方法和私有方法。PowerMock通过扩展Mockito,提供了强大的功能,帮助开发者在复杂的测试场景中保持高效和准确的单元测试。希望本文对您的Java单元测试有所帮助。
64 2
|
2月前
|
算法 索引
HashMap扩容时的rehash方法中(e.hash & oldCap) == 0算法推导
HashMap在扩容时,会创建一个新数组,并将旧数组中的数据迁移过去。通过(e.hash & oldCap)是否等于0,数据被巧妙地分为两类:一类保持原有索引位置,另一类索引位置增加旧数组长度。此过程确保了数据均匀分布,提高了查询效率。
39 2
|
2月前
|
JSON 算法 数据可视化
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
这篇文章是关于如何通过算法接口返回的目标检测结果来计算性能指标的笔记。它涵盖了任务描述、指标分析(包括TP、FP、FN、TN、精准率和召回率),接口处理,数据集处理,以及如何使用实用工具进行文件操作和数据可视化。文章还提供了一些Python代码示例,用于处理图像文件、转换数据格式以及计算目标检测的性能指标。
67 0
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
|
2月前
|
测试技术 Python
自动化测试项目学习笔记(三):Unittest加载测试用例的四种方法
本文介绍了使用Python的unittest框架来加载测试用例的四种方法,包括通过测试用例类、模块、路径和逐条加载测试用例。
67 0
自动化测试项目学习笔记(三):Unittest加载测试用例的四种方法
|
2月前
|
测试技术 Python
自动化测试项目学习笔记(二):学习各种setup、tearDown、断言方法
本文主要介绍了自动化测试中setup、teardown、断言方法的使用,以及unittest框架中setUp、tearDown、setUpClass和tearDownClass的区别和应用。
65 0
自动化测试项目学习笔记(二):学习各种setup、tearDown、断言方法
|
2月前
|
测试技术 UED
软件测试中的探索性测试:一种高效且灵活的测试方法
本文将深入探讨探索性测试的核心概念、优势及其在实际项目中的应用。我们将从探索性测试的基本定义入手,逐步解析其在不同场景下的具体实施方法和最佳实践。通过详细的案例分析和方法对比,帮助读者全面了解这种既高效又灵活的软件测试技术。