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