detect.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. /*******************************************************************************
  2. License:
  3. This software and/or related materials was developed at the National Institute
  4. of Standards and Technology (NIST) by employees of the Federal Government
  5. in the course of their official duties. Pursuant to title 17 Section 105
  6. of the United States Code, this software is not subject to copyright
  7. protection and is in the public domain.
  8. This software and/or related materials have been determined to be not subject
  9. to the EAR (see Part 734.3 of the EAR for exact details) because it is
  10. a publicly available technology and software, and is freely distributed
  11. to any interested party with no licensing requirements. Therefore, it is
  12. permissible to distribute this software as a free download from the internet.
  13. Disclaimer:
  14. This software and/or related materials was developed to promote biometric
  15. standards and biometric technology testing for the Federal Government
  16. in accordance with the USA PATRIOT Act and the Enhanced Border Security
  17. and Visa Entry Reform Act. Specific hardware and software products identified
  18. in this software were used in order to perform the software development.
  19. In no case does such identification imply recommendation or endorsement
  20. by the National Institute of Standards and Technology, nor does it imply that
  21. the products and equipment identified are necessarily the best available
  22. for the purpose.
  23. This software and/or related materials are provided "AS-IS" without warranty
  24. of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY,
  25. NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY
  26. or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the
  27. licensed product, however used. In no event shall NIST be liable for any
  28. damages and/or costs, including but not limited to incidental or consequential
  29. damages of any kind, including economic damage or injury to property and lost
  30. profits, regardless of whether NIST shall be advised, have reason to know,
  31. or in fact shall know of the possibility.
  32. By using this software, you agree to bear all risk relating to quality,
  33. use and performance of the software and/or related materials. You agree
  34. to hold the Government harmless from any claim arising from your use
  35. of the software.
  36. *******************************************************************************/
  37. /***********************************************************************
  38. LIBRARY: LFS - NIST Latent Fingerprint System
  39. FILE: DETECT.C
  40. AUTHOR: Michael D. Garris
  41. DATE: 08/16/1999
  42. UPDATED: 10/04/1999 Version 2 by MDG
  43. UPDATED: 03/16/2005 by MDG
  44. Takes an 8-bit grayscale fingerpinrt image and detects minutiae
  45. as part of the NIST Latent Fingerprint System (LFS).
  46. ***********************************************************************
  47. ROUTINES:
  48. lfs_detect_minutiae()
  49. lfs_detect_minutiae_V2()
  50. ***********************************************************************/
  51. #include <stdio.h>
  52. #include <string.h>
  53. #include "lfs.h"
  54. #include "mytime.h"
  55. #include "log.h"
  56. /*************************************************************************
  57. #cat: lfs_detect_minutiae - Takes a grayscale fingerprint image (of arbitrary
  58. #cat: size), and returns a map of directional ridge flow in the image
  59. #cat: (2 versions), a binarized image designating ridges from valleys,
  60. #cat: and a list of minutiae (including position, type, direction,
  61. #cat: neighbors, and ridge counts to neighbors).
  62. Input:
  63. idata - input 8-bit grayscale fingerprint image data
  64. iw - width (in pixels) of the image
  65. ih - height (in pixels) of the image
  66. lfsparms - parameters and thresholds for controlling LFS
  67. Output:
  68. ominutiae - resulting list of minutiae
  69. oimap - resulting IMAP
  70. {invalid (-1) or valid ridge directions}
  71. onmap - resulting NMAP
  72. {invalid (-1), high-curvature (-2), blanked blocks {-3} or
  73. valid ridge directions}
  74. omw - width (in blocks) of image maps
  75. omh - height (in blocks) of image maps
  76. obdata - resulting binarized image
  77. {0 = black pixel (ridge) and 255 = white pixel (valley)}
  78. obw - width (in pixels) of the binary image
  79. obh - height (in pixels) of the binary image
  80. Return Code:
  81. Zero - successful completion
  82. Negative - system error
  83. **************************************************************************/
  84. int lfs_detect_minutiae(MINUTIAE **ominutiae,
  85. int **oimap, int **onmap, int *omw, int *omh,
  86. unsigned char **obdata, int *obw, int *obh,
  87. unsigned char *idata, const int iw, const int ih,
  88. const LFSPARMS *lfsparms)
  89. {
  90. unsigned char *pdata, *bdata;
  91. int pw, ph, bw, bh;
  92. DIR2RAD *dir2rad;
  93. DFTWAVES *dftwaves;
  94. ROTGRIDS *dftgrids;
  95. ROTGRIDS *dirbingrids;
  96. int *imap, *nmap, mw, mh;
  97. int ret, maxpad;
  98. MINUTIAE *minutiae;
  99. set_timer(total_timer);
  100. /******************/
  101. /* INITIALIZATION */
  102. /******************/
  103. /* If LOG_REPORT defined, open log report file. */
  104. if((ret = open_logfile()))
  105. /* If system error, exit with error code. */
  106. return(ret);
  107. /* Determine the maximum amount of image padding required to support */
  108. /* LFS processes. */
  109. maxpad = get_max_padding(lfsparms->blocksize,
  110. lfsparms->dirbin_grid_w, lfsparms->dirbin_grid_h,
  111. lfsparms->isobin_grid_dim);
  112. /* Initialize lookup table for converting integer IMAP directions */
  113. /* to angles in radians. */
  114. if((ret = init_dir2rad(&dir2rad, lfsparms->num_directions))){
  115. /* Free memory allocated to this point. */
  116. return(ret);
  117. }
  118. /* Initialize wave form lookup tables for DFT analyses. */
  119. /* used for direction binarization. */
  120. if((ret = init_dftwaves(&dftwaves, dft_coefs, lfsparms->num_dft_waves,
  121. lfsparms->blocksize))){
  122. /* Free memory allocated to this point. */
  123. free_dir2rad(dir2rad);
  124. return(ret);
  125. }
  126. /* Initialize lookup table for pixel offsets to rotated grids */
  127. /* used for DFT analyses. */
  128. if((ret = init_rotgrids(&dftgrids, iw, ih, maxpad,
  129. lfsparms->start_dir_angle, lfsparms->num_directions,
  130. lfsparms->blocksize, lfsparms->blocksize,
  131. RELATIVE2ORIGIN))){
  132. /* Free memory allocated to this point. */
  133. free_dir2rad(dir2rad);
  134. free_dftwaves(dftwaves);
  135. return(ret);
  136. }
  137. /* Pad input image based on max padding. */
  138. if(maxpad > 0){ /* May not need to pad at all */
  139. if((ret = pad_uchar_image(&pdata, &pw, &ph, idata, iw, ih,
  140. maxpad, lfsparms->pad_value))){
  141. /* Free memory allocated to this point. */
  142. free_dir2rad(dir2rad);
  143. free_dftwaves(dftwaves);
  144. free_rotgrids(dftgrids);
  145. return(ret);
  146. }
  147. }
  148. else{
  149. /* If padding is unnecessary, then copy the input image. */
  150. pdata = (unsigned char *)malloc(iw*ih);
  151. if(pdata == (unsigned char *)NULL){
  152. /* Free memory allocated to this point. */
  153. free_dir2rad(dir2rad);
  154. free_dftwaves(dftwaves);
  155. free_rotgrids(dftgrids);
  156. fprintf(stderr, "ERROR : lfs_detect_minutiae : malloc : pdata\n");
  157. return(-430);
  158. }
  159. memcpy(pdata, idata, iw*ih);
  160. pw = iw;
  161. ph = ih;
  162. }
  163. /* Scale input image to 6 bits [0..63] */
  164. /* !!! Would like to remove this dependency eventualy !!! */
  165. /* But, the DFT computations will need to be changed, and */
  166. /* could not get this work upon first attempt. */
  167. bits_8to6(pdata, pw, ph);
  168. print2log("\nINITIALIZATION AND PADDING DONE\n");
  169. /******************/
  170. /* IMAP */
  171. /******************/
  172. set_timer(imap_timer);
  173. /* Generate IMAP for the input image. */
  174. if((ret = gen_imap(&imap, &mw, &mh, pdata, pw, ph, dir2rad,
  175. dftwaves, dftgrids, lfsparms))){
  176. /* Free memory allocated to this point. */
  177. free_dir2rad(dir2rad);
  178. free_dftwaves(dftwaves);
  179. free_rotgrids(dftgrids);
  180. free(pdata);
  181. return(ret);
  182. }
  183. free_dir2rad(dir2rad);
  184. free_dftwaves(dftwaves);
  185. free_rotgrids(dftgrids);
  186. print2log("\nIMAP DONE\n");
  187. /* Generate NMAP from the IMAP of the input image. */
  188. if((ret = gen_nmap(&nmap, imap, mw, mh, lfsparms))){
  189. /* Free memory allocated to this point. */
  190. free(pdata);
  191. free(imap);
  192. return(ret);
  193. }
  194. print2log("\nNMAP DONE\n");
  195. time_accum(imap_timer, imap_time);
  196. /******************/
  197. /* BINARIZARION */
  198. /******************/
  199. set_timer(bin_timer);
  200. /* Initialize lookup table for pixel offsets to rotated grids */
  201. /* used for directional binarization. */
  202. if((ret = init_rotgrids(&dirbingrids, iw, ih, maxpad,
  203. lfsparms->start_dir_angle, lfsparms->num_directions,
  204. lfsparms->dirbin_grid_w, lfsparms->dirbin_grid_h,
  205. RELATIVE2CENTER))){
  206. /* Free memory allocated to this point. */
  207. free(pdata);
  208. free(imap);
  209. free(nmap);
  210. return(ret);
  211. }
  212. /* Binarize input image based on NMAP information. */
  213. if((ret = binarize(&bdata, &bw, &bh, pdata, pw, ph, nmap, mw, mh,
  214. dirbingrids, lfsparms))){
  215. /* Free memory allocated to this point. */
  216. free(pdata);
  217. free(imap);
  218. free(nmap);
  219. free_rotgrids(dirbingrids);
  220. return(ret);
  221. }
  222. free_rotgrids(dirbingrids);
  223. /* Check dimension of binary image. If they are different from */
  224. /* the input image, then ERROR. */
  225. if((iw != bw) || (ih != bh)){
  226. /* Free memory allocated to this point. */
  227. free(pdata);
  228. free(imap);
  229. free(nmap);
  230. free(bdata);
  231. fprintf(stderr,
  232. "ERROR : lfs_detect_minutiae : binary image has bad dimensions : %d, %d\n",
  233. bw, bh);
  234. return(-431);
  235. }
  236. print2log("\nBINARIZATION DONE\n");
  237. time_accum(bin_timer, bin_time);
  238. /******************/
  239. /* DETECTION */
  240. /******************/
  241. set_timer(minutia_timer);
  242. /* Convert 8-bit grayscale binary image [0,255] to */
  243. /* 8-bit binary image [0,1]. */
  244. gray2bin(1, 1, 0, bdata, iw, ih);
  245. /* Allocate list of maximum number of minutia pointers. */
  246. if((ret = alloc_minutiae(&minutiae, MAX_MINUTIAE))){
  247. return(ret);
  248. }
  249. /* Detect the minutiae in the binarized image. */
  250. if((ret = detect_minutiae(minutiae, bdata, iw, ih, imap, nmap, mw, mh,
  251. lfsparms))){
  252. /* Free memory allocated to this point. */
  253. free(pdata);
  254. free(imap);
  255. free(nmap);
  256. free(bdata);
  257. return(ret);
  258. }
  259. time_accum(minutia_timer, minutia_time);
  260. set_timer(rm_minutia_timer);
  261. if((ret = remove_false_minutia(minutiae, bdata, iw, ih, nmap, mw, mh,
  262. lfsparms))){
  263. /* Free memory allocated to this point. */
  264. free(pdata);
  265. free(imap);
  266. free(nmap);
  267. free(bdata);
  268. free_minutiae(minutiae);
  269. return(ret);
  270. }
  271. print2log("\nMINUTIA DETECTION DONE\n");
  272. time_accum(rm_minutia_timer, rm_minutia_time);
  273. /******************/
  274. /* RIDGE COUNTS */
  275. /******************/
  276. set_timer(ridge_count_timer);
  277. if((ret = count_minutiae_ridges(minutiae, bdata, iw, ih, lfsparms))){
  278. /* Free memory allocated to this point. */
  279. free(pdata);
  280. free(imap);
  281. free(nmap);
  282. free(bdata);
  283. free_minutiae(minutiae);
  284. return(ret);
  285. }
  286. print2log("\nNEIGHBOR RIDGE COUNT DONE\n");
  287. time_accum(ridge_count_timer, ridge_count_time);
  288. /******************/
  289. /* WRAP-UP */
  290. /******************/
  291. /* Convert 8-bit binary image [0,1] to 8-bit */
  292. /* grayscale binary image [0,255]. */
  293. gray2bin(1, 255, 0, bdata, iw, ih);
  294. /* Deallocate working memory. */
  295. free(pdata);
  296. /* Assign results to output pointers. */
  297. *oimap = imap;
  298. *onmap = nmap;
  299. *omw = mw;
  300. *omh = mh;
  301. *obdata = bdata;
  302. *obw = bw;
  303. *obh = bh;
  304. *ominutiae = minutiae;
  305. time_accum(total_timer, total_time);
  306. /******************/
  307. /* PRINT TIMINGS */
  308. /******************/
  309. /* These Timings will print when TIMER is defined. */
  310. /* print IMAP generation timing statistics */
  311. print_time(stderr, "TIMER: IMAP time = %f (secs)\n", imap_time);
  312. /* print binarization timing statistics */
  313. print_time(stderr, "TIMER: Binarization time = %f (secs)\n", bin_time);
  314. /* print minutia detection timing statistics */
  315. print_time(stderr, "TIMER: Minutia Detection time = %f (secs)\n",
  316. minutia_time);
  317. /* print minutia removal timing statistics */
  318. print_time(stderr, "TIMER: Minutia Removal time = %f (secs)\n",
  319. rm_minutia_time);
  320. /* print neighbor ridge count timing statistics */
  321. print_time(stderr, "TIMER: Neighbor Ridge Counting time = %f (secs)\n",
  322. ridge_count_time);
  323. /* print total timing statistics */
  324. print_time(stderr, "TIMER: Total time = %f (secs)\n", total_time);
  325. /* If LOG_REPORT defined, close log report file. */
  326. if((ret = close_logfile()))
  327. return(ret);
  328. return(0);
  329. }
  330. /*************************************************************************
  331. #cat: lfs_detect_minutiae_V2 - Takes a grayscale fingerprint image (of
  332. #cat: arbitrary size), and returns a set of image block maps,
  333. #cat: a binarized image designating ridges from valleys,
  334. #cat: and a list of minutiae (including position, reliability,
  335. #cat: type, direction, neighbors, and ridge counts to neighbors).
  336. #cat: The image maps include a ridge flow directional map,
  337. #cat: a map of low contrast blocks, a map of low ridge flow blocks.
  338. #cat: and a map of high-curvature blocks.
  339. Input:
  340. idata - input 8-bit grayscale fingerprint image data
  341. iw - width (in pixels) of the image
  342. ih - height (in pixels) of the image
  343. lfsparms - parameters and thresholds for controlling LFS
  344. Output:
  345. ominutiae - resulting list of minutiae
  346. odmap - resulting Direction Map
  347. {invalid (-1) or valid ridge directions}
  348. olcmap - resulting Low Contrast Map
  349. {low contrast (TRUE), high contrast (FALSE)}
  350. olfmap - resulting Low Ridge Flow Map
  351. {low ridge flow (TRUE), high ridge flow (FALSE)}
  352. ohcmap - resulting High Curvature Map
  353. {high curvature (TRUE), low curvature (FALSE)}
  354. omw - width (in blocks) of image maps
  355. omh - height (in blocks) of image maps
  356. obdata - resulting binarized image
  357. {0 = black pixel (ridge) and 255 = white pixel (valley)}
  358. obw - width (in pixels) of the binary image
  359. obh - height (in pixels) of the binary image
  360. Return Code:
  361. Zero - successful completion
  362. Negative - system error
  363. **************************************************************************/
  364. int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
  365. int **odmap, int **olcmap, int **olfmap, int **ohcmap,
  366. int *omw, int *omh,
  367. unsigned char **obdata, int *obw, int *obh,
  368. unsigned char *idata, const int iw, const int ih,
  369. const LFSPARMS *lfsparms)
  370. {
  371. unsigned char *pdata, *bdata;
  372. int pw, ph, bw, bh;
  373. DIR2RAD *dir2rad;
  374. DFTWAVES *dftwaves;
  375. ROTGRIDS *dftgrids;
  376. ROTGRIDS *dirbingrids;
  377. int *direction_map, *low_contrast_map, *low_flow_map, *high_curve_map;
  378. int mw, mh;
  379. int ret, maxpad;
  380. MINUTIAE *minutiae;
  381. set_timer(total_timer);
  382. /******************/
  383. /* INITIALIZATION */
  384. /******************/
  385. /* If LOG_REPORT defined, open log report file. */
  386. if((ret = open_logfile()))
  387. /* If system error, exit with error code. */
  388. return(ret);
  389. /* Determine the maximum amount of image padding required to support */
  390. /* LFS processes. */
  391. maxpad = get_max_padding_V2(lfsparms->windowsize, lfsparms->windowoffset,
  392. lfsparms->dirbin_grid_w, lfsparms->dirbin_grid_h);
  393. /* Initialize lookup table for converting integer directions */
  394. /* to angles in radians. */
  395. if((ret = init_dir2rad(&dir2rad, lfsparms->num_directions))){
  396. /* Free memory allocated to this point. */
  397. return(ret);
  398. }
  399. /* Initialize wave form lookup tables for DFT analyses. */
  400. /* used for direction binarization. */
  401. if((ret = init_dftwaves(&dftwaves, dft_coefs, lfsparms->num_dft_waves,
  402. lfsparms->windowsize))){
  403. /* Free memory allocated to this point. */
  404. free_dir2rad(dir2rad);
  405. return(ret);
  406. }
  407. /* Initialize lookup table for pixel offsets to rotated grids */
  408. /* used for DFT analyses. */
  409. if((ret = init_rotgrids(&dftgrids, iw, ih, maxpad,
  410. lfsparms->start_dir_angle, lfsparms->num_directions,
  411. lfsparms->windowsize, lfsparms->windowsize,
  412. RELATIVE2ORIGIN))){
  413. /* Free memory allocated to this point. */
  414. free_dir2rad(dir2rad);
  415. free_dftwaves(dftwaves);
  416. return(ret);
  417. }
  418. /* Pad input image based on max padding. */
  419. if(maxpad > 0){ /* May not need to pad at all */
  420. if((ret = pad_uchar_image(&pdata, &pw, &ph, idata, iw, ih,
  421. maxpad, lfsparms->pad_value))){
  422. /* Free memory allocated to this point. */
  423. free_dir2rad(dir2rad);
  424. free_dftwaves(dftwaves);
  425. free_rotgrids(dftgrids);
  426. return(ret);
  427. }
  428. }
  429. else{
  430. /* If padding is unnecessary, then copy the input image. */
  431. pdata = (unsigned char *)malloc(iw*ih);
  432. if(pdata == (unsigned char *)NULL){
  433. /* Free memory allocated to this point. */
  434. free_dir2rad(dir2rad);
  435. free_dftwaves(dftwaves);
  436. free_rotgrids(dftgrids);
  437. fprintf(stderr, "ERROR : lfs_detect_minutiae_V2 : malloc : pdata\n");
  438. return(-580);
  439. }
  440. memcpy(pdata, idata, iw*ih);
  441. pw = iw;
  442. ph = ih;
  443. }
  444. /* Scale input image to 6 bits [0..63] */
  445. /* !!! Would like to remove this dependency eventualy !!! */
  446. /* But, the DFT computations will need to be changed, and */
  447. /* could not get this work upon first attempt. Also, if not */
  448. /* careful, I think accumulated power magnitudes may overflow */
  449. /* doubles. */
  450. bits_8to6(pdata, pw, ph);
  451. print2log("\nINITIALIZATION AND PADDING DONE\n");
  452. /******************/
  453. /* MAPS */
  454. /******************/
  455. set_timer(imap_timer);
  456. /* Generate block maps from the input image. */
  457. if((ret = gen_image_maps(&direction_map, &low_contrast_map,
  458. &low_flow_map, &high_curve_map, &mw, &mh,
  459. pdata, pw, ph, dir2rad, dftwaves, dftgrids, lfsparms))){
  460. /* Free memory allocated to this point. */
  461. free_dir2rad(dir2rad);
  462. free_dftwaves(dftwaves);
  463. free_rotgrids(dftgrids);
  464. free(pdata);
  465. return(ret);
  466. }
  467. /* Deallocate working memories. */
  468. free_dir2rad(dir2rad);
  469. free_dftwaves(dftwaves);
  470. free_rotgrids(dftgrids);
  471. print2log("\nMAPS DONE\n");
  472. time_accum(imap_timer, imap_time);
  473. /******************/
  474. /* BINARIZARION */
  475. /******************/
  476. set_timer(bin_timer);
  477. /* Initialize lookup table for pixel offsets to rotated grids */
  478. /* used for directional binarization. */
  479. if((ret = init_rotgrids(&dirbingrids, iw, ih, maxpad,
  480. lfsparms->start_dir_angle, lfsparms->num_directions,
  481. lfsparms->dirbin_grid_w, lfsparms->dirbin_grid_h,
  482. RELATIVE2CENTER))){
  483. /* Free memory allocated to this point. */
  484. free(pdata);
  485. free(direction_map);
  486. free(low_contrast_map);
  487. free(low_flow_map);
  488. free(high_curve_map);
  489. return(ret);
  490. }
  491. /* Binarize input image based on NMAP information. */
  492. if((ret = binarize_V2(&bdata, &bw, &bh,
  493. pdata, pw, ph, direction_map, mw, mh,
  494. dirbingrids, lfsparms))){
  495. /* Free memory allocated to this point. */
  496. free(pdata);
  497. free(direction_map);
  498. free(low_contrast_map);
  499. free(low_flow_map);
  500. free(high_curve_map);
  501. free_rotgrids(dirbingrids);
  502. return(ret);
  503. }
  504. /* Deallocate working memory. */
  505. free_rotgrids(dirbingrids);
  506. /* Check dimension of binary image. If they are different from */
  507. /* the input image, then ERROR. */
  508. if((iw != bw) || (ih != bh)){
  509. /* Free memory allocated to this point. */
  510. free(pdata);
  511. free(direction_map);
  512. free(low_contrast_map);
  513. free(low_flow_map);
  514. free(high_curve_map);
  515. free(bdata);
  516. fprintf(stderr, "ERROR : lfs_detect_minutiae_V2 :");
  517. fprintf(stderr,"binary image has bad dimensions : %d, %d\n",
  518. bw, bh);
  519. return(-581);
  520. }
  521. print2log("\nBINARIZATION DONE\n");
  522. time_accum(bin_timer, bin_time);
  523. /******************/
  524. /* DETECTION */
  525. /******************/
  526. set_timer(minutia_timer);
  527. /* Convert 8-bit grayscale binary image [0,255] to */
  528. /* 8-bit binary image [0,1]. */
  529. gray2bin(1, 1, 0, bdata, iw, ih);
  530. /* Allocate initial list of minutia pointers. */
  531. if((ret = alloc_minutiae(&minutiae, MAX_MINUTIAE))){
  532. return(ret);
  533. }
  534. /* Detect the minutiae in the binarized image. */
  535. if((ret = detect_minutiae_V2(minutiae, bdata, iw, ih,
  536. direction_map, low_flow_map, high_curve_map,
  537. mw, mh, lfsparms))){
  538. /* Free memory allocated to this point. */
  539. free(pdata);
  540. free(direction_map);
  541. free(low_contrast_map);
  542. free(low_flow_map);
  543. free(high_curve_map);
  544. free(bdata);
  545. return(ret);
  546. }
  547. time_accum(minutia_timer, minutia_time);
  548. set_timer(rm_minutia_timer);
  549. if((ret = remove_false_minutia_V2(minutiae, bdata, iw, ih,
  550. direction_map, low_flow_map, high_curve_map, mw, mh,
  551. lfsparms))){
  552. /* Free memory allocated to this point. */
  553. free(pdata);
  554. free(direction_map);
  555. free(low_contrast_map);
  556. free(low_flow_map);
  557. free(high_curve_map);
  558. free(bdata);
  559. free_minutiae(minutiae);
  560. return(ret);
  561. }
  562. print2log("\nMINUTIA DETECTION DONE\n");
  563. time_accum(rm_minutia_timer, rm_minutia_time);
  564. /******************/
  565. /* RIDGE COUNTS */
  566. /******************/
  567. set_timer(ridge_count_timer);
  568. if((ret = count_minutiae_ridges(minutiae, bdata, iw, ih, lfsparms))){
  569. /* Free memory allocated to this point. */
  570. free(pdata);
  571. free(direction_map);
  572. free(low_contrast_map);
  573. free(low_flow_map);
  574. free(high_curve_map);
  575. free_minutiae(minutiae);
  576. return(ret);
  577. }
  578. print2log("\nNEIGHBOR RIDGE COUNT DONE\n");
  579. time_accum(ridge_count_timer, ridge_count_time);
  580. /******************/
  581. /* WRAP-UP */
  582. /******************/
  583. /* Convert 8-bit binary image [0,1] to 8-bit */
  584. /* grayscale binary image [0,255]. */
  585. gray2bin(1, 255, 0, bdata, iw, ih);
  586. /* Deallocate working memory. */
  587. free(pdata);
  588. /* Assign results to output pointers. */
  589. *odmap = direction_map;
  590. *olcmap = low_contrast_map;
  591. *olfmap = low_flow_map;
  592. *ohcmap = high_curve_map;
  593. *omw = mw;
  594. *omh = mh;
  595. *obdata = bdata;
  596. *obw = bw;
  597. *obh = bh;
  598. *ominutiae = minutiae;
  599. time_accum(total_timer, total_time);
  600. /******************/
  601. /* PRINT TIMINGS */
  602. /******************/
  603. /* These Timings will print when TIMER is defined. */
  604. /* print MAP generation timing statistics */
  605. print_time(stderr, "TIMER: MAPS time = %f (secs)\n", imap_time);
  606. /* print binarization timing statistics */
  607. print_time(stderr, "TIMER: Binarization time = %f (secs)\n", bin_time);
  608. /* print minutia detection timing statistics */
  609. print_time(stderr, "TIMER: Minutia Detection time = %f (secs)\n",
  610. minutia_time);
  611. /* print minutia removal timing statistics */
  612. print_time(stderr, "TIMER: Minutia Removal time = %f (secs)\n",
  613. rm_minutia_time);
  614. /* print neighbor ridge count timing statistics */
  615. print_time(stderr, "TIMER: Neighbor Ridge Counting time = %f (secs)\n",
  616. ridge_count_time);
  617. /* print total timing statistics */
  618. print_time(stderr, "TIMER: Total time = %f (secs)\n", total_time);
  619. /* If LOG_REPORT defined, close log report file. */
  620. if((ret = close_logfile()))
  621. return(ret);
  622. return(0);
  623. }