More NBIS cleanups
[libfprint.git] / libfprint / nbis / mindtct / ridges.c
blob0fb26863328c6e639d327075a1c54a6736d34851
1 /*******************************************************************************
3 License:
4 This software was developed at the National Institute of Standards and
5 Technology (NIST) by employees of the Federal Government in the course
6 of their official duties. Pursuant to title 17 Section 105 of the
7 United States Code, this software is not subject to copyright protection
8 and is in the public domain. NIST assumes no responsibility whatsoever for
9 its use by other parties, and makes no guarantees, expressed or implied,
10 about its quality, reliability, or any other characteristic.
12 Disclaimer:
13 This software was developed to promote biometric standards and biometric
14 technology testing for the Federal Government in accordance with the USA
15 PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act.
16 Specific hardware and software products identified in this software were used
17 in order to perform the software development. In no case does such
18 identification imply recommendation or endorsement by the National Institute
19 of Standards and Technology, nor does it imply that the products and equipment
20 identified are necessarily the best available for the purpose.
22 *******************************************************************************/
24 /***********************************************************************
25 LIBRARY: LFS - NIST Latent Fingerprint System
27 FILE: RIDGES.C
28 AUTHOR: Michael D. Garris
29 DATE: 08/09/1999
30 UPDATED: 03/16/2005 by MDG
32 Contains routines responsible for locating nearest minutia
33 neighbors and counting intervening ridges as part of the
34 NIST Latent Fingerprint System (LFS).
36 ***********************************************************************
37 ROUTINES:
38 count_minutiae_ridges()
39 count_minutia_ridges()
40 find_neighbors()
41 update_nbr_dists()
42 insert_neighbor()
43 sort_neighbors()
44 ridge_count()
45 find_transition()
46 validate_ridge_crossing()
47 ***********************************************************************/
49 #include <stdio.h>
50 #include <lfs.h>
51 #include <log.h>
53 /*************************************************************************
54 **************************************************************************
55 #cat: insert_neighbor - Takes a minutia index and its squared distance to a
56 #cat: primary minutia point, and inserts them in the specified
57 #cat: position of their respective lists, shifting previously
58 #cat: stored values down and off the lists as necessary.
60 Input:
61 pos - postions where values are to be inserted in lists
62 nbr_index - index of minutia being inserted
63 nbr_dist2 - squared distance of minutia to its primary point
64 nbr_list - current list of nearest neighbor minutia indices
65 nbr_sqr_dists - corresponding squared euclidean distance of each
66 neighbor to the primary minutia point
67 nnbrs - number of neighbors currently in the list
68 max_nbrs - maximum number of closest neighbors to be returned
69 Output:
70 nbr_list - updated list of nearest neighbor indices
71 nbr_sqr_dists - updated list of nearest neighbor distances
72 nnbrs - number of neighbors in the update lists
73 Return Code:
74 Zero - successful completion
75 Negative - system error
76 **************************************************************************/
77 static int insert_neighbor(const int pos, const int nbr_index, const double nbr_dist2,
78 int *nbr_list, double *nbr_sqr_dists,
79 int *nnbrs, const int max_nbrs)
81 int i;
83 /* If the desired insertion position is beyond one passed the last */
84 /* neighbor in the lists OR greater than equal to the maximum ... */
85 /* NOTE: pos is zero-oriented while nnbrs and max_nbrs are 1-oriented. */
86 if((pos > *nnbrs) ||
87 (pos >= max_nbrs)){
88 fprintf(stderr,
89 "ERROR : insert_neighbor : insertion point exceeds lists\n");
90 return(-480);
93 /* If the neighbor lists are NOT full ... */
94 if(*nnbrs < max_nbrs){
95 /* Then we have room to shift everything down to make room for new */
96 /* neighbor and increase the number of neighbors stored by 1. */
97 i = *nnbrs-1;
98 (*nnbrs)++;
100 /* Otherwise, the neighbors lists are full ... */
101 else if(*nnbrs == max_nbrs)
102 /* So, we must bump the last neighbor in the lists off to make */
103 /* room for the new neighbor (ignore last neighbor in lists). */
104 i = *nnbrs-2;
105 /* Otherwise, there is a list overflow error condition */
106 /* (shouldn't ever happen, but just in case) ... */
107 else{
108 fprintf(stderr,
109 "ERROR : insert_neighbor : overflow in neighbor lists\n");
110 return(-481);
113 /* While we havn't reached the desired insertion point ... */
114 while(i >= pos){
115 /* Shift the current neighbor down the list 1 positon. */
116 nbr_list[i+1] = nbr_list[i];
117 nbr_sqr_dists[i+1] = nbr_sqr_dists[i];
118 i--;
121 /* We are now ready to put our new neighbor in the position where */
122 /* we shifted everything down from to make room. */
123 nbr_list[pos] = nbr_index;
124 nbr_sqr_dists[pos] = nbr_dist2;
126 /* Return normally. */
127 return(0);
130 /*************************************************************************
131 **************************************************************************
132 #cat: update_nbr_dists - Takes the current list of neighbors along with a
133 #cat: primary minutia and a potential new neighbor, and
134 #cat: determines if the new neighbor is sufficiently close
135 #cat: to be added to the list of nearest neighbors. If added,
136 #cat: it is placed in the list in its proper order based on
137 #cat: squared distance to the primary point.
139 Input:
140 nbr_list - current list of nearest neighbor minutia indices
141 nbr_sqr_dists - corresponding squared euclidean distance of each
142 neighbor to the primary minutia point
143 nnbrs - number of neighbors currently in the list
144 max_nbrs - maximum number of closest neighbors to be returned
145 first - index of the primary minutia point
146 second - index of the secondary (new neighbor) point
147 minutiae - list of minutiae
148 Output:
149 nbr_list - updated list of nearest neighbor indices
150 nbr_sqr_dists - updated list of nearest neighbor distances
151 nnbrs - number of neighbors in the update lists
152 Return Code:
153 Zero - successful completion
154 Negative - system error
155 **************************************************************************/
156 static int update_nbr_dists(int *nbr_list, double *nbr_sqr_dists,
157 int *nnbrs, const int max_nbrs,
158 const int first, const int second, MINUTIAE *minutiae)
160 double dist2;
161 MINUTIA *minutia1, *minutia2;
162 int pos, last_nbr;
164 /* Compute position of maximum last neighbor stored. */
165 last_nbr = max_nbrs - 1;
167 /* Assigne temporary minutia pointers. */
168 minutia1 = minutiae->list[first];
169 minutia2 = minutiae->list[second];
171 /* Compute squared euclidean distance between minutia pair. */
172 dist2 = squared_distance(minutia1->x, minutia1->y,
173 minutia2->x, minutia2->y);
175 /* If maximum number of neighbors not yet stored in lists OR */
176 /* if the squared distance to current secondary is less */
177 /* than the largest stored neighbor distance ... */
178 if((*nnbrs < max_nbrs) ||
179 (dist2 < nbr_sqr_dists[last_nbr])){
181 /* Find insertion point in neighbor lists. */
182 pos = find_incr_position_dbl(dist2, nbr_sqr_dists, *nnbrs);
183 /* If the position returned is >= maximum list length (this should */
184 /* never happen, but just in case) ... */
185 if(pos >= max_nbrs){
186 fprintf(stderr,
187 "ERROR : update_nbr_dists : illegal position for new neighbor\n");
188 return(-470);
190 /* Insert the new neighbor into the neighbor lists at the */
191 /* specified location. */
192 if(insert_neighbor(pos, second, dist2,
193 nbr_list, nbr_sqr_dists, nnbrs, max_nbrs))
194 return(-471);
196 /* Otherwise, neighbor inserted successfully, so return normally. */
197 return(0);
199 /* Otherwise, the new neighbor is not sufficiently close to be */
200 /* added or inserted into the neighbor lists, so ignore the neighbor */
201 /* and return normally. */
202 else
203 return(0);
207 /*************************************************************************
208 **************************************************************************
209 #cat: find_neighbors - Takes a primary minutia and a list of all minutiae
210 #cat: and locates a specified maximum number of closest neighbors
211 #cat: to the primary point. Neighbors are searched, starting
212 #cat: in the same pixel column, below, the primary point and then
213 #cat: along consecutive and complete pixel columns in the image
214 #cat: to the right of the primary point.
216 Input:
217 max_nbrs - maximum number of closest neighbors to be returned
218 first - index of the primary minutia point
219 minutiae - list of minutiae
220 Output:
221 onbr_list - points to list of detected closest neighbors
222 onnbrs - points to number of neighbors returned
223 Return Code:
224 Zero - successful completion
225 Negative - system error
226 **************************************************************************/
227 static int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs,
228 const int first, MINUTIAE *minutiae)
230 int ret, second, last_nbr;
231 MINUTIA *minutia1, *minutia2;
232 int *nbr_list, nnbrs;
233 double *nbr_sqr_dists, xdist, xdist2;
235 /* Allocate list of neighbor minutiae indices. */
236 nbr_list = (int *)malloc(max_nbrs * sizeof(int));
237 if(nbr_list == (int *)NULL){
238 fprintf(stderr, "ERROR : find_neighbors : malloc : nbr_list\n");
239 return(-460);
242 /* Allocate list of squared euclidean distances between neighbors */
243 /* and current primary minutia point. */
244 nbr_sqr_dists = (double *)malloc(max_nbrs * sizeof(double));
245 if(nbr_sqr_dists == (double *)NULL){
246 free(nbr_list);
247 fprintf(stderr,
248 "ERROR : find_neighbors : malloc : nbr_sqr_dists\n");
249 return(-461);
252 /* Initialize number of stored neighbors to 0. */
253 nnbrs = 0;
254 /* Assign secondary to one passed current primary minutia. */
255 second = first + 1;
256 /* Compute location of maximum last stored neighbor. */
257 last_nbr = max_nbrs - 1;
259 /* While minutia (in sorted order) still remian for processing ... */
260 /* NOTE: The minutia in the input list have been sorted on X and */
261 /* then on Y. So, the neighbors are selected according to those */
262 /* that lie below the primary minutia in the same pixel column and */
263 /* then subsequently those that lie in complete pixel columns to */
264 /* the right of the primary minutia. */
265 while(second < minutiae->num){
266 /* Assign temporary minutia pointers. */
267 minutia1 = minutiae->list[first];
268 minutia2 = minutiae->list[second];
270 /* Compute squared distance between minutiae along x-axis. */
271 xdist = minutia2->x - minutia1->x;
272 xdist2 = xdist * xdist;
274 /* If the neighbor lists are not full OR the x-distance to current */
275 /* secondary is smaller than maximum neighbor distance stored ... */
276 if((nnbrs < max_nbrs) ||
277 (xdist2 < nbr_sqr_dists[last_nbr])){
278 /* Append or insert the new neighbor into the neighbor lists. */
279 if((ret = update_nbr_dists(nbr_list, nbr_sqr_dists, &nnbrs, max_nbrs,
280 first, second, minutiae))){
281 free(nbr_sqr_dists);
282 return(ret);
285 /* Otherwise, if the neighbor lists is full AND the x-distance */
286 /* to current secondary is larger than maximum neighbor distance */
287 /* stored ... */
288 else
289 /* So, stop searching for more neighbors. */
290 break;
292 /* Bump to next secondary minutia. */
293 second++;
296 /* Deallocate working memory. */
297 free(nbr_sqr_dists);
299 /* If no neighbors found ... */
300 if(nnbrs == 0){
301 /* Deallocate the neighbor list. */
302 free(nbr_list);
303 *onnbrs = 0;
305 /* Otherwise, assign neighbors to output pointer. */
306 else{
307 *onbr_list = nbr_list;
308 *onnbrs = nnbrs;
311 /* Return normally. */
312 return(0);
315 /*************************************************************************
316 **************************************************************************
317 #cat: sort_neighbors - Takes a list of primary minutia and its neighboring
318 #cat: minutia indices and sorts the neighbors based on their
319 #cat: position relative to the primary minutia point. Neighbors
320 #cat: are sorted starting vertical to the primary point and
321 #cat: proceeding clockwise.
323 Input:
324 nbr_list - list of neighboring minutia indices
325 nnbrs - number of neighbors in the list
326 first - the index of the primary minutia point
327 minutiae - list of minutiae
328 Output:
329 nbr_list - neighboring minutia indices in sorted order
330 Return Code:
331 Zero - successful completion
332 Negative - system error
333 **************************************************************************/
334 static int sort_neighbors(int *nbr_list, const int nnbrs, const int first,
335 MINUTIAE *minutiae)
337 double *join_thetas, theta;
338 int i;
339 static double pi2 = M_PI*2.0;
341 /* List of angles of lines joining the current primary to each */
342 /* of the secondary neighbors. */
343 join_thetas = (double *)malloc(nnbrs * sizeof(double));
344 if(join_thetas == (double *)NULL){
345 fprintf(stderr, "ERROR : sort_neighbors : malloc : join_thetas\n");
346 return(-490);
349 for(i = 0; i < nnbrs; i++){
350 /* Compute angle to line connecting the 2 points. */
351 /* Coordinates are swapped and order of points reversed to */
352 /* account for 0 direction is vertical and positive direction */
353 /* is clockwise. */
354 theta = angle2line(minutiae->list[nbr_list[i]]->y,
355 minutiae->list[nbr_list[i]]->x,
356 minutiae->list[first]->y,
357 minutiae->list[first]->x);
359 /* Make sure the angle is positive. */
360 theta += pi2;
361 theta = fmod(theta, pi2);
362 join_thetas[i] = theta;
365 /* Sort the neighbor indicies into rank order. */
366 bubble_sort_double_inc_2(join_thetas, nbr_list, nnbrs);
368 /* Deallocate the list of angles. */
369 free(join_thetas);
371 /* Return normally. */
372 return(0);
375 /*************************************************************************
376 **************************************************************************
377 #cat: find_transition - Takes a pixel trajectory and a starting index, and
378 #cat: searches forward along the trajectory until the specified
379 #cat: adjacent pixel pair is found, returning the index where
380 #cat: the pair was found (the index of the second pixel).
382 Input:
383 iptr - pointer to starting pixel index into trajectory
384 pix1 - first pixel value in transition pair
385 pix2 - second pixel value in transition pair
386 xlist - x-pixel coords of line trajectory
387 ylist - y-pixel coords of line trajectory
388 num - number of coords in line trajectory
389 bdata - binary image data (0==while & 1==black)
390 iw - width (in pixels) of image
391 ih - height (in pixels) of image
392 Output:
393 iptr - points to location where 2nd pixel in pair is found
394 Return Code:
395 TRUE - pixel pair transition found
396 FALSE - pixel pair transition not found
397 **************************************************************************/
398 static int find_transition(int *iptr, const int pix1, const int pix2,
399 const int *xlist, const int *ylist, const int num,
400 unsigned char *bdata, const int iw, const int ih)
402 int i, j;
404 /* Set previous index to starting position. */
405 i = *iptr;
406 /* Bump previous index by 1 to get next index. */
407 j = i+1;
409 /* While not one point from the end of the trajectory .. */
410 while(i < num-1){
411 /* If we have found the desired transition ... */
412 if((*(bdata+(ylist[i]*iw)+xlist[i]) == pix1) &&
413 (*(bdata+(ylist[j]*iw)+xlist[j]) == pix2)){
414 /* Adjust the position pointer to the location of the */
415 /* second pixel in the transition. */
416 *iptr = j;
418 /* Return TRUE. */
419 return(TRUE);
421 /* Otherwise, the desired transition was not found in current */
422 /* pixel pair, so bump to the next pair along the trajector. */
423 i++;
424 j++;
427 /* If we get here, then we exhausted the trajector without finding */
428 /* the desired transition, so set the position pointer to the end */
429 /* of the trajector, and return FALSE. */
430 *iptr = num;
431 return(FALSE);
434 /*************************************************************************
435 **************************************************************************
436 #cat: validate_ridge_crossing - Takes a pair of points, a ridge start
437 #cat: transition and a ridge end transition, and walks the
438 #cat: ridge contour from thre ridge end points a specified
439 #cat: number of steps, looking for the ridge start point.
440 #cat: If found, then transitions determined not to be a valid
441 #cat: ridge crossing.
443 Input:
444 ridge_start - index into line trajectory of ridge start transition
445 ridge_end - index into line trajectory of ridge end transition
446 xlist - x-pixel coords of line trajectory
447 ylist - y-pixel coords of line trajectory
448 num - number of coords in line trajectory
449 bdata - binary image data (0==while & 1==black)
450 iw - width (in pixels) of image
451 ih - height (in pixels) of image
452 max_ridge_steps - number of steps taken in search in both
453 scan directions
454 Return Code:
455 TRUE - ridge crossing VALID
456 FALSE - ridge corssing INVALID
457 Negative - system error
458 **************************************************************************/
459 static int validate_ridge_crossing(const int ridge_start, const int ridge_end,
460 const int *xlist, const int *ylist, const int num,
461 unsigned char *bdata, const int iw, const int ih,
462 const int max_ridge_steps)
464 int ret;
465 int feat_x, feat_y, edge_x, edge_y;
466 int *contour_x, *contour_y, *contour_ex, *contour_ey, ncontour;
468 /* Assign edge pixel pair for contour trace. */
469 feat_x = xlist[ridge_end];
470 feat_y = ylist[ridge_end];
471 edge_x = xlist[ridge_end-1];
472 edge_y = ylist[ridge_end-1];
474 /* Adjust pixel pair if they neighbor each other diagonally. */
475 fix_edge_pixel_pair(&feat_x, &feat_y, &edge_x, &edge_y,
476 bdata, iw, ih);
478 /* Trace ridge contour, starting at the ridge end transition, and */
479 /* taking a specified number of step scanning for edge neighbors */
480 /* clockwise. As we trace the ridge, we want to detect if we */
481 /* encounter the ridge start transition. NOTE: The ridge end */
482 /* position is on the white (of a black to white transition) and */
483 /* the ridge start is on the black (of a black to white trans), */
484 /* so the edge trace needs to look for the what pixel (not the */
485 /* black one) of the ridge start transition. */
486 ret = trace_contour(&contour_x, &contour_y,
487 &contour_ex, &contour_ey, &ncontour,
488 max_ridge_steps,
489 xlist[ridge_start-1], ylist[ridge_start-1],
490 feat_x, feat_y, edge_x, edge_y,
491 SCAN_CLOCKWISE, bdata, iw, ih);
492 /* If a system error occurred ... */
493 if(ret < 0)
494 /* Return error code. */
495 return(ret);
497 /* Otherwise, if the trace was not IGNORED, then a contour was */
498 /* was generated and returned. We aren't interested in the */
499 /* actual contour, so deallocate it. */
500 if(ret != IGNORE)
501 free_contour(contour_x, contour_y, contour_ex, contour_ey);
503 /* If the trace was IGNORED, then we had some sort of initialization */
504 /* problem, so treat this the same as if was actually located the */
505 /* ridge start point (in which case LOOP_FOUND is returned). */
506 /* So, If not IGNORED and ridge start not encounted in trace ... */
507 if((ret != IGNORE) &&
508 (ret != LOOP_FOUND)){
510 /* Now conduct contour trace scanning for edge neighbors counter- */
511 /* clockwise. */
512 ret = trace_contour(&contour_x, &contour_y,
513 &contour_ex, &contour_ey, &ncontour,
514 max_ridge_steps,
515 xlist[ridge_start-1], ylist[ridge_start-1],
516 feat_x, feat_y, edge_x, edge_y,
517 SCAN_COUNTER_CLOCKWISE, bdata, iw, ih);
518 /* If a system error occurred ... */
519 if(ret < 0)
520 /* Return error code. */
521 return(ret);
523 /* Otherwise, if the trace was not IGNORED, then a contour was */
524 /* was generated and returned. We aren't interested in the */
525 /* actual contour, so deallocate it. */
526 if(ret != IGNORE)
527 free_contour(contour_x, contour_y, contour_ex, contour_ey);
529 /* If trace not IGNORED and ridge start not encounted in 2nd trace ... */
530 if((ret != IGNORE) &&
531 (ret != LOOP_FOUND)){
532 /* If we get here, assume we have a ridge crossing. */
533 return(TRUE);
535 /* Otherwise, second trace returned IGNORE or ridge start found. */
537 /* Otherwise, first trace returned IGNORE or ridge start found. */
539 /* If we get here, then we failed to validate a ridge crossing. */
540 return(FALSE);
543 /*************************************************************************
544 **************************************************************************
545 #cat: ridge_count - Takes a pair of minutiae, and counts the number of
546 #cat: ridges crossed along the linear trajectory connecting
547 #cat: the 2 points in the image.
549 Input:
550 first - index of primary minutia
551 second - index of secondary (neighbor) minutia
552 minutiae - list of minutiae
553 bdata - binary image data (0==while & 1==black)
554 iw - width (in pixels) of image
555 ih - height (in pixels) of image
556 lfsparms - parameters and thresholds for controlling LFS
557 Return Code:
558 Zero or Positive - number of ridges counted
559 Negative - system error
560 **************************************************************************/
561 static int ridge_count(const int first, const int second, MINUTIAE *minutiae,
562 unsigned char *bdata, const int iw, const int ih,
563 const LFSPARMS *lfsparms)
565 MINUTIA *minutia1, *minutia2;
566 int i, ret, found;
567 int *xlist, *ylist, num;
568 int ridge_count, ridge_start, ridge_end;
569 int prevpix, curpix;
571 minutia1 = minutiae->list[first];
572 minutia2 = minutiae->list[second];
574 /* If the 2 mintuia have identical pixel coords ... */
575 if((minutia1->x == minutia2->x) &&
576 (minutia1->y == minutia2->y))
577 /* Then zero ridges between points. */
578 return(0);
580 /* Compute linear trajectory of contiguous pixels between first */
581 /* and second minutia points. */
582 if((ret = line_points(&xlist, &ylist, &num,
583 minutia1->x, minutia1->y, minutia2->x, minutia2->y))){
584 return(ret);
587 /* It there are no points on the line trajectory, then no ridges */
588 /* to count (this should not happen, but just in case) ... */
589 if(num == 0){
590 free(xlist);
591 free(ylist);
592 return(0);
595 /* Find first pixel opposite type along linear trajectory from */
596 /* first minutia. */
597 prevpix = *(bdata+(ylist[0]*iw)+xlist[0]);
598 i = 1;
599 found = FALSE;
600 while(i < num){
601 curpix = *(bdata+(ylist[i]*iw)+xlist[i]);
602 if(curpix != prevpix){
603 found = TRUE;
604 break;
606 i++;
609 /* If opposite pixel not found ... then no ridges to count */
610 if(!found){
611 free(xlist);
612 free(ylist);
613 return(0);
616 /* Ready to count ridges, so initialize counter to 0. */
617 ridge_count = 0;
619 print2log("RIDGE COUNT: %d,%d to %d,%d ", minutia1->x, minutia1->y,
620 minutia2->x, minutia2->y);
622 /* While not at the end of the trajectory ... */
623 while(i < num){
624 /* If 0-to-1 transition not found ... */
625 if(!find_transition(&i, 0, 1, xlist, ylist, num, bdata, iw, ih)){
626 /* Then we are done looking for ridges. */
627 free(xlist);
628 free(ylist);
630 print2log("\n");
632 /* Return number of ridges counted to this point. */
633 return(ridge_count);
635 /* Otherwise, we found a new ridge start transition, so store */
636 /* its location (the location of the 1 in 0-to-1 transition). */
637 ridge_start = i;
639 print2log(": RS %d,%d ", xlist[i], ylist[i]);
641 /* If 1-to-0 transition not found ... */
642 if(!find_transition(&i, 1, 0, xlist, ylist, num, bdata, iw, ih)){
643 /* Then we are done looking for ridges. */
644 free(xlist);
645 free(ylist);
647 print2log("\n");
649 /* Return number of ridges counted to this point. */
650 return(ridge_count);
652 /* Otherwise, we found a new ridge end transition, so store */
653 /* its location (the location of the 0 in 1-to-0 transition). */
654 ridge_end = i;
656 print2log("; RE %d,%d ", xlist[i], ylist[i]);
658 /* Conduct the validation, tracing the contour of the ridge */
659 /* from the ridge ending point a specified number of steps */
660 /* scanning for neighbors clockwise and counter-clockwise. */
661 /* If the ridge starting point is encounted during the trace */
662 /* then we can assume we do not have a valid ridge crossing */
663 /* and instead we are walking on and off the edge of the */
664 /* side of a ridge. */
665 ret = validate_ridge_crossing(ridge_start, ridge_end,
666 xlist, ylist, num, bdata, iw, ih,
667 lfsparms->max_ridge_steps);
669 /* If system error ... */
670 if(ret < 0){
671 free(xlist);
672 free(ylist);
673 /* Return the error code. */
674 return(ret);
677 print2log("; V%d ", ret);
679 /* If validation result is TRUE ... */
680 if(ret){
681 /* Then assume we have found a valid ridge crossing and bump */
682 /* the ridge counter. */
683 ridge_count++;
686 /* Otherwise, ignore the current ridge start and end transitions */
687 /* and go back and search for new ridge start. */
690 /* Deallocate working memories. */
691 free(xlist);
692 free(ylist);
694 print2log("\n");
696 /* Return the number of ridges counted. */
697 return(ridge_count);
700 /*************************************************************************
701 **************************************************************************
702 #cat: count_minutia_ridges - Takes a minutia, and determines its closest
703 #cat: neighbors and counts the number of interveining ridges
704 #cat: between the minutia point and each of its neighbors.
706 Input:
707 minutia - input minutia
708 bdata - binary image data (0==while & 1==black)
709 iw - width (in pixels) of image
710 ih - height (in pixels) of image
711 lfsparms - parameters and thresholds for controlling LFS
712 Output:
713 minutiae - minutia augmented with neighbors and ridge counts
714 Return Code:
715 Zero - successful completion
716 Negative - system error
717 **************************************************************************/
718 static int count_minutia_ridges(const int first, MINUTIAE *minutiae,
719 unsigned char *bdata, const int iw, const int ih,
720 const LFSPARMS *lfsparms)
722 int i, ret, *nbr_list, *nbr_nridges, nnbrs;
724 /* Find up to the maximum number of qualifying neighbors. */
725 if((ret = find_neighbors(&nbr_list, &nnbrs, lfsparms->max_nbrs,
726 first, minutiae))){
727 free(nbr_list);
728 return(ret);
731 print2log("NBRS FOUND: %d,%d = %d\n", minutiae->list[first]->x,
732 minutiae->list[first]->y, nnbrs);
734 /* If no neighors found ... */
735 if(nnbrs == 0){
736 /* Then no list returned and no ridges to count. */
737 return(0);
740 /* Sort neighbors on delta dirs. */
741 if((ret = sort_neighbors(nbr_list, nnbrs, first, minutiae))){
742 free(nbr_list);
743 return(ret);
746 /* Count ridges between first and neighbors. */
747 /* List of ridge counts, one for each neighbor stored. */
748 nbr_nridges = (int *)malloc(nnbrs * sizeof(int));
749 if(nbr_nridges == (int *)NULL){
750 free(nbr_list);
751 fprintf(stderr, "ERROR : count_minutia_ridges : malloc : nbr_nridges\n");
752 return(-450);
755 /* Foreach neighbor found and sorted in list ... */
756 for(i = 0; i < nnbrs; i++){
757 /* Count the ridges between the primary minutia and the neighbor. */
758 ret = ridge_count(first, nbr_list[i], minutiae, bdata, iw, ih, lfsparms);
759 /* If system error ... */
760 if(ret < 0){
761 /* Deallocate working memories. */
762 free(nbr_list);
763 free(nbr_nridges);
764 /* Return error code. */
765 return(ret);
768 /* Otherwise, ridge count successful, so store ridge count to list. */
769 nbr_nridges[i] = ret;
772 /* Assign neighbor indices and ridge counts to primary minutia. */
773 minutiae->list[first]->nbrs = nbr_list;
774 minutiae->list[first]->ridge_counts = nbr_nridges;
775 minutiae->list[first]->num_nbrs = nnbrs;
777 /* Return normally. */
778 return(0);
781 /*************************************************************************
782 **************************************************************************
783 #cat: count_minutiae_ridges - Takes a list of minutiae, and for each one,
784 #cat: determines its closest neighbors and counts the number
785 #cat: of interveining ridges between the minutia point and
786 #cat: each of its neighbors.
788 Input:
789 minutiae - list of minutiae
790 bdata - binary image data (0==while & 1==black)
791 iw - width (in pixels) of image
792 ih - height (in pixels) of image
793 lfsparms - parameters and thresholds for controlling LFS
794 Output:
795 minutiae - list of minutiae augmented with neighbors and ridge counts
796 Return Code:
797 Zero - successful completion
798 Negative - system error
799 **************************************************************************/
800 int count_minutiae_ridges(MINUTIAE *minutiae,
801 unsigned char *bdata, const int iw, const int ih,
802 const LFSPARMS *lfsparms)
804 int ret;
805 int i;
807 print2log("\nFINDING NBRS AND COUNTING RIDGES:\n");
809 /* Sort minutia points on x then y (column-oriented). */
810 if((ret = sort_minutiae_x_y(minutiae, iw, ih))){
811 return(ret);
814 /* Remove any duplicate minutia points from the list. */
815 if((ret = rm_dup_minutiae(minutiae))){
816 return(ret);
819 /* Foreach remaining sorted minutia in list ... */
820 for(i = 0; i < minutiae->num-1; i++){
821 /* Located neighbors and count number of ridges in between. */
822 /* NOTE: neighbor and ridge count results are stored in */
823 /* minutiae->list[i]. */
824 if((ret = count_minutia_ridges(i, minutiae, bdata, iw, ih, lfsparms))){
825 return(ret);
829 /* Return normally. */
830 return(0);