1 /*******************************************************************************
2 
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.
11 
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.
21 
22 *******************************************************************************/
23 
24 /***********************************************************************
25       LIBRARY: LFS - NIST Latent Fingerprint System
26 
27       FILE:    RIDGES.C
28       AUTHOR:  Michael D. Garris
29       DATE:    08/09/1999
30       UPDATED: 03/16/2005 by MDG
31 
32       Contains routines responsible for locating nearest minutia
33       neighbors and counting intervening ridges as part of the
34       NIST Latent Fingerprint System (LFS).
35 
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 ***********************************************************************/
48 
49 #include <stdio.h>
50 #include <lfs.h>
51 #include <log.h>
52 
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.
59 
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 **************************************************************************/
insert_neighbor(const int pos,const int nbr_index,const double nbr_dist2,int * nbr_list,double * nbr_sqr_dists,int * nnbrs,const int max_nbrs)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)
80 {
81    int i;
82 
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);
91    }
92 
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)++;
99    }
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);
111    }
112 
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--;
119    }
120 
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;
125 
126    /* Return normally. */
127    return(0);
128 }
129 
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.
138 
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 **************************************************************************/
update_nbr_dists(int * nbr_list,double * nbr_sqr_dists,int * nnbrs,const int max_nbrs,const int first,const int second,MINUTIAE * minutiae)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)
159 {
160    double dist2;
161    MINUTIA *minutia1, *minutia2;
162    int pos, last_nbr;
163 
164    /* Compute position of maximum last neighbor stored. */
165    last_nbr = max_nbrs - 1;
166 
167    /* Assigne temporary minutia pointers. */
168    minutia1 = minutiae->list[first];
169    minutia2 = minutiae->list[second];
170 
171    /* Compute squared euclidean distance between minutia pair. */
172    dist2 = squared_distance(minutia1->x, minutia1->y,
173                             minutia2->x, minutia2->y);
174 
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])){
180 
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);
189       }
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);
195 
196       /* Otherwise, neighbor inserted successfully, so return normally. */
197       return(0);
198    }
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);
204 
205 }
206 
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.
215 
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 **************************************************************************/
find_neighbors(int ** onbr_list,int * onnbrs,const int max_nbrs,const int first,MINUTIAE * minutiae)227 static int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs,
228                    const int first, MINUTIAE *minutiae)
229 {
230    int ret, second, last_nbr;
231    MINUTIA *minutia1, *minutia2;
232    int *nbr_list, nnbrs;
233    double *nbr_sqr_dists, xdist, xdist2;
234 
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);
240    }
241 
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);
250    }
251 
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;
258 
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];
269 
270       /* Compute squared distance between minutiae along x-axis. */
271       xdist = minutia2->x - minutia1->x;
272       xdist2 = xdist * xdist;
273 
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);
283          }
284       }
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;
291 
292        /* Bump to next secondary minutia. */
293        second++;
294    }
295 
296    /* Deallocate working memory. */
297    free(nbr_sqr_dists);
298 
299    /* If no neighbors found ... */
300    if(nnbrs == 0){
301       /* Deallocate the neighbor list. */
302       free(nbr_list);
303       *onnbrs = 0;
304    }
305    /* Otherwise, assign neighbors to output pointer. */
306    else{
307       *onbr_list = nbr_list;
308       *onnbrs = nnbrs;
309    }
310 
311    /* Return normally. */
312    return(0);
313 }
314 
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.
322 
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 **************************************************************************/
sort_neighbors(int * nbr_list,const int nnbrs,const int first,MINUTIAE * minutiae)334 static int sort_neighbors(int *nbr_list, const int nnbrs, const int first,
335                    MINUTIAE *minutiae)
336 {
337    double *join_thetas, theta;
338    int i;
339    static double pi2 = M_PI*2.0;
340 
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);
347    }
348 
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);
358 
359       /* Make sure the angle is positive. */
360       theta += pi2;
361       theta = fmod(theta, pi2);
362       join_thetas[i] = theta;
363    }
364 
365    /* Sort the neighbor indicies into rank order. */
366    bubble_sort_double_inc_2(join_thetas, nbr_list, nnbrs);
367 
368    /* Deallocate the list of angles. */
369    free(join_thetas);
370 
371    /* Return normally. */
372    return(0);
373 }
374 
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).
381 
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 **************************************************************************/
find_transition(int * iptr,const int pix1,const int pix2,const int * xlist,const int * ylist,const int num,unsigned char * bdata,const int iw,const int ih)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)
401 {
402    int i, j;
403 
404    /* Set previous index to starting position. */
405    i = *iptr;
406    /* Bump previous index by 1 to get next index. */
407    j = i+1;
408 
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;
417 
418          /* Return TRUE. */
419          return(TRUE);
420       }
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++;
425    }
426 
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);
432 }
433 
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.
442 
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 **************************************************************************/
validate_ridge_crossing(const int ridge_start,const int ridge_end,const int * xlist,const int * ylist,const int num,unsigned char * bdata,const int iw,const int ih,const int max_ridge_steps)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)
463 {
464    int ret;
465    int feat_x, feat_y, edge_x, edge_y;
466    int *contour_x, *contour_y, *contour_ex, *contour_ey, ncontour;
467 
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];
473 
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);
477 
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);
496 
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);
502 
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)){
509 
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);
522 
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);
528 
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);
534       }
535       /* Otherwise, second trace returned IGNORE or ridge start found. */
536    }
537    /* Otherwise, first trace returned IGNORE or ridge start found. */
538 
539    /* If we get here, then we failed to validate a ridge crossing. */
540    return(FALSE);
541 }
542 
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.
548 
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 **************************************************************************/
ridge_count(const int first,const int second,MINUTIAE * minutiae,unsigned char * bdata,const int iw,const int ih,const LFSPARMS * lfsparms)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)
564 {
565    MINUTIA *minutia1, *minutia2;
566    int i, ret, found;
567    int *xlist, *ylist, num;
568    int ridge_cnt, ridge_start, ridge_end;
569    int prevpix, curpix;
570 
571    minutia1 = minutiae->list[first];
572    minutia2 = minutiae->list[second];
573 
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);
579 
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);
585    }
586 
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);
593    }
594 
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;
605       }
606       i++;
607    }
608 
609    /* If opposite pixel not found ... then no ridges to count */
610    if(!found){
611       free(xlist);
612       free(ylist);
613       return(0);
614    }
615 
616    /* Ready to count ridges, so initialize counter to 0. */
617    ridge_cnt = 0;
618 
619    print2log("RIDGE COUNT: %d,%d to %d,%d ", minutia1->x, minutia1->y,
620                                                minutia2->x, minutia2->y);
621 
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);
629 
630          print2log("\n");
631 
632          /* Return number of ridges counted to this point. */
633          return(ridge_cnt);
634       }
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;
638 
639       print2log(": RS %d,%d ", xlist[i], ylist[i]);
640 
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);
646 
647          print2log("\n");
648 
649          /* Return number of ridges counted to this point. */
650          return(ridge_cnt);
651       }
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;
655 
656       print2log("; RE %d,%d ", xlist[i], ylist[i]);
657 
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);
668 
669       /* If system error ... */
670       if(ret < 0){
671          free(xlist);
672          free(ylist);
673          /* Return the error code. */
674          return(ret);
675       }
676 
677       print2log("; V%d ", ret);
678 
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_cnt++;
684       }
685 
686       /* Otherwise, ignore the current ridge start and end transitions */
687       /* and go back and search for new ridge start.                   */
688    }
689 
690    /* Deallocate working memories. */
691    free(xlist);
692    free(ylist);
693 
694    print2log("\n");
695 
696    /* Return the number of ridges counted. */
697    return(ridge_cnt);
698 }
699 
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.
705 
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 **************************************************************************/
count_minutia_ridges(const int first,MINUTIAE * minutiae,unsigned char * bdata,const int iw,const int ih,const LFSPARMS * lfsparms)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)
721 {
722    int i, ret, *nbr_list = NULL, *nbr_nridges, nnbrs;
723 
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);
729    }
730 
731    print2log("NBRS FOUND: %d,%d = %d\n", minutiae->list[first]->x,
732               minutiae->list[first]->y, nnbrs);
733 
734    /* If no neighors found ... */
735    if(nnbrs == 0){
736       /* Then no list returned and no ridges to count. */
737       return(0);
738    }
739 
740    /* Sort neighbors on delta dirs. */
741    if((ret = sort_neighbors(nbr_list, nnbrs, first, minutiae))){
742       free(nbr_list);
743       return(ret);
744    }
745 
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);
753    }
754 
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);
766       }
767 
768       /* Otherwise, ridge count successful, so store ridge count to list. */
769       nbr_nridges[i] = ret;
770    }
771 
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;
776 
777    /* Return normally. */
778    return(0);
779 }
780 
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.
787 
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 **************************************************************************/
count_minutiae_ridges(MINUTIAE * minutiae,unsigned char * bdata,const int iw,const int ih,const LFSPARMS * lfsparms)800 int count_minutiae_ridges(MINUTIAE *minutiae,
801                       unsigned char *bdata, const int iw, const int ih,
802                       const LFSPARMS *lfsparms)
803 {
804    int ret;
805    int i;
806 
807    print2log("\nFINDING NBRS AND COUNTING RIDGES:\n");
808 
809    /* Sort minutia points on x then y (column-oriented). */
810    if((ret = sort_minutiae_x_y(minutiae, iw, ih))){
811       return(ret);
812    }
813 
814    /* Remove any duplicate minutia points from the list. */
815    if((ret = rm_dup_minutiae(minutiae))){
816       return(ret);
817    }
818 
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);
826       }
827    }
828 
829    /* Return normally. */
830    return(0);
831 }
832 
833