Line | Branch | Exec | Source |
---|---|---|---|
1 | /******************************************************************************* | ||
2 | |||
3 | License: | ||
4 | This software and/or related materials was developed at the National Institute | ||
5 | of Standards and Technology (NIST) by employees of the Federal Government | ||
6 | in the course of their official duties. Pursuant to title 17 Section 105 | ||
7 | of the United States Code, this software is not subject to copyright | ||
8 | protection and is in the public domain. | ||
9 | |||
10 | This software and/or related materials have been determined to be not subject | ||
11 | to the EAR (see Part 734.3 of the EAR for exact details) because it is | ||
12 | a publicly available technology and software, and is freely distributed | ||
13 | to any interested party with no licensing requirements. Therefore, it is | ||
14 | permissible to distribute this software as a free download from the internet. | ||
15 | |||
16 | Disclaimer: | ||
17 | This software and/or related materials was developed to promote biometric | ||
18 | standards and biometric technology testing for the Federal Government | ||
19 | in accordance with the USA PATRIOT Act and the Enhanced Border Security | ||
20 | and Visa Entry Reform Act. Specific hardware and software products identified | ||
21 | in this software were used in order to perform the software development. | ||
22 | In no case does such identification imply recommendation or endorsement | ||
23 | by the National Institute of Standards and Technology, nor does it imply that | ||
24 | the products and equipment identified are necessarily the best available | ||
25 | for the purpose. | ||
26 | |||
27 | This software and/or related materials are provided "AS-IS" without warranty | ||
28 | of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, | ||
29 | NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY | ||
30 | or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the | ||
31 | licensed product, however used. In no event shall NIST be liable for any | ||
32 | damages and/or costs, including but not limited to incidental or consequential | ||
33 | damages of any kind, including economic damage or injury to property and lost | ||
34 | profits, regardless of whether NIST shall be advised, have reason to know, | ||
35 | or in fact shall know of the possibility. | ||
36 | |||
37 | By using this software, you agree to bear all risk relating to quality, | ||
38 | use and performance of the software and/or related materials. You agree | ||
39 | to hold the Government harmless from any claim arising from your use | ||
40 | of the software. | ||
41 | |||
42 | *******************************************************************************/ | ||
43 | |||
44 | |||
45 | /*********************************************************************** | ||
46 | LIBRARY: LFS - NIST Latent Fingerprint System | ||
47 | |||
48 | FILE: RIDGES.C | ||
49 | AUTHOR: Michael D. Garris | ||
50 | DATE: 08/09/1999 | ||
51 | UPDATED: 03/16/2005 by MDG | ||
52 | |||
53 | Contains routines responsible for locating nearest minutia | ||
54 | neighbors and counting intervening ridges as part of the | ||
55 | NIST Latent Fingerprint System (LFS). | ||
56 | |||
57 | *********************************************************************** | ||
58 | ROUTINES: | ||
59 | count_minutiae_ridges() | ||
60 | count_minutia_ridges() | ||
61 | find_neighbors() | ||
62 | update_nbr_dists() | ||
63 | insert_neighbor() | ||
64 | sort_neighbors() | ||
65 | ridge_count() | ||
66 | find_transition() | ||
67 | validate_ridge_crossing() | ||
68 | ***********************************************************************/ | ||
69 | |||
70 | #include <stdio.h> | ||
71 | #include <lfs.h> | ||
72 | #include <log.h> | ||
73 | |||
74 | /************************************************************************* | ||
75 | ************************************************************************** | ||
76 | #cat: count_minutiae_ridges - Takes a list of minutiae, and for each one, | ||
77 | #cat: determines its closest neighbors and counts the number | ||
78 | #cat: of interveining ridges between the minutia point and | ||
79 | #cat: each of its neighbors. | ||
80 | |||
81 | Input: | ||
82 | minutiae - list of minutiae | ||
83 | bdata - binary image data (0==while & 1==black) | ||
84 | iw - width (in pixels) of image | ||
85 | ih - height (in pixels) of image | ||
86 | lfsparms - parameters and thresholds for controlling LFS | ||
87 | Output: | ||
88 | minutiae - list of minutiae augmented with neighbors and ridge counts | ||
89 | Return Code: | ||
90 | Zero - successful completion | ||
91 | Negative - system error | ||
92 | **************************************************************************/ | ||
93 | 48 | int count_minutiae_ridges(MINUTIAE *minutiae, | |
94 | unsigned char *bdata, const int iw, const int ih, | ||
95 | const LFSPARMS *lfsparms) | ||
96 | { | ||
97 | 48 | int ret; | |
98 | 48 | int i; | |
99 | |||
100 | 48 | print2log("\nFINDING NBRS AND COUNTING RIDGES:\n"); | |
101 | |||
102 | /* Sort minutia points on x then y (column-oriented). */ | ||
103 |
1/2✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
|
48 | if((ret = sort_minutiae_x_y(minutiae, iw, ih))){ |
104 | return(ret); | ||
105 | } | ||
106 | |||
107 | /* Remove any duplicate minutia points from the list. */ | ||
108 |
1/2✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
|
48 | if((ret = rm_dup_minutiae(minutiae))){ |
109 | return(ret); | ||
110 | } | ||
111 | |||
112 | /* Foreach remaining sorted minutia in list ... */ | ||
113 |
2/2✓ Branch 0 taken 3447 times.
✓ Branch 1 taken 48 times.
|
3495 | for(i = 0; i < minutiae->num-1; i++){ |
114 | /* Located neighbors and count number of ridges in between. */ | ||
115 | /* NOTE: neighbor and ridge count results are stored in */ | ||
116 | /* minutiae->list[i]. */ | ||
117 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3447 times.
|
3447 | if((ret = count_minutia_ridges(i, minutiae, bdata, iw, ih, lfsparms))){ |
118 | ✗ | return(ret); | |
119 | } | ||
120 | } | ||
121 | |||
122 | /* Return normally. */ | ||
123 | return(0); | ||
124 | } | ||
125 | |||
126 | /************************************************************************* | ||
127 | ************************************************************************** | ||
128 | #cat: count_minutia_ridges - Takes a minutia, and determines its closest | ||
129 | #cat: neighbors and counts the number of interveining ridges | ||
130 | #cat: between the minutia point and each of its neighbors. | ||
131 | |||
132 | Input: | ||
133 | minutia - input minutia | ||
134 | bdata - binary image data (0==while & 1==black) | ||
135 | iw - width (in pixels) of image | ||
136 | ih - height (in pixels) of image | ||
137 | lfsparms - parameters and thresholds for controlling LFS | ||
138 | Output: | ||
139 | minutiae - minutia augmented with neighbors and ridge counts | ||
140 | Return Code: | ||
141 | Zero - successful completion | ||
142 | Negative - system error | ||
143 | **************************************************************************/ | ||
144 | 3447 | int count_minutia_ridges(const int first, MINUTIAE *minutiae, | |
145 | unsigned char *bdata, const int iw, const int ih, | ||
146 | const LFSPARMS *lfsparms) | ||
147 | { | ||
148 | 3447 | int i, ret, *nbr_list, *nbr_nridges, nnbrs; | |
149 | |||
150 |
1/2✓ Branch 0 taken 3447 times.
✗ Branch 1 not taken.
|
3447 | g_assert (lfsparms->max_nbrs > 0); |
151 | |||
152 | /* Find up to the maximum number of qualifying neighbors. */ | ||
153 | 3447 | nbr_list = NULL; | |
154 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3447 times.
|
3447 | if((ret = find_neighbors(&nbr_list, &nnbrs, lfsparms->max_nbrs, |
155 | first, minutiae))){ | ||
156 | ✗ | if (nbr_list != NULL) | |
157 | ✗ | g_free(nbr_list); | |
158 | ✗ | return(ret); | |
159 | } | ||
160 | |||
161 | 3447 | print2log("NBRS FOUND: %d,%d = %d\n", minutiae->list[first]->x, | |
162 | 3447 | minutiae->list[first]->y, nnbrs); | |
163 | |||
164 | /* If no neighors found ... */ | ||
165 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3447 times.
|
3447 | if(nnbrs == 0){ |
166 | /* Then no list returned and no ridges to count. */ | ||
167 | return(0); | ||
168 | } | ||
169 | |||
170 | /* Sort neighbors on delta dirs. */ | ||
171 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3447 times.
|
3447 | if((ret = sort_neighbors(nbr_list, nnbrs, first, minutiae))){ |
172 | ✗ | g_free(nbr_list); | |
173 | ✗ | return(ret); | |
174 | } | ||
175 | |||
176 | /* Count ridges between first and neighbors. */ | ||
177 | /* List of ridge counts, one for each neighbor stored. */ | ||
178 | 3447 | nbr_nridges = (int *)g_malloc(nnbrs * sizeof(int)); | |
179 | |||
180 | /* Foreach neighbor found and sorted in list ... */ | ||
181 |
2/2✓ Branch 1 taken 16762 times.
✓ Branch 2 taken 3447 times.
|
23656 | for(i = 0; i < nnbrs; i++){ |
182 | /* Count the ridges between the primary minutia and the neighbor. */ | ||
183 | 16762 | ret = ridge_count(first, nbr_list[i], minutiae, bdata, iw, ih, lfsparms); | |
184 | /* If system error ... */ | ||
185 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16762 times.
|
16762 | if(ret < 0){ |
186 | /* Deallocate working memories. */ | ||
187 | ✗ | g_free(nbr_list); | |
188 | ✗ | g_free(nbr_nridges); | |
189 | /* Return error code. */ | ||
190 | ✗ | return(ret); | |
191 | } | ||
192 | |||
193 | /* Otherwise, ridge count successful, so store ridge count to list. */ | ||
194 | 16762 | nbr_nridges[i] = ret; | |
195 | } | ||
196 | |||
197 | /* Assign neighbor indices and ridge counts to primary minutia. */ | ||
198 | 3447 | minutiae->list[first]->nbrs = nbr_list; | |
199 | 3447 | minutiae->list[first]->ridge_counts = nbr_nridges; | |
200 | 3447 | minutiae->list[first]->num_nbrs = nnbrs; | |
201 | |||
202 | /* Return normally. */ | ||
203 | 3447 | return(0); | |
204 | } | ||
205 | |||
206 | /************************************************************************* | ||
207 | ************************************************************************** | ||
208 | #cat: find_neighbors - Takes a primary minutia and a list of all minutiae | ||
209 | #cat: and locates a specified maximum number of closest neighbors | ||
210 | #cat: to the primary point. Neighbors are searched, starting | ||
211 | #cat: in the same pixel column, below, the primary point and then | ||
212 | #cat: along consecutive and complete pixel columns in the image | ||
213 | #cat: to the right of the primary point. | ||
214 | |||
215 | Input: | ||
216 | max_nbrs - maximum number of closest neighbors to be returned | ||
217 | first - index of the primary minutia point | ||
218 | minutiae - list of minutiae | ||
219 | Output: | ||
220 | onbr_list - points to list of detected closest neighbors | ||
221 | onnbrs - points to number of neighbors returned | ||
222 | Return Code: | ||
223 | Zero - successful completion | ||
224 | Negative - system error | ||
225 | **************************************************************************/ | ||
226 | 3447 | int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs, | |
227 | const int first, MINUTIAE *minutiae) | ||
228 | { | ||
229 | 3447 | int ret, second, last_nbr; | |
230 | 3447 | MINUTIA *minutia1, *minutia2; | |
231 | 3447 | int *nbr_list, nnbrs; | |
232 | 3447 | double *nbr_sqr_dists, xdist, xdist2; | |
233 | |||
234 | /* Allocate list of neighbor minutiae indices. */ | ||
235 | 3447 | nbr_list = (int *)g_malloc(max_nbrs * sizeof(int)); | |
236 | |||
237 | /* Allocate list of squared euclidean distances between neighbors */ | ||
238 | /* and current primary minutia point. */ | ||
239 | 3447 | nbr_sqr_dists = (double *)g_malloc(max_nbrs * sizeof(double)); | |
240 | |||
241 | /* Initialize number of stored neighbors to 0. */ | ||
242 | 3447 | nnbrs = 0; | |
243 | /* Assign secondary to one passed current primary minutia. */ | ||
244 | 3447 | second = first + 1; | |
245 | /* Compute location of maximum last stored neighbor. */ | ||
246 | 3447 | last_nbr = max_nbrs - 1; | |
247 | |||
248 | /* While minutia (in sorted order) still remian for processing ... */ | ||
249 | /* NOTE: The minutia in the input list have been sorted on X and */ | ||
250 | /* then on Y. So, the neighbors are selected according to those */ | ||
251 | /* that lie below the primary minutia in the same pixel column and */ | ||
252 | /* then subsequently those that lie in complete pixel columns to */ | ||
253 | /* the right of the primary minutia. */ | ||
254 |
2/2✓ Branch 0 taken 57953 times.
✓ Branch 1 taken 642 times.
|
58595 | while(second < minutiae->num){ |
255 | /* Assign temporary minutia pointers. */ | ||
256 | 57953 | minutia1 = minutiae->list[first]; | |
257 | 57953 | minutia2 = minutiae->list[second]; | |
258 | |||
259 | /* Compute squared distance between minutiae along x-axis. */ | ||
260 | 57953 | xdist = minutia2->x - minutia1->x; | |
261 | 57953 | xdist2 = xdist * xdist; | |
262 | |||
263 | /* If the neighbor lists are not full OR the x-distance to current */ | ||
264 | /* secondary is smaller than maximum neighbor distance stored ... */ | ||
265 |
2/2✓ Branch 0 taken 41191 times.
✓ Branch 1 taken 16762 times.
|
57953 | if((nnbrs < max_nbrs) || |
266 |
2/2✓ Branch 0 taken 38386 times.
✓ Branch 1 taken 2805 times.
|
41191 | (xdist2 < nbr_sqr_dists[last_nbr])){ |
267 | /* Append or insert the new neighbor into the neighbor lists. */ | ||
268 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 55148 times.
|
55148 | if((ret = update_nbr_dists(nbr_list, nbr_sqr_dists, &nnbrs, max_nbrs, |
269 | first, second, minutiae))){ | ||
270 | ✗ | g_free(nbr_sqr_dists); | |
271 | ✗ | g_free(nbr_list); | |
272 | ✗ | return(ret); | |
273 | } | ||
274 | } | ||
275 | /* Otherwise, if the neighbor lists is full AND the x-distance */ | ||
276 | /* to current secondary is larger than maximum neighbor distance */ | ||
277 | /* stored ... */ | ||
278 | else | ||
279 | /* So, stop searching for more neighbors. */ | ||
280 | break; | ||
281 | |||
282 | /* Bump to next secondary minutia. */ | ||
283 | 55148 | second++; | |
284 | } | ||
285 | |||
286 | /* Deallocate working memory. */ | ||
287 | 3447 | g_free(nbr_sqr_dists); | |
288 | |||
289 | /* If no neighbors found ... */ | ||
290 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3447 times.
|
3447 | if(nnbrs == 0){ |
291 | /* Deallocate the neighbor list. */ | ||
292 | ✗ | g_free(nbr_list); | |
293 | ✗ | *onnbrs = 0; | |
294 | } | ||
295 | /* Otherwise, assign neighbors to output pointer. */ | ||
296 | else{ | ||
297 | 3447 | *onbr_list = nbr_list; | |
298 | 3447 | *onnbrs = nnbrs; | |
299 | } | ||
300 | |||
301 | /* Return normally. */ | ||
302 | return(0); | ||
303 | } | ||
304 | |||
305 | /************************************************************************* | ||
306 | ************************************************************************** | ||
307 | #cat: update_nbr_dists - Takes the current list of neighbors along with a | ||
308 | #cat: primary minutia and a potential new neighbor, and | ||
309 | #cat: determines if the new neighbor is sufficiently close | ||
310 | #cat: to be added to the list of nearest neighbors. If added, | ||
311 | #cat: it is placed in the list in its proper order based on | ||
312 | #cat: squared distance to the primary point. | ||
313 | |||
314 | Input: | ||
315 | nbr_list - current list of nearest neighbor minutia indices | ||
316 | nbr_sqr_dists - corresponding squared euclidean distance of each | ||
317 | neighbor to the primary minutia point | ||
318 | nnbrs - number of neighbors currently in the list | ||
319 | max_nbrs - maximum number of closest neighbors to be returned | ||
320 | first - index of the primary minutia point | ||
321 | second - index of the secondary (new neighbor) point | ||
322 | minutiae - list of minutiae | ||
323 | Output: | ||
324 | nbr_list - updated list of nearest neighbor indices | ||
325 | nbr_sqr_dists - updated list of nearest neighbor distances | ||
326 | nnbrs - number of neighbors in the update lists | ||
327 | Return Code: | ||
328 | Zero - successful completion | ||
329 | Negative - system error | ||
330 | **************************************************************************/ | ||
331 | 55148 | int update_nbr_dists(int *nbr_list, double *nbr_sqr_dists, | |
332 | int *nnbrs, const int max_nbrs, | ||
333 | const int first, const int second, MINUTIAE *minutiae) | ||
334 | { | ||
335 | 55148 | double dist2; | |
336 | 55148 | MINUTIA *minutia1, *minutia2; | |
337 | 55148 | int pos, last_nbr; | |
338 | |||
339 | /* Compute position of maximum last neighbor stored. */ | ||
340 | 55148 | last_nbr = max_nbrs - 1; | |
341 | |||
342 | /* Assigne temporary minutia pointers. */ | ||
343 | 55148 | minutia1 = minutiae->list[first]; | |
344 | 55148 | minutia2 = minutiae->list[second]; | |
345 | |||
346 | /* Compute squared euclidean distance between minutia pair. */ | ||
347 | 55148 | dist2 = squared_distance(minutia1->x, minutia1->y, | |
348 | minutia2->x, minutia2->y); | ||
349 | |||
350 | /* If maximum number of neighbors not yet stored in lists OR */ | ||
351 | /* if the squared distance to current secondary is less */ | ||
352 | /* than the largest stored neighbor distance ... */ | ||
353 |
2/2✓ Branch 0 taken 38386 times.
✓ Branch 1 taken 16762 times.
|
55148 | if((*nnbrs < max_nbrs) || |
354 |
2/2✓ Branch 0 taken 16921 times.
✓ Branch 1 taken 21465 times.
|
38386 | (dist2 < nbr_sqr_dists[last_nbr])){ |
355 | |||
356 | /* Find insertion point in neighbor lists. */ | ||
357 | 33683 | pos = find_incr_position_dbl(dist2, nbr_sqr_dists, *nnbrs); | |
358 | /* If the position returned is >= maximum list length (this should */ | ||
359 | /* never happen, but just in case) ... */ | ||
360 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33683 times.
|
33683 | if(pos >= max_nbrs){ |
361 | ✗ | fprintf(stderr, | |
362 | "ERROR : update_nbr_dists : illegal position for new neighbor\n"); | ||
363 | ✗ | return(-470); | |
364 | } | ||
365 | /* Insert the new neighbor into the neighbor lists at the */ | ||
366 | /* specified location. */ | ||
367 |
1/2✓ Branch 1 taken 33683 times.
✗ Branch 2 not taken.
|
33683 | if(insert_neighbor(pos, second, dist2, |
368 | nbr_list, nbr_sqr_dists, nnbrs, max_nbrs)) | ||
369 | return(-471); | ||
370 | |||
371 | /* Otherwise, neighbor inserted successfully, so return normally. */ | ||
372 | return(0); | ||
373 | } | ||
374 | /* Otherwise, the new neighbor is not sufficiently close to be */ | ||
375 | /* added or inserted into the neighbor lists, so ignore the neighbor */ | ||
376 | /* and return normally. */ | ||
377 | else | ||
378 | return(0); | ||
379 | |||
380 | } | ||
381 | |||
382 | /************************************************************************* | ||
383 | ************************************************************************** | ||
384 | #cat: insert_neighbor - Takes a minutia index and its squared distance to a | ||
385 | #cat: primary minutia point, and inserts them in the specified | ||
386 | #cat: position of their respective lists, shifting previously | ||
387 | #cat: stored values down and off the lists as necessary. | ||
388 | |||
389 | Input: | ||
390 | pos - postions where values are to be inserted in lists | ||
391 | nbr_index - index of minutia being inserted | ||
392 | nbr_dist2 - squared distance of minutia to its primary point | ||
393 | nbr_list - current list of nearest neighbor minutia indices | ||
394 | nbr_sqr_dists - corresponding squared euclidean distance of each | ||
395 | neighbor to the primary minutia point | ||
396 | nnbrs - number of neighbors currently in the list | ||
397 | max_nbrs - maximum number of closest neighbors to be returned | ||
398 | Output: | ||
399 | nbr_list - updated list of nearest neighbor indices | ||
400 | nbr_sqr_dists - updated list of nearest neighbor distances | ||
401 | nnbrs - number of neighbors in the update lists | ||
402 | Return Code: | ||
403 | Zero - successful completion | ||
404 | Negative - system error | ||
405 | **************************************************************************/ | ||
406 | 33683 | int insert_neighbor(const int pos, const int nbr_index, const double nbr_dist2, | |
407 | int *nbr_list, double *nbr_sqr_dists, | ||
408 | int *nnbrs, const int max_nbrs) | ||
409 | { | ||
410 | 33683 | int i; | |
411 | |||
412 |
1/2✓ Branch 0 taken 33683 times.
✗ Branch 1 not taken.
|
33683 | g_assert (pos >= 0); |
413 | |||
414 | /* If the desired insertion position is beyond one passed the last */ | ||
415 | /* neighbor in the lists OR greater than equal to the maximum ... */ | ||
416 | /* NOTE: pos is zero-oriented while nnbrs and max_nbrs are 1-oriented. */ | ||
417 |
2/4✓ Branch 0 taken 33683 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 33683 times.
|
33683 | if((pos > *nnbrs) || |
418 | (pos >= max_nbrs)){ | ||
419 | ✗ | fprintf(stderr, | |
420 | "ERROR : insert_neighbor : insertion point exceeds lists\n"); | ||
421 | ✗ | return(-480); | |
422 | } | ||
423 | |||
424 | /* If the neighbor lists are NOT full ... */ | ||
425 |
2/2✓ Branch 0 taken 16762 times.
✓ Branch 1 taken 16921 times.
|
33683 | if(*nnbrs < max_nbrs){ |
426 | /* Then we have room to shift everything down to make room for new */ | ||
427 | /* neighbor and increase the number of neighbors stored by 1. */ | ||
428 | 16762 | i = *nnbrs-1; | |
429 | 16762 | (*nnbrs)++; | |
430 | } | ||
431 | /* Otherwise, the neighbors lists are full ... */ | ||
432 |
1/2✓ Branch 0 taken 16921 times.
✗ Branch 1 not taken.
|
16921 | else if(*nnbrs == max_nbrs) |
433 | /* So, we must bump the last neighbor in the lists off to make */ | ||
434 | /* room for the new neighbor (ignore last neighbor in lists). */ | ||
435 | 16921 | i = *nnbrs-2; | |
436 | /* Otherwise, there is a list overflow error condition */ | ||
437 | /* (shouldn't ever happen, but just in case) ... */ | ||
438 | else{ | ||
439 | ✗ | fprintf(stderr, | |
440 | "ERROR : insert_neighbor : overflow in neighbor lists\n"); | ||
441 | ✗ | return(-481); | |
442 | } | ||
443 | |||
444 | /* While we havn't reached the desired insertion point ... */ | ||
445 |
2/2✓ Branch 0 taken 43276 times.
✓ Branch 1 taken 33683 times.
|
76959 | while(i >= pos){ |
446 | /* Shift the current neighbor down the list 1 positon. */ | ||
447 | 43276 | nbr_list[i+1] = nbr_list[i]; | |
448 | 43276 | nbr_sqr_dists[i+1] = nbr_sqr_dists[i]; | |
449 | 43276 | i--; | |
450 | } | ||
451 | |||
452 | /* We are now ready to put our new neighbor in the position where */ | ||
453 | /* we shifted everything down from to make room. */ | ||
454 | 33683 | nbr_list[pos] = nbr_index; | |
455 | 33683 | nbr_sqr_dists[pos] = nbr_dist2; | |
456 | |||
457 | /* Return normally. */ | ||
458 | 33683 | return(0); | |
459 | } | ||
460 | |||
461 | /************************************************************************* | ||
462 | ************************************************************************** | ||
463 | #cat: sort_neighbors - Takes a list of primary minutia and its neighboring | ||
464 | #cat: minutia indices and sorts the neighbors based on their | ||
465 | #cat: position relative to the primary minutia point. Neighbors | ||
466 | #cat: are sorted starting vertical to the primary point and | ||
467 | #cat: proceeding clockwise. | ||
468 | |||
469 | Input: | ||
470 | nbr_list - list of neighboring minutia indices | ||
471 | nnbrs - number of neighbors in the list | ||
472 | first - the index of the primary minutia point | ||
473 | minutiae - list of minutiae | ||
474 | Output: | ||
475 | nbr_list - neighboring minutia indices in sorted order | ||
476 | Return Code: | ||
477 | Zero - successful completion | ||
478 | Negative - system error | ||
479 | **************************************************************************/ | ||
480 | 3447 | int sort_neighbors(int *nbr_list, const int nnbrs, const int first, | |
481 | MINUTIAE *minutiae) | ||
482 | { | ||
483 | 3447 | double *join_thetas, theta; | |
484 | 3447 | int i; | |
485 | 3447 | static double pi2 = M_PI*2.0; | |
486 | |||
487 | /* List of angles of lines joining the current primary to each */ | ||
488 | /* of the secondary neighbors. */ | ||
489 | 3447 | join_thetas = (double *)g_malloc(nnbrs * sizeof(double)); | |
490 | |||
491 |
2/2✓ Branch 1 taken 16762 times.
✓ Branch 2 taken 3447 times.
|
23656 | for(i = 0; i < nnbrs; i++){ |
492 | /* Compute angle to line connecting the 2 points. */ | ||
493 | /* Coordinates are swapped and order of points reversed to */ | ||
494 | /* account for 0 direction is vertical and positive direction */ | ||
495 | /* is clockwise. */ | ||
496 | 33524 | theta = angle2line(minutiae->list[nbr_list[i]]->y, | |
497 | 16762 | minutiae->list[nbr_list[i]]->x, | |
498 | minutiae->list[first]->y, | ||
499 | 16762 | minutiae->list[first]->x); | |
500 | |||
501 | /* Make sure the angle is positive. */ | ||
502 | 16762 | theta += pi2; | |
503 | 16762 | theta = fmod(theta, pi2); | |
504 | 16762 | join_thetas[i] = theta; | |
505 | } | ||
506 | |||
507 | /* Sort the neighbor indicies into rank order. */ | ||
508 | 3447 | bubble_sort_double_inc_2(join_thetas, nbr_list, nnbrs); | |
509 | |||
510 | /* Deallocate the list of angles. */ | ||
511 | 3447 | g_free(join_thetas); | |
512 | |||
513 | /* Return normally. */ | ||
514 | 3447 | return(0); | |
515 | } | ||
516 | |||
517 | /************************************************************************* | ||
518 | ************************************************************************** | ||
519 | #cat: ridge_count - Takes a pair of minutiae, and counts the number of | ||
520 | #cat: ridges crossed along the linear trajectory connecting | ||
521 | #cat: the 2 points in the image. | ||
522 | |||
523 | Input: | ||
524 | first - index of primary minutia | ||
525 | second - index of secondary (neighbor) minutia | ||
526 | minutiae - list of minutiae | ||
527 | bdata - binary image data (0==while & 1==black) | ||
528 | iw - width (in pixels) of image | ||
529 | ih - height (in pixels) of image | ||
530 | lfsparms - parameters and thresholds for controlling LFS | ||
531 | Return Code: | ||
532 | Zero or Positive - number of ridges counted | ||
533 | Negative - system error | ||
534 | **************************************************************************/ | ||
535 | 16762 | int ridge_count(const int first, const int second, MINUTIAE *minutiae, | |
536 | unsigned char *bdata, const int iw, const int ih, | ||
537 | const LFSPARMS *lfsparms) | ||
538 | { | ||
539 | 16762 | MINUTIA *minutia1, *minutia2; | |
540 | 16762 | int i, ret, found; | |
541 | 16762 | int *xlist, *ylist, num; | |
542 | 16762 | int ridge_count, ridge_start, ridge_end; | |
543 | 16762 | int prevpix, curpix; | |
544 | |||
545 | 16762 | minutia1 = minutiae->list[first]; | |
546 | 16762 | minutia2 = minutiae->list[second]; | |
547 | |||
548 | /* If the 2 mintuia have identical pixel coords ... */ | ||
549 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16762 times.
|
16762 | if((minutia1->x == minutia2->x) && |
550 | (minutia1->y == minutia2->y)) | ||
551 | /* Then zero ridges between points. */ | ||
552 | return(0); | ||
553 | |||
554 | /* Compute linear trajectory of contiguous pixels between first */ | ||
555 | /* and second minutia points. */ | ||
556 |
1/2✓ Branch 1 taken 16762 times.
✗ Branch 2 not taken.
|
16762 | if((ret = line_points(&xlist, &ylist, &num, |
557 | minutia1->x, minutia1->y, minutia2->x, minutia2->y))){ | ||
558 | return(ret); | ||
559 | } | ||
560 | |||
561 | /* It there are no points on the line trajectory, then no ridges */ | ||
562 | /* to count (this should not happen, but just in case) ... */ | ||
563 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16762 times.
|
16762 | if(num == 0){ |
564 | ✗ | g_free(xlist); | |
565 | ✗ | g_free(ylist); | |
566 | ✗ | return(0); | |
567 | } | ||
568 | |||
569 | /* Find first pixel opposite type along linear trajectory from */ | ||
570 | /* first minutia. */ | ||
571 | 16762 | prevpix = *(bdata+(ylist[0]*iw)+xlist[0]); | |
572 | 16762 | i = 1; | |
573 | 16762 | found = FALSE; | |
574 |
2/2✓ Branch 0 taken 40577 times.
✓ Branch 1 taken 12 times.
|
40589 | while(i < num){ |
575 | 40577 | curpix = *(bdata+(ylist[i]*iw)+xlist[i]); | |
576 |
2/2✓ Branch 0 taken 23827 times.
✓ Branch 1 taken 16750 times.
|
40577 | if(curpix != prevpix){ |
577 | found = TRUE; | ||
578 | break; | ||
579 | } | ||
580 | 23827 | i++; | |
581 | } | ||
582 | |||
583 | /* If opposite pixel not found ... then no ridges to count */ | ||
584 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 16750 times.
|
16762 | if(!found){ |
585 | 12 | g_free(xlist); | |
586 | 12 | g_free(ylist); | |
587 | 12 | return(0); | |
588 | } | ||
589 | |||
590 | /* Ready to count ridges, so initialize counter to 0. */ | ||
591 | 16750 | ridge_count = 0; | |
592 | |||
593 | 16750 | print2log("RIDGE COUNT: %d,%d to %d,%d ", minutia1->x, minutia1->y, | |
594 | minutia2->x, minutia2->y); | ||
595 | |||
596 | /* While not at the end of the trajectory ... */ | ||
597 |
1/2✓ Branch 1 taken 71471 times.
✗ Branch 2 not taken.
|
71471 | while(i < num){ |
598 | /* If 0-to-1 transition not found ... */ | ||
599 |
2/2✓ Branch 1 taken 8840 times.
✓ Branch 2 taken 62631 times.
|
71471 | if(!find_transition(&i, 0, 1, xlist, ylist, num, bdata, iw, ih)){ |
600 | /* Then we are done looking for ridges. */ | ||
601 | 8840 | g_free(xlist); | |
602 | 8840 | g_free(ylist); | |
603 | |||
604 | 8840 | print2log("\n"); | |
605 | |||
606 | /* Return number of ridges counted to this point. */ | ||
607 | 8840 | return(ridge_count); | |
608 | } | ||
609 | /* Otherwise, we found a new ridge start transition, so store */ | ||
610 | /* its location (the location of the 1 in 0-to-1 transition). */ | ||
611 | 62631 | ridge_start = i; | |
612 | |||
613 | 62631 | print2log(": RS %d,%d ", xlist[i], ylist[i]); | |
614 | |||
615 | /* If 1-to-0 transition not found ... */ | ||
616 |
2/2✓ Branch 1 taken 7910 times.
✓ Branch 2 taken 54721 times.
|
62631 | if(!find_transition(&i, 1, 0, xlist, ylist, num, bdata, iw, ih)){ |
617 | /* Then we are done looking for ridges. */ | ||
618 | 7910 | g_free(xlist); | |
619 | 7910 | g_free(ylist); | |
620 | |||
621 | 7910 | print2log("\n"); | |
622 | |||
623 | /* Return number of ridges counted to this point. */ | ||
624 | 7910 | return(ridge_count); | |
625 | } | ||
626 | /* Otherwise, we found a new ridge end transition, so store */ | ||
627 | /* its location (the location of the 0 in 1-to-0 transition). */ | ||
628 | 54721 | ridge_end = i; | |
629 | |||
630 | 54721 | print2log("; RE %d,%d ", xlist[i], ylist[i]); | |
631 | |||
632 | /* Conduct the validation, tracing the contour of the ridge */ | ||
633 | /* from the ridge ending point a specified number of steps */ | ||
634 | /* scanning for neighbors clockwise and counter-clockwise. */ | ||
635 | /* If the ridge starting point is encounted during the trace */ | ||
636 | /* then we can assume we do not have a valid ridge crossing */ | ||
637 | /* and instead we are walking on and off the edge of the */ | ||
638 | /* side of a ridge. */ | ||
639 | 109442 | ret = validate_ridge_crossing(ridge_start, ridge_end, | |
640 | xlist, ylist, num, bdata, iw, ih, | ||
641 | 54721 | lfsparms->max_ridge_steps); | |
642 | |||
643 | /* If system error ... */ | ||
644 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 54721 times.
|
54721 | if(ret < 0){ |
645 | ✗ | g_free(xlist); | |
646 | ✗ | g_free(ylist); | |
647 | /* Return the error code. */ | ||
648 | ✗ | return(ret); | |
649 | } | ||
650 | |||
651 | 54721 | print2log("; V%d ", ret); | |
652 | |||
653 | /* If validation result is TRUE ... */ | ||
654 |
2/2✓ Branch 0 taken 47949 times.
✓ Branch 1 taken 6772 times.
|
54721 | if(ret){ |
655 | /* Then assume we have found a valid ridge crossing and bump */ | ||
656 | /* the ridge counter. */ | ||
657 | 47949 | ridge_count++; | |
658 | } | ||
659 | |||
660 | /* Otherwise, ignore the current ridge start and end transitions */ | ||
661 | /* and go back and search for new ridge start. */ | ||
662 | } | ||
663 | |||
664 | /* Deallocate working memories. */ | ||
665 | ✗ | g_free(xlist); | |
666 | ✗ | g_free(ylist); | |
667 | |||
668 | ✗ | print2log("\n"); | |
669 | |||
670 | /* Return the number of ridges counted. */ | ||
671 | ✗ | return(ridge_count); | |
672 | } | ||
673 | |||
674 | /************************************************************************* | ||
675 | ************************************************************************** | ||
676 | #cat: find_transition - Takes a pixel trajectory and a starting index, and | ||
677 | #cat: searches forward along the trajectory until the specified | ||
678 | #cat: adjacent pixel pair is found, returning the index where | ||
679 | #cat: the pair was found (the index of the second pixel). | ||
680 | |||
681 | Input: | ||
682 | iptr - pointer to starting pixel index into trajectory | ||
683 | pix1 - first pixel value in transition pair | ||
684 | pix2 - second pixel value in transition pair | ||
685 | xlist - x-pixel coords of line trajectory | ||
686 | ylist - y-pixel coords of line trajectory | ||
687 | num - number of coords in line trajectory | ||
688 | bdata - binary image data (0==while & 1==black) | ||
689 | iw - width (in pixels) of image | ||
690 | ih - height (in pixels) of image | ||
691 | Output: | ||
692 | iptr - points to location where 2nd pixel in pair is found | ||
693 | Return Code: | ||
694 | TRUE - pixel pair transition found | ||
695 | FALSE - pixel pair transition not found | ||
696 | **************************************************************************/ | ||
697 | 134102 | int find_transition(int *iptr, const int pix1, const int pix2, | |
698 | const int *xlist, const int *ylist, const int num, | ||
699 | unsigned char *bdata, const int iw, const int ih) | ||
700 | { | ||
701 | 134102 | int i, j; | |
702 | |||
703 | /* Set previous index to starting position. */ | ||
704 | 134102 | i = *iptr; | |
705 | /* Bump previous index by 1 to get next index. */ | ||
706 | 134102 | j = i+1; | |
707 | |||
708 | /* While not one point from the end of the trajectory .. */ | ||
709 |
2/2✓ Branch 0 taken 536514 times.
✓ Branch 1 taken 16750 times.
|
553264 | while(i < num-1){ |
710 | /* If we have found the desired transition ... */ | ||
711 |
2/2✓ Branch 0 taken 489415 times.
✓ Branch 1 taken 47099 times.
|
536514 | if((*(bdata+(ylist[i]*iw)+xlist[i]) == pix1) && |
712 |
2/2✓ Branch 0 taken 117352 times.
✓ Branch 1 taken 372063 times.
|
489415 | (*(bdata+(ylist[j]*iw)+xlist[j]) == pix2)){ |
713 | /* Adjust the position pointer to the location of the */ | ||
714 | /* second pixel in the transition. */ | ||
715 | 117352 | *iptr = j; | |
716 | |||
717 | /* Return TRUE. */ | ||
718 | 117352 | return(TRUE); | |
719 | } | ||
720 | /* Otherwise, the desired transition was not found in current */ | ||
721 | /* pixel pair, so bump to the next pair along the trajector. */ | ||
722 | 419162 | i++; | |
723 | 419162 | j++; | |
724 | } | ||
725 | |||
726 | /* If we get here, then we exhausted the trajector without finding */ | ||
727 | /* the desired transition, so set the position pointer to the end */ | ||
728 | /* of the trajector, and return FALSE. */ | ||
729 | 16750 | *iptr = num; | |
730 | 16750 | return(FALSE); | |
731 | } | ||
732 | |||
733 | /************************************************************************* | ||
734 | ************************************************************************** | ||
735 | #cat: validate_ridge_crossing - Takes a pair of points, a ridge start | ||
736 | #cat: transition and a ridge end transition, and walks the | ||
737 | #cat: ridge contour from thre ridge end points a specified | ||
738 | #cat: number of steps, looking for the ridge start point. | ||
739 | #cat: If found, then transitions determined not to be a valid | ||
740 | #cat: ridge crossing. | ||
741 | |||
742 | Input: | ||
743 | ridge_start - index into line trajectory of ridge start transition | ||
744 | ridge_end - index into line trajectory of ridge end transition | ||
745 | xlist - x-pixel coords of line trajectory | ||
746 | ylist - y-pixel coords of line trajectory | ||
747 | num - number of coords in line trajectory | ||
748 | bdata - binary image data (0==while & 1==black) | ||
749 | iw - width (in pixels) of image | ||
750 | ih - height (in pixels) of image | ||
751 | max_ridge_steps - number of steps taken in search in both | ||
752 | scan directions | ||
753 | Return Code: | ||
754 | TRUE - ridge crossing VALID | ||
755 | FALSE - ridge corssing INVALID | ||
756 | Negative - system error | ||
757 | **************************************************************************/ | ||
758 | 54721 | int validate_ridge_crossing(const int ridge_start, const int ridge_end, | |
759 | const int *xlist, const int *ylist, const int num, | ||
760 | unsigned char *bdata, const int iw, const int ih, | ||
761 | const int max_ridge_steps) | ||
762 | { | ||
763 | 54721 | int ret; | |
764 | 54721 | int feat_x, feat_y, edge_x, edge_y; | |
765 | 54721 | int *contour_x, *contour_y, *contour_ex, *contour_ey, ncontour; | |
766 | |||
767 | /* Assign edge pixel pair for contour trace. */ | ||
768 | 54721 | feat_x = xlist[ridge_end]; | |
769 | 54721 | feat_y = ylist[ridge_end]; | |
770 | 54721 | edge_x = xlist[ridge_end-1]; | |
771 | 54721 | edge_y = ylist[ridge_end-1]; | |
772 | |||
773 | /* Adjust pixel pair if they neighbor each other diagonally. */ | ||
774 | 54721 | fix_edge_pixel_pair(&feat_x, &feat_y, &edge_x, &edge_y, | |
775 | bdata, iw, ih); | ||
776 | |||
777 | /* Trace ridge contour, starting at the ridge end transition, and */ | ||
778 | /* taking a specified number of step scanning for edge neighbors */ | ||
779 | /* clockwise. As we trace the ridge, we want to detect if we */ | ||
780 | /* encounter the ridge start transition. NOTE: The ridge end */ | ||
781 | /* position is on the white (of a black to white transition) and */ | ||
782 | /* the ridge start is on the black (of a black to white trans), */ | ||
783 | /* so the edge trace needs to look for the what pixel (not the */ | ||
784 | /* black one) of the ridge start transition. */ | ||
785 | 109442 | ret = trace_contour(&contour_x, &contour_y, | |
786 | &contour_ex, &contour_ey, &ncontour, | ||
787 | max_ridge_steps, | ||
788 | 54721 | xlist[ridge_start-1], ylist[ridge_start-1], | |
789 | feat_x, feat_y, edge_x, edge_y, | ||
790 | SCAN_CLOCKWISE, bdata, iw, ih); | ||
791 | /* If a system error occurred ... */ | ||
792 |
1/2✓ Branch 0 taken 54721 times.
✗ Branch 1 not taken.
|
54721 | if(ret < 0) |
793 | /* Return error code. */ | ||
794 | return(ret); | ||
795 | |||
796 | /* Otherwise, if the trace was not IGNORED, then a contour was */ | ||
797 | /* was generated and returned. We aren't interested in the */ | ||
798 | /* actual contour, so deallocate it. */ | ||
799 |
1/2✓ Branch 0 taken 54721 times.
✗ Branch 1 not taken.
|
54721 | if(ret != IGNORE) |
800 | 54721 | free_contour(contour_x, contour_y, contour_ex, contour_ey); | |
801 | |||
802 | /* If the trace was IGNORED, then we had some sort of initialization */ | ||
803 | /* problem, so treat this the same as if was actually located the */ | ||
804 | /* ridge start point (in which case LOOP_FOUND is returned). */ | ||
805 | /* So, If not IGNORED and ridge start not encounted in trace ... */ | ||
806 |
2/2✓ Branch 0 taken 51312 times.
✓ Branch 1 taken 3409 times.
|
54721 | if((ret != IGNORE) && |
807 | (ret != LOOP_FOUND)){ | ||
808 | |||
809 | /* Now conduct contour trace scanning for edge neighbors counter- */ | ||
810 | /* clockwise. */ | ||
811 | 51312 | ret = trace_contour(&contour_x, &contour_y, | |
812 | &contour_ex, &contour_ey, &ncontour, | ||
813 | max_ridge_steps, | ||
814 | xlist[ridge_start-1], ylist[ridge_start-1], | ||
815 | feat_x, feat_y, edge_x, edge_y, | ||
816 | SCAN_COUNTER_CLOCKWISE, bdata, iw, ih); | ||
817 | /* If a system error occurred ... */ | ||
818 |
1/2✓ Branch 0 taken 51312 times.
✗ Branch 1 not taken.
|
51312 | if(ret < 0) |
819 | /* Return error code. */ | ||
820 | return(ret); | ||
821 | |||
822 | /* Otherwise, if the trace was not IGNORED, then a contour was */ | ||
823 | /* was generated and returned. We aren't interested in the */ | ||
824 | /* actual contour, so deallocate it. */ | ||
825 |
1/2✓ Branch 0 taken 51312 times.
✗ Branch 1 not taken.
|
51312 | if(ret != IGNORE) |
826 | 51312 | free_contour(contour_x, contour_y, contour_ex, contour_ey); | |
827 | |||
828 | /* If trace not IGNORED and ridge start not encounted in 2nd trace ... */ | ||
829 |
2/2✓ Branch 0 taken 3363 times.
✓ Branch 1 taken 47949 times.
|
51312 | if((ret != IGNORE) && |
830 | (ret != LOOP_FOUND)){ | ||
831 | /* If we get here, assume we have a ridge crossing. */ | ||
832 | return(TRUE); | ||
833 | } | ||
834 | /* Otherwise, second trace returned IGNORE or ridge start found. */ | ||
835 | } | ||
836 | /* Otherwise, first trace returned IGNORE or ridge start found. */ | ||
837 | |||
838 | /* If we get here, then we failed to validate a ridge crossing. */ | ||
839 | return(FALSE); | ||
840 | } | ||
841 |