ridges.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  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: RIDGES.C
  40. AUTHOR: Michael D. Garris
  41. DATE: 08/09/1999
  42. UPDATED: 03/16/2005 by MDG
  43. Contains routines responsible for locating nearest minutia
  44. neighbors and counting intervening ridges as part of the
  45. NIST Latent Fingerprint System (LFS).
  46. ***********************************************************************
  47. ROUTINES:
  48. count_minutiae_ridges()
  49. count_minutia_ridges()
  50. find_neighbors()
  51. update_nbr_dists()
  52. insert_neighbor()
  53. sort_neighbors()
  54. ridge_count()
  55. find_transition()
  56. validate_ridge_crossing()
  57. ***********************************************************************/
  58. #include <stdio.h>
  59. #include "lfs.h"
  60. #include "log.h"
  61. /*************************************************************************
  62. **************************************************************************
  63. #cat: count_minutiae_ridges - Takes a list of minutiae, and for each one,
  64. #cat: determines its closest neighbors and counts the number
  65. #cat: of interveining ridges between the minutia point and
  66. #cat: each of its neighbors.
  67. Input:
  68. minutiae - list of minutiae
  69. bdata - binary image data (0==while & 1==black)
  70. iw - width (in pixels) of image
  71. ih - height (in pixels) of image
  72. lfsparms - parameters and thresholds for controlling LFS
  73. Output:
  74. minutiae - list of minutiae augmented with neighbors and ridge counts
  75. Return Code:
  76. Zero - successful completion
  77. Negative - system error
  78. **************************************************************************/
  79. int count_minutiae_ridges(MINUTIAE *minutiae,
  80. unsigned char *bdata, const int iw, const int ih,
  81. const LFSPARMS *lfsparms)
  82. {
  83. int ret;
  84. int i;
  85. print2log("\nFINDING NBRS AND COUNTING RIDGES:\n");
  86. /* Sort minutia points on x then y (column-oriented). */
  87. if((ret = sort_minutiae_x_y(minutiae, iw, ih))){
  88. return(ret);
  89. }
  90. /* Remove any duplicate minutia points from the list. */
  91. if((ret = rm_dup_minutiae(minutiae))){
  92. return(ret);
  93. }
  94. /* Foreach remaining sorted minutia in list ... */
  95. for(i = 0; i < minutiae->num-1; i++){
  96. /* Located neighbors and count number of ridges in between. */
  97. /* NOTE: neighbor and ridge count results are stored in */
  98. /* minutiae->list[i]. */
  99. if((ret = count_minutia_ridges(i, minutiae, bdata, iw, ih, lfsparms))){
  100. return(ret);
  101. }
  102. }
  103. /* Return normally. */
  104. return(0);
  105. }
  106. /*************************************************************************
  107. **************************************************************************
  108. #cat: count_minutia_ridges - Takes a minutia, and determines its closest
  109. #cat: neighbors and counts the number of interveining ridges
  110. #cat: between the minutia point and each of its neighbors.
  111. Input:
  112. minutia - input minutia
  113. bdata - binary image data (0==while & 1==black)
  114. iw - width (in pixels) of image
  115. ih - height (in pixels) of image
  116. lfsparms - parameters and thresholds for controlling LFS
  117. Output:
  118. minutiae - minutia augmented with neighbors and ridge counts
  119. Return Code:
  120. Zero - successful completion
  121. Negative - system error
  122. **************************************************************************/
  123. int count_minutia_ridges(const int first, MINUTIAE *minutiae,
  124. unsigned char *bdata, const int iw, const int ih,
  125. const LFSPARMS *lfsparms)
  126. {
  127. int i, ret, *nbr_list, *nbr_nridges, nnbrs;
  128. /* Find up to the maximum number of qualifying neighbors. */
  129. if((ret = find_neighbors(&nbr_list, &nnbrs, lfsparms->max_nbrs,
  130. first, minutiae))){
  131. free(nbr_list);
  132. return(ret);
  133. }
  134. print2log("NBRS FOUND: %d,%d = %d\n", minutiae->list[first]->x,
  135. minutiae->list[first]->y, nnbrs);
  136. /* If no neighors found ... */
  137. if(nnbrs == 0){
  138. /* Then no list returned and no ridges to count. */
  139. return(0);
  140. }
  141. /* Sort neighbors on delta dirs. */
  142. if((ret = sort_neighbors(nbr_list, nnbrs, first, minutiae))){
  143. free(nbr_list);
  144. return(ret);
  145. }
  146. /* Count ridges between first and neighbors. */
  147. /* List of ridge counts, one for each neighbor stored. */
  148. nbr_nridges = (int *)malloc(nnbrs * sizeof(int));
  149. if(nbr_nridges == (int *)NULL){
  150. free(nbr_list);
  151. fprintf(stderr, "ERROR : count_minutia_ridges : malloc : nbr_nridges\n");
  152. return(-450);
  153. }
  154. /* Foreach neighbor found and sorted in list ... */
  155. for(i = 0; i < nnbrs; i++){
  156. /* Count the ridges between the primary minutia and the neighbor. */
  157. ret = ridge_count(first, nbr_list[i], minutiae, bdata, iw, ih, lfsparms);
  158. /* If system error ... */
  159. if(ret < 0){
  160. /* Deallocate working memories. */
  161. free(nbr_list);
  162. free(nbr_nridges);
  163. /* Return error code. */
  164. return(ret);
  165. }
  166. /* Otherwise, ridge count successful, so store ridge count to list. */
  167. nbr_nridges[i] = ret;
  168. }
  169. /* Assign neighbor indices and ridge counts to primary minutia. */
  170. minutiae->list[first]->nbrs = nbr_list;
  171. minutiae->list[first]->ridge_counts = nbr_nridges;
  172. minutiae->list[first]->num_nbrs = nnbrs;
  173. /* Return normally. */
  174. return(0);
  175. }
  176. /*************************************************************************
  177. **************************************************************************
  178. #cat: find_neighbors - Takes a primary minutia and a list of all minutiae
  179. #cat: and locates a specified maximum number of closest neighbors
  180. #cat: to the primary point. Neighbors are searched, starting
  181. #cat: in the same pixel column, below, the primary point and then
  182. #cat: along consecutive and complete pixel columns in the image
  183. #cat: to the right of the primary point.
  184. Input:
  185. max_nbrs - maximum number of closest neighbors to be returned
  186. first - index of the primary minutia point
  187. minutiae - list of minutiae
  188. Output:
  189. onbr_list - points to list of detected closest neighbors
  190. onnbrs - points to number of neighbors returned
  191. Return Code:
  192. Zero - successful completion
  193. Negative - system error
  194. **************************************************************************/
  195. int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs,
  196. const int first, MINUTIAE *minutiae)
  197. {
  198. int ret, second, last_nbr;
  199. MINUTIA *minutia1, *minutia2;
  200. int *nbr_list, nnbrs;
  201. double *nbr_sqr_dists, xdist, xdist2;
  202. /* Allocate list of neighbor minutiae indices. */
  203. nbr_list = (int *)malloc(max_nbrs * sizeof(int));
  204. if(nbr_list == (int *)NULL){
  205. fprintf(stderr, "ERROR : find_neighbors : malloc : nbr_list\n");
  206. return(-460);
  207. }
  208. /* Allocate list of squared euclidean distances between neighbors */
  209. /* and current primary minutia point. */
  210. nbr_sqr_dists = (double *)malloc(max_nbrs * sizeof(double));
  211. if(nbr_sqr_dists == (double *)NULL){
  212. free(nbr_list);
  213. fprintf(stderr,
  214. "ERROR : find_neighbors : malloc : nbr_sqr_dists\n");
  215. return(-461);
  216. }
  217. /* Initialize number of stored neighbors to 0. */
  218. nnbrs = 0;
  219. /* Assign secondary to one passed current primary minutia. */
  220. second = first + 1;
  221. /* Compute location of maximum last stored neighbor. */
  222. last_nbr = max_nbrs - 1;
  223. /* While minutia (in sorted order) still remian for processing ... */
  224. /* NOTE: The minutia in the input list have been sorted on X and */
  225. /* then on Y. So, the neighbors are selected according to those */
  226. /* that lie below the primary minutia in the same pixel column and */
  227. /* then subsequently those that lie in complete pixel columns to */
  228. /* the right of the primary minutia. */
  229. while(second < minutiae->num){
  230. /* Assign temporary minutia pointers. */
  231. minutia1 = minutiae->list[first];
  232. minutia2 = minutiae->list[second];
  233. /* Compute squared distance between minutiae along x-axis. */
  234. xdist = minutia2->x - minutia1->x;
  235. xdist2 = xdist * xdist;
  236. /* If the neighbor lists are not full OR the x-distance to current */
  237. /* secondary is smaller than maximum neighbor distance stored ... */
  238. if((nnbrs < max_nbrs) ||
  239. (xdist2 < nbr_sqr_dists[last_nbr])){
  240. /* Append or insert the new neighbor into the neighbor lists. */
  241. if((ret = update_nbr_dists(nbr_list, nbr_sqr_dists, &nnbrs, max_nbrs,
  242. first, second, minutiae))){
  243. free(nbr_sqr_dists);
  244. return(ret);
  245. }
  246. }
  247. /* Otherwise, if the neighbor lists is full AND the x-distance */
  248. /* to current secondary is larger than maximum neighbor distance */
  249. /* stored ... */
  250. else
  251. /* So, stop searching for more neighbors. */
  252. break;
  253. /* Bump to next secondary minutia. */
  254. second++;
  255. }
  256. /* Deallocate working memory. */
  257. free(nbr_sqr_dists);
  258. /* If no neighbors found ... */
  259. if(nnbrs == 0){
  260. /* Deallocate the neighbor list. */
  261. free(nbr_list);
  262. *onnbrs = 0;
  263. }
  264. /* Otherwise, assign neighbors to output pointer. */
  265. else{
  266. *onbr_list = nbr_list;
  267. *onnbrs = nnbrs;
  268. }
  269. /* Return normally. */
  270. return(0);
  271. }
  272. /*************************************************************************
  273. **************************************************************************
  274. #cat: update_nbr_dists - Takes the current list of neighbors along with a
  275. #cat: primary minutia and a potential new neighbor, and
  276. #cat: determines if the new neighbor is sufficiently close
  277. #cat: to be added to the list of nearest neighbors. If added,
  278. #cat: it is placed in the list in its proper order based on
  279. #cat: squared distance to the primary point.
  280. Input:
  281. nbr_list - current list of nearest neighbor minutia indices
  282. nbr_sqr_dists - corresponding squared euclidean distance of each
  283. neighbor to the primary minutia point
  284. nnbrs - number of neighbors currently in the list
  285. max_nbrs - maximum number of closest neighbors to be returned
  286. first - index of the primary minutia point
  287. second - index of the secondary (new neighbor) point
  288. minutiae - list of minutiae
  289. Output:
  290. nbr_list - updated list of nearest neighbor indices
  291. nbr_sqr_dists - updated list of nearest neighbor distances
  292. nnbrs - number of neighbors in the update lists
  293. Return Code:
  294. Zero - successful completion
  295. Negative - system error
  296. **************************************************************************/
  297. int update_nbr_dists(int *nbr_list, double *nbr_sqr_dists,
  298. int *nnbrs, const int max_nbrs,
  299. const int first, const int second, MINUTIAE *minutiae)
  300. {
  301. double dist2;
  302. MINUTIA *minutia1, *minutia2;
  303. int pos, last_nbr;
  304. /* Compute position of maximum last neighbor stored. */
  305. last_nbr = max_nbrs - 1;
  306. /* Assigne temporary minutia pointers. */
  307. minutia1 = minutiae->list[first];
  308. minutia2 = minutiae->list[second];
  309. /* Compute squared euclidean distance between minutia pair. */
  310. dist2 = squared_distance(minutia1->x, minutia1->y,
  311. minutia2->x, minutia2->y);
  312. /* If maximum number of neighbors not yet stored in lists OR */
  313. /* if the squared distance to current secondary is less */
  314. /* than the largest stored neighbor distance ... */
  315. if((*nnbrs < max_nbrs) ||
  316. (dist2 < nbr_sqr_dists[last_nbr])){
  317. /* Find insertion point in neighbor lists. */
  318. pos = find_incr_position_dbl(dist2, nbr_sqr_dists, *nnbrs);
  319. /* If the position returned is >= maximum list length (this should */
  320. /* never happen, but just in case) ... */
  321. if(pos >= max_nbrs){
  322. fprintf(stderr,
  323. "ERROR : update_nbr_dists : illegal position for new neighbor\n");
  324. return(-470);
  325. }
  326. /* Insert the new neighbor into the neighbor lists at the */
  327. /* specified location. */
  328. if(insert_neighbor(pos, second, dist2,
  329. nbr_list, nbr_sqr_dists, nnbrs, max_nbrs))
  330. return(-471);
  331. /* Otherwise, neighbor inserted successfully, so return normally. */
  332. return(0);
  333. }
  334. /* Otherwise, the new neighbor is not sufficiently close to be */
  335. /* added or inserted into the neighbor lists, so ignore the neighbor */
  336. /* and return normally. */
  337. else
  338. return(0);
  339. }
  340. /*************************************************************************
  341. **************************************************************************
  342. #cat: insert_neighbor - Takes a minutia index and its squared distance to a
  343. #cat: primary minutia point, and inserts them in the specified
  344. #cat: position of their respective lists, shifting previously
  345. #cat: stored values down and off the lists as necessary.
  346. Input:
  347. pos - postions where values are to be inserted in lists
  348. nbr_index - index of minutia being inserted
  349. nbr_dist2 - squared distance of minutia to its primary point
  350. nbr_list - current list of nearest neighbor minutia indices
  351. nbr_sqr_dists - corresponding squared euclidean distance of each
  352. neighbor to the primary minutia point
  353. nnbrs - number of neighbors currently in the list
  354. max_nbrs - maximum number of closest neighbors to be returned
  355. Output:
  356. nbr_list - updated list of nearest neighbor indices
  357. nbr_sqr_dists - updated list of nearest neighbor distances
  358. nnbrs - number of neighbors in the update lists
  359. Return Code:
  360. Zero - successful completion
  361. Negative - system error
  362. **************************************************************************/
  363. int insert_neighbor(const int pos, const int nbr_index, const double nbr_dist2,
  364. int *nbr_list, double *nbr_sqr_dists,
  365. int *nnbrs, const int max_nbrs)
  366. {
  367. int i;
  368. /* If the desired insertion position is beyond one passed the last */
  369. /* neighbor in the lists OR greater than equal to the maximum ... */
  370. /* NOTE: pos is zero-oriented while nnbrs and max_nbrs are 1-oriented. */
  371. if((pos > *nnbrs) ||
  372. (pos >= max_nbrs)){
  373. fprintf(stderr,
  374. "ERROR : insert_neighbor : insertion point exceeds lists\n");
  375. return(-480);
  376. }
  377. /* If the neighbor lists are NOT full ... */
  378. if(*nnbrs < max_nbrs){
  379. /* Then we have room to shift everything down to make room for new */
  380. /* neighbor and increase the number of neighbors stored by 1. */
  381. i = *nnbrs-1;
  382. (*nnbrs)++;
  383. }
  384. /* Otherwise, the neighbors lists are full ... */
  385. else if(*nnbrs == max_nbrs)
  386. /* So, we must bump the last neighbor in the lists off to make */
  387. /* room for the new neighbor (ignore last neighbor in lists). */
  388. i = *nnbrs-2;
  389. /* Otherwise, there is a list overflow error condition */
  390. /* (shouldn't ever happen, but just in case) ... */
  391. else{
  392. fprintf(stderr,
  393. "ERROR : insert_neighbor : overflow in neighbor lists\n");
  394. return(-481);
  395. }
  396. /* While we havn't reached the desired insertion point ... */
  397. while(i >= pos){
  398. /* Shift the current neighbor down the list 1 positon. */
  399. nbr_list[i+1] = nbr_list[i];
  400. nbr_sqr_dists[i+1] = nbr_sqr_dists[i];
  401. i--;
  402. }
  403. /* We are now ready to put our new neighbor in the position where */
  404. /* we shifted everything down from to make room. */
  405. nbr_list[pos] = nbr_index;
  406. nbr_sqr_dists[pos] = nbr_dist2;
  407. /* Return normally. */
  408. return(0);
  409. }
  410. /*************************************************************************
  411. **************************************************************************
  412. #cat: sort_neighbors - Takes a list of primary minutia and its neighboring
  413. #cat: minutia indices and sorts the neighbors based on their
  414. #cat: position relative to the primary minutia point. Neighbors
  415. #cat: are sorted starting vertical to the primary point and
  416. #cat: proceeding clockwise.
  417. Input:
  418. nbr_list - list of neighboring minutia indices
  419. nnbrs - number of neighbors in the list
  420. first - the index of the primary minutia point
  421. minutiae - list of minutiae
  422. Output:
  423. nbr_list - neighboring minutia indices in sorted order
  424. Return Code:
  425. Zero - successful completion
  426. Negative - system error
  427. **************************************************************************/
  428. int sort_neighbors(int *nbr_list, const int nnbrs, const int first,
  429. MINUTIAE *minutiae)
  430. {
  431. double *join_thetas, theta;
  432. int i;
  433. static double pi2 = M_PI*2.0;
  434. /* List of angles of lines joining the current primary to each */
  435. /* of the secondary neighbors. */
  436. join_thetas = (double *)malloc(nnbrs * sizeof(double));
  437. if(join_thetas == (double *)NULL){
  438. fprintf(stderr, "ERROR : sort_neighbors : malloc : join_thetas\n");
  439. return(-490);
  440. }
  441. for(i = 0; i < nnbrs; i++){
  442. /* Compute angle to line connecting the 2 points. */
  443. /* Coordinates are swapped and order of points reversed to */
  444. /* account for 0 direction is vertical and positive direction */
  445. /* is clockwise. */
  446. theta = angle2line(minutiae->list[nbr_list[i]]->y,
  447. minutiae->list[nbr_list[i]]->x,
  448. minutiae->list[first]->y,
  449. minutiae->list[first]->x);
  450. /* Make sure the angle is positive. */
  451. theta += pi2;
  452. theta = fmod(theta, pi2);
  453. join_thetas[i] = theta;
  454. }
  455. /* Sort the neighbor indicies into rank order. */
  456. bubble_sort_double_inc_2(join_thetas, nbr_list, nnbrs);
  457. /* Deallocate the list of angles. */
  458. free(join_thetas);
  459. /* Return normally. */
  460. return(0);
  461. }
  462. /*************************************************************************
  463. **************************************************************************
  464. #cat: ridge_count - Takes a pair of minutiae, and counts the number of
  465. #cat: ridges crossed along the linear trajectory connecting
  466. #cat: the 2 points in the image.
  467. Input:
  468. first - index of primary minutia
  469. second - index of secondary (neighbor) minutia
  470. minutiae - list of minutiae
  471. bdata - binary image data (0==while & 1==black)
  472. iw - width (in pixels) of image
  473. ih - height (in pixels) of image
  474. lfsparms - parameters and thresholds for controlling LFS
  475. Return Code:
  476. Zero or Positive - number of ridges counted
  477. Negative - system error
  478. **************************************************************************/
  479. int ridge_count(const int first, const int second, MINUTIAE *minutiae,
  480. unsigned char *bdata, const int iw, const int ih,
  481. const LFSPARMS *lfsparms)
  482. {
  483. MINUTIA *minutia1, *minutia2;
  484. int i, ret, found;
  485. int *xlist, *ylist, num;
  486. int ridge_count, ridge_start, ridge_end;
  487. int prevpix, curpix;
  488. minutia1 = minutiae->list[first];
  489. minutia2 = minutiae->list[second];
  490. /* If the 2 mintuia have identical pixel coords ... */
  491. if((minutia1->x == minutia2->x) &&
  492. (minutia1->y == minutia2->y))
  493. /* Then zero ridges between points. */
  494. return(0);
  495. /* Compute linear trajectory of contiguous pixels between first */
  496. /* and second minutia points. */
  497. if((ret = line_points(&xlist, &ylist, &num,
  498. minutia1->x, minutia1->y, minutia2->x, minutia2->y))){
  499. return(ret);
  500. }
  501. /* It there are no points on the line trajectory, then no ridges */
  502. /* to count (this should not happen, but just in case) ... */
  503. if(num == 0){
  504. free(xlist);
  505. free(ylist);
  506. return(0);
  507. }
  508. /* Find first pixel opposite type along linear trajectory from */
  509. /* first minutia. */
  510. prevpix = *(bdata+(ylist[0]*iw)+xlist[0]);
  511. i = 1;
  512. found = FALSE;
  513. while(i < num){
  514. curpix = *(bdata+(ylist[i]*iw)+xlist[i]);
  515. if(curpix != prevpix){
  516. found = TRUE;
  517. break;
  518. }
  519. i++;
  520. }
  521. /* If opposite pixel not found ... then no ridges to count */
  522. if(!found){
  523. free(xlist);
  524. free(ylist);
  525. return(0);
  526. }
  527. /* Ready to count ridges, so initialize counter to 0. */
  528. ridge_count = 0;
  529. print2log("RIDGE COUNT: %d,%d to %d,%d ", minutia1->x, minutia1->y,
  530. minutia2->x, minutia2->y);
  531. /* While not at the end of the trajectory ... */
  532. while(i < num){
  533. /* If 0-to-1 transition not found ... */
  534. if(!find_transition(&i, 0, 1, xlist, ylist, num, bdata, iw, ih)){
  535. /* Then we are done looking for ridges. */
  536. free(xlist);
  537. free(ylist);
  538. print2log("\n");
  539. /* Return number of ridges counted to this point. */
  540. return(ridge_count);
  541. }
  542. /* Otherwise, we found a new ridge start transition, so store */
  543. /* its location (the location of the 1 in 0-to-1 transition). */
  544. ridge_start = i;
  545. print2log(": RS %d,%d ", xlist[i], ylist[i]);
  546. /* If 1-to-0 transition not found ... */
  547. if(!find_transition(&i, 1, 0, xlist, ylist, num, bdata, iw, ih)){
  548. /* Then we are done looking for ridges. */
  549. free(xlist);
  550. free(ylist);
  551. print2log("\n");
  552. /* Return number of ridges counted to this point. */
  553. return(ridge_count);
  554. }
  555. /* Otherwise, we found a new ridge end transition, so store */
  556. /* its location (the location of the 0 in 1-to-0 transition). */
  557. ridge_end = i;
  558. print2log("; RE %d,%d ", xlist[i], ylist[i]);
  559. /* Conduct the validation, tracing the contour of the ridge */
  560. /* from the ridge ending point a specified number of steps */
  561. /* scanning for neighbors clockwise and counter-clockwise. */
  562. /* If the ridge starting point is encounted during the trace */
  563. /* then we can assume we do not have a valid ridge crossing */
  564. /* and instead we are walking on and off the edge of the */
  565. /* side of a ridge. */
  566. ret = validate_ridge_crossing(ridge_start, ridge_end,
  567. xlist, ylist, num, bdata, iw, ih,
  568. lfsparms->max_ridge_steps);
  569. /* If system error ... */
  570. if(ret < 0){
  571. free(xlist);
  572. free(ylist);
  573. /* Return the error code. */
  574. return(ret);
  575. }
  576. print2log("; V%d ", ret);
  577. /* If validation result is TRUE ... */
  578. if(ret){
  579. /* Then assume we have found a valid ridge crossing and bump */
  580. /* the ridge counter. */
  581. ridge_count++;
  582. }
  583. /* Otherwise, ignore the current ridge start and end transitions */
  584. /* and go back and search for new ridge start. */
  585. }
  586. /* Deallocate working memories. */
  587. free(xlist);
  588. free(ylist);
  589. print2log("\n");
  590. /* Return the number of ridges counted. */
  591. return(ridge_count);
  592. }
  593. /*************************************************************************
  594. **************************************************************************
  595. #cat: find_transition - Takes a pixel trajectory and a starting index, and
  596. #cat: searches forward along the trajectory until the specified
  597. #cat: adjacent pixel pair is found, returning the index where
  598. #cat: the pair was found (the index of the second pixel).
  599. Input:
  600. iptr - pointer to starting pixel index into trajectory
  601. pix1 - first pixel value in transition pair
  602. pix2 - second pixel value in transition pair
  603. xlist - x-pixel coords of line trajectory
  604. ylist - y-pixel coords of line trajectory
  605. num - number of coords in line trajectory
  606. bdata - binary image data (0==while & 1==black)
  607. iw - width (in pixels) of image
  608. ih - height (in pixels) of image
  609. Output:
  610. iptr - points to location where 2nd pixel in pair is found
  611. Return Code:
  612. TRUE - pixel pair transition found
  613. FALSE - pixel pair transition not found
  614. **************************************************************************/
  615. int find_transition(int *iptr, const int pix1, const int pix2,
  616. const int *xlist, const int *ylist, const int num,
  617. unsigned char *bdata, const int iw, const int ih)
  618. {
  619. int i, j;
  620. /* Set previous index to starting position. */
  621. i = *iptr;
  622. /* Bump previous index by 1 to get next index. */
  623. j = i+1;
  624. /* While not one point from the end of the trajectory .. */
  625. while(i < num-1){
  626. /* If we have found the desired transition ... */
  627. if((*(bdata+(ylist[i]*iw)+xlist[i]) == pix1) &&
  628. (*(bdata+(ylist[j]*iw)+xlist[j]) == pix2)){
  629. /* Adjust the position pointer to the location of the */
  630. /* second pixel in the transition. */
  631. *iptr = j;
  632. /* Return TRUE. */
  633. return(TRUE);
  634. }
  635. /* Otherwise, the desired transition was not found in current */
  636. /* pixel pair, so bump to the next pair along the trajector. */
  637. i++;
  638. j++;
  639. }
  640. /* If we get here, then we exhausted the trajector without finding */
  641. /* the desired transition, so set the position pointer to the end */
  642. /* of the trajector, and return FALSE. */
  643. *iptr = num;
  644. return(FALSE);
  645. }
  646. /*************************************************************************
  647. **************************************************************************
  648. #cat: validate_ridge_crossing - Takes a pair of points, a ridge start
  649. #cat: transition and a ridge end transition, and walks the
  650. #cat: ridge contour from thre ridge end points a specified
  651. #cat: number of steps, looking for the ridge start point.
  652. #cat: If found, then transitions determined not to be a valid
  653. #cat: ridge crossing.
  654. Input:
  655. ridge_start - index into line trajectory of ridge start transition
  656. ridge_end - index into line trajectory of ridge end transition
  657. xlist - x-pixel coords of line trajectory
  658. ylist - y-pixel coords of line trajectory
  659. num - number of coords in line trajectory
  660. bdata - binary image data (0==while & 1==black)
  661. iw - width (in pixels) of image
  662. ih - height (in pixels) of image
  663. max_ridge_steps - number of steps taken in search in both
  664. scan directions
  665. Return Code:
  666. TRUE - ridge crossing VALID
  667. FALSE - ridge corssing INVALID
  668. Negative - system error
  669. **************************************************************************/
  670. int validate_ridge_crossing(const int ridge_start, const int ridge_end,
  671. const int *xlist, const int *ylist, const int num,
  672. unsigned char *bdata, const int iw, const int ih,
  673. const int max_ridge_steps)
  674. {
  675. int ret;
  676. int feat_x, feat_y, edge_x, edge_y;
  677. int *contour_x, *contour_y, *contour_ex, *contour_ey, ncontour;
  678. /* Assign edge pixel pair for contour trace. */
  679. feat_x = xlist[ridge_end];
  680. feat_y = ylist[ridge_end];
  681. edge_x = xlist[ridge_end-1];
  682. edge_y = ylist[ridge_end-1];
  683. /* Adjust pixel pair if they neighbor each other diagonally. */
  684. fix_edge_pixel_pair(&feat_x, &feat_y, &edge_x, &edge_y,
  685. bdata, iw, ih);
  686. /* Trace ridge contour, starting at the ridge end transition, and */
  687. /* taking a specified number of step scanning for edge neighbors */
  688. /* clockwise. As we trace the ridge, we want to detect if we */
  689. /* encounter the ridge start transition. NOTE: The ridge end */
  690. /* position is on the white (of a black to white transition) and */
  691. /* the ridge start is on the black (of a black to white trans), */
  692. /* so the edge trace needs to look for the what pixel (not the */
  693. /* black one) of the ridge start transition. */
  694. ret = trace_contour(&contour_x, &contour_y,
  695. &contour_ex, &contour_ey, &ncontour,
  696. max_ridge_steps,
  697. xlist[ridge_start-1], ylist[ridge_start-1],
  698. feat_x, feat_y, edge_x, edge_y,
  699. SCAN_CLOCKWISE, bdata, iw, ih);
  700. /* If a system error occurred ... */
  701. if(ret < 0)
  702. /* Return error code. */
  703. return(ret);
  704. /* Otherwise, if the trace was not IGNORED, then a contour was */
  705. /* was generated and returned. We aren't interested in the */
  706. /* actual contour, so deallocate it. */
  707. if(ret != IGNORE)
  708. free_contour(contour_x, contour_y, contour_ex, contour_ey);
  709. /* If the trace was IGNORED, then we had some sort of initialization */
  710. /* problem, so treat this the same as if was actually located the */
  711. /* ridge start point (in which case LOOP_FOUND is returned). */
  712. /* So, If not IGNORED and ridge start not encounted in trace ... */
  713. if((ret != IGNORE) &&
  714. (ret != LOOP_FOUND)){
  715. /* Now conduct contour trace scanning for edge neighbors counter- */
  716. /* clockwise. */
  717. ret = trace_contour(&contour_x, &contour_y,
  718. &contour_ex, &contour_ey, &ncontour,
  719. max_ridge_steps,
  720. xlist[ridge_start-1], ylist[ridge_start-1],
  721. feat_x, feat_y, edge_x, edge_y,
  722. SCAN_COUNTER_CLOCKWISE, bdata, iw, ih);
  723. /* If a system error occurred ... */
  724. if(ret < 0)
  725. /* Return error code. */
  726. return(ret);
  727. /* Otherwise, if the trace was not IGNORED, then a contour was */
  728. /* was generated and returned. We aren't interested in the */
  729. /* actual contour, so deallocate it. */
  730. if(ret != IGNORE)
  731. free_contour(contour_x, contour_y, contour_ex, contour_ey);
  732. /* If trace not IGNORED and ridge start not encounted in 2nd trace ... */
  733. if((ret != IGNORE) &&
  734. (ret != LOOP_FOUND)){
  735. /* If we get here, assume we have a ridge crossing. */
  736. return(TRUE);
  737. }
  738. /* Otherwise, second trace returned IGNORE or ridge start found. */
  739. }
  740. /* Otherwise, first trace returned IGNORE or ridge start found. */
  741. /* If we get here, then we failed to validate a ridge crossing. */
  742. return(FALSE);
  743. }