1 /*******************************************************************************
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.
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
28 AUTHOR: Michael D. Garris
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 ***********************************************************************
38 count_minutiae_ridges()
39 count_minutia_ridges()
46 validate_ridge_crossing()
47 ***********************************************************************/
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.
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
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
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
)
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. */
89 "ERROR : insert_neighbor : insertion point exceeds lists\n");
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. */
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). */
105 /* Otherwise, there is a list overflow error condition */
106 /* (shouldn't ever happen, but just in case) ... */
109 "ERROR : insert_neighbor : overflow in neighbor lists\n");
113 /* While we havn't reached the desired insertion point ... */
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
];
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. */
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.
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
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
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
)
161 MINUTIA
*minutia1
, *minutia2
;
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) ... */
187 "ERROR : update_nbr_dists : illegal position for new neighbor\n");
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
))
196 /* Otherwise, neighbor inserted successfully, so return normally. */
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. */
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.
217 max_nbrs - maximum number of closest neighbors to be returned
218 first - index of the primary minutia point
219 minutiae - list of minutiae
221 onbr_list - points to list of detected closest neighbors
222 onnbrs - points to number of neighbors returned
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");
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
){
248 "ERROR : find_neighbors : malloc : nbr_sqr_dists\n");
252 /* Initialize number of stored neighbors to 0. */
254 /* Assign secondary to one passed current primary minutia. */
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
))){
285 /* Otherwise, if the neighbor lists is full AND the x-distance */
286 /* to current secondary is larger than maximum neighbor distance */
289 /* So, stop searching for more neighbors. */
292 /* Bump to next secondary minutia. */
296 /* Deallocate working memory. */
299 /* If no neighbors found ... */
301 /* Deallocate the neighbor list. */
305 /* Otherwise, assign neighbors to output pointer. */
307 *onbr_list
= nbr_list
;
311 /* Return normally. */
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.
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
329 nbr_list - neighboring minutia indices in sorted order
331 Zero - successful completion
332 Negative - system error
333 **************************************************************************/
334 static int sort_neighbors(int *nbr_list
, const int nnbrs
, const int first
,
337 double *join_thetas
, theta
;
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");
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 */
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. */
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. */
371 /* Return normally. */
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).
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
393 iptr - points to location where 2nd pixel in pair is found
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
)
404 /* Set previous index to starting position. */
406 /* Bump previous index by 1 to get next index. */
409 /* While not one point from the end of the trajectory .. */
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. */
421 /* Otherwise, the desired transition was not found in current */
422 /* pixel pair, so bump to the next pair along the trajector. */
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. */
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.
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
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
)
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
,
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
,
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 ... */
494 /* Return error code. */
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. */
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- */
512 ret
= trace_contour(&contour_x
, &contour_y
,
513 &contour_ex
, &contour_ey
, &ncontour
,
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 ... */
520 /* Return error code. */
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. */
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. */
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. */
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.
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
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
;
567 int *xlist
, *ylist
, num
;
568 int ridge_count
, ridge_start
, ridge_end
;
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. */
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
))){
587 /* It there are no points on the line trajectory, then no ridges */
588 /* to count (this should not happen, but just in case) ... */
595 /* Find first pixel opposite type along linear trajectory from */
597 prevpix
= *(bdata
+(ylist
[0]*iw
)+xlist
[0]);
601 curpix
= *(bdata
+(ylist
[i
]*iw
)+xlist
[i
]);
602 if(curpix
!= prevpix
){
609 /* If opposite pixel not found ... then no ridges to count */
616 /* Ready to count ridges, so initialize counter to 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 ... */
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. */
632 /* Return number of ridges counted to this point. */
635 /* Otherwise, we found a new ridge start transition, so store */
636 /* its location (the location of the 1 in 0-to-1 transition). */
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. */
649 /* Return number of ridges counted to this point. */
652 /* Otherwise, we found a new ridge end transition, so store */
653 /* its location (the location of the 0 in 1-to-0 transition). */
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 ... */
673 /* Return the error code. */
677 print2log("; V%d ", ret
);
679 /* If validation result is TRUE ... */
681 /* Then assume we have found a valid ridge crossing and bump */
682 /* the ridge counter. */
686 /* Otherwise, ignore the current ridge start and end transitions */
687 /* and go back and search for new ridge start. */
690 /* Deallocate working memories. */
696 /* Return the number of ridges counted. */
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.
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
713 minutiae - minutia augmented with neighbors and ridge counts
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
,
731 print2log("NBRS FOUND: %d,%d = %d\n", minutiae
->list
[first
]->x
,
732 minutiae
->list
[first
]->y
, nnbrs
);
734 /* If no neighors found ... */
736 /* Then no list returned and no ridges to count. */
740 /* Sort neighbors on delta dirs. */
741 if((ret
= sort_neighbors(nbr_list
, nnbrs
, first
, minutiae
))){
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
){
751 fprintf(stderr
, "ERROR : count_minutia_ridges : malloc : nbr_nridges\n");
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 ... */
761 /* Deallocate working memories. */
764 /* Return error code. */
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. */
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.
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
795 minutiae - list of minutiae augmented with neighbors and ridge counts
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
)
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
))){
814 /* Remove any duplicate minutia points from the list. */
815 if((ret
= rm_dup_minutiae(minutiae
))){
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
))){
829 /* Return normally. */