GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 87.6% 92 / 0 / 105
Functions: 100.0% 4 / 0 / 4
Branches: 83.3% 60 / 0 / 72

libfprint/nbis/mindtct/quality.c
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: QUALITY.C
49 AUTHOR: Michael D. Garris
50 DATE: 09/25/2000
51 UPDATED: 03/16/2005 by MDG
52
53 Contains routines responsible for assessing minutia quality
54 and assigning different reliability measures. These routines
55 are primarily to support the rejection of bad minutiae.
56
57 ***********************************************************************
58 ROUTINES:
59 gen_quality_map()
60 combined_minutia_quality()
61 grayscale_reliability()
62 get_neighborhood_stats()
63 reliability_fr_quality_map()
64
65 ***********************************************************************/
66
67 #include <stdio.h>
68 #include <math.h>
69 #include <lfs.h>
70
71 /***********************************************************************
72 ************************************************************************
73 #cat: gen_quality_map - Takes a direction map, low contrast map, low ridge
74 #cat: flow map, and high curvature map, and combines them
75 #cat: into a single map containing 5 levels of decreasing
76 #cat: quality. This is done through a set of heuristics.
77
78 Code originally written by Austin Hicklin for FBI ATU
79 Modified by Michael D. Garris (NIST) Sept. 1, 2000
80
81 Set quality of 0(unusable)..4(good) (I call these grades A..F)
82 0/F: low contrast OR no direction
83 1/D: low flow OR high curve
84 (with low contrast OR no direction neighbor)
85 (or within NEIGHBOR_DELTA of edge)
86 2/C: low flow OR high curve
87 (or good quality with low contrast/no direction neighbor)
88 3/B: good quality with low flow / high curve neighbor
89 4/A: good quality (none of the above)
90
91 Generally, the features in A/B quality are useful, the C/D quality
92 ones are not.
93
94 Input:
95 direction_map - map with blocks assigned dominant ridge flow direction
96 low_contrast_map - map with blocks flagged as low contrast
97 low_flow_map - map with blocks flagged as low ridge flow
98 high_curve_map - map with blocks flagged as high curvature
99 map_w - width (in blocks) of the maps
100 map_h - height (in blocks) of the maps
101 Output:
102 oqmap - points to new quality map
103 Return Code:
104 Zero - successful completion
105 Negative - system error
106 ************************************************************************/
107 49 int gen_quality_map(int **oqmap, int *direction_map, int *low_contrast_map,
108 int *low_flow_map, int *high_curve_map,
109 const int map_w, const int map_h)
110 {
111
112 49 int *QualMap;
113 49 int thisX, thisY;
114 49 int compX, compY;
115 49 int arrayPos, arrayPos2;
116 49 int QualOffset;
117
118
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 49 times.
49 ASSERT_SIZE_MUL(map_w, map_h);
119
1/2
✓ Branch 4 → 5 taken 49 times.
✗ Branch 4 → 7 not taken.
49 ASSERT_SIZE_MUL(map_w * map_h, sizeof(int));
120
121 49 QualMap = (int *)g_malloc(map_w * map_h * sizeof(int));
122
123 /* Foreach row of blocks in maps ... */
124
2/2
✓ Branch 35 → 36 taken 1723 times.
✓ Branch 35 → 37 taken 49 times.
1821 for(thisY=0; thisY<map_h; thisY++){
125 /* Foreach block in current row ... */
126
2/2
✓ Branch 33 → 8 taken 52630 times.
✓ Branch 33 → 34 taken 1723 times.
54353 for(thisX=0; thisX<map_w; thisX++) {
127 /* Compute block index. */
128 52630 arrayPos=(thisY*map_w)+thisX;
129 /* If current block has low contrast or INVALID direction ... */
130
4/4
✓ Branch 8 → 9 taken 46761 times.
✓ Branch 8 → 10 taken 5869 times.
✓ Branch 9 → 10 taken 7152 times.
✓ Branch 9 → 11 taken 39609 times.
52630 if(low_contrast_map[arrayPos] || direction_map[arrayPos]<0)
131 /* Set block's quality to 0/F. */
132 13021 QualMap[arrayPos]=0;
133 else{
134 /* Set baseline quality before looking at neighbors */
135 /* (will subtract QualOffset below) */
136 /* If current block has low flow or high curvature ... */
137
4/4
✓ Branch 11 → 12 taken 23858 times.
✓ Branch 11 → 13 taken 15751 times.
✓ Branch 12 → 13 taken 854 times.
✓ Branch 12 → 14 taken 23004 times.
39609 if(low_flow_map[arrayPos] || high_curve_map[arrayPos])
138 /* Set block's quality initially to 3/B. */
139 16605 QualMap[arrayPos] = 3; /* offset will be -1..-2 */
140 /* Otherwise, block is NOT low flow AND NOT high curvature... */
141 else
142 /* Set block's quality to 4/A. */
143 23004 QualMap[arrayPos]=4; /* offset will be 0..-2 */
144
145 /* If block within NEIGHBOR_DELTA of edge ... */
146
6/6
✓ Branch 15 → 16 taken 38413 times.
✓ Branch 15 → 19 taken 1196 times.
✓ Branch 16 → 17 taken 37222 times.
✓ Branch 16 → 19 taken 1191 times.
✓ Branch 17 → 18 taken 35982 times.
✓ Branch 17 → 19 taken 1240 times.
39609 if(thisY < NEIGHBOR_DELTA || thisY > map_h - 1 - NEIGHBOR_DELTA ||
147
2/2
✓ Branch 18 → 19 taken 1108 times.
✓ Branch 18 → 20 taken 34874 times.
35982 thisX < NEIGHBOR_DELTA || thisX > map_w - 1 - NEIGHBOR_DELTA)
148 /* Set block's quality to 1/E. */
149 4735 QualMap[arrayPos]=1;
150 /* Otherwise, test neighboring blocks ... */
151 else{
152 /* Initialize quality adjustment to 0. */
153 34874 QualOffset=0;
154 /* Foreach row in neighborhood ... */
155 34874 for(compY=thisY-NEIGHBOR_DELTA;
156
2/2
✓ Branch 30 → 21 taken 174370 times.
✓ Branch 30 → 31 taken 34874 times.
209244 compY<=thisY+NEIGHBOR_DELTA;compY++){
157 /* Foreach block in neighborhood */
158 /* (including current block)... */
159 174370 for(compX=thisX-NEIGHBOR_DELTA;
160
2/2
✓ Branch 28 → 22 taken 816588 times.
✓ Branch 28 → 29 taken 150988 times.
967576 compX<=thisX+NEIGHBOR_DELTA;compX++) {
161 /* Compute neighboring block's index. */
162 816588 arrayPos2 = (compY*map_w)+compX;
163 /* If neighbor block (which might be itself) has */
164 /* low contrast or INVALID direction .. */
165
2/2
✓ Branch 22 → 23 taken 813193 times.
✓ Branch 22 → 29 taken 3395 times.
816588 if(low_contrast_map[arrayPos2] ||
166
2/2
✓ Branch 23 → 24 taken 793206 times.
✓ Branch 23 → 29 taken 19987 times.
813193 direction_map[arrayPos2]<0) {
167 /* Set quality adjustment to -2. */
168 QualOffset=-2;
169 /* Done with neighborhood row. */
170 break;
171 }
172 /* Otherwise, if neighbor block (which might be */
173 /* itself) has low flow or high curvature ... */
174
2/2
✓ Branch 24 → 25 taken 471163 times.
✓ Branch 24 → 26 taken 322043 times.
793206 else if(low_flow_map[arrayPos2] ||
175
2/2
✓ Branch 25 → 26 taken 16418 times.
✓ Branch 25 → 27 taken 454745 times.
471163 high_curve_map[arrayPos2]) {
176 /* Set quality to -1 if not already -2. */
177 338461 QualOffset=min(QualOffset,-1);
178 }
179 }
180 }
181 /* Decrement minutia quality by neighborhood adjustment. */
182 34874 QualMap[arrayPos]+=QualOffset;
183 }
184 }
185 }
186 }
187
188 /* Set output pointer. */
189 49 *oqmap = QualMap;
190 /* Return normally. */
191 49 return(0);
192 }
193
194 /***********************************************************************
195 ************************************************************************
196 #cat: combined_minutia_quality - Combines quality measures derived from
197 #cat: the quality map and neighboring pixel statistics to
198 #cat: infer a reliability measure on the scale [0...1].
199
200 Input:
201 minutiae - structure contining the detected minutia
202 quality_map - map with blocks assigned 1 of 5 quality levels
203 map_w - width (in blocks) of the map
204 map_h - height (in blocks) of the map
205 blocksize - size (in pixels) of each block in the map
206 idata - 8-bit grayscale fingerprint image
207 iw - width (in pixels) of the image
208 ih - height (in pixels) of the image
209 id - depth (in pixels) of the image
210 ppmm - scan resolution of the image in pixels/mm
211 Output:
212 minutiae - updated reliability members
213 Return Code:
214 Zero - successful completion
215 Negative - system error
216 ************************************************************************/
217 49 int combined_minutia_quality(MINUTIAE *minutiae,
218 int *quality_map, const int mw, const int mh, const int blocksize,
219 unsigned char *idata, const int iw, const int ih, const int id,
220 const double ppmm)
221 {
222 49 int ret, i, index, radius_pix;
223 49 int *pquality_map, qmap_value;
224 49 MINUTIA *minutia;
225 49 double gs_reliability, reliability;
226
227 /* If image is not 8-bit grayscale ... */
228
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 7 taken 49 times.
49 if(id != 8){
229 fprintf(stderr, "ERROR : combined_miutia_quality : ");
230 fprintf(stderr, "image must pixel depth = %d must be 8 ", id);
231 fprintf(stderr, "to compute reliability\n");
232 return(-2);
233 }
234
235 /* Compute pixel radius of neighborhood based on image's scan resolution. */
236
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 49 times.
49 radius_pix = sround(RADIUS_MM * ppmm);
237
238 /* Expand block map values to pixel map. */
239
1/2
✓ Branch 11 → 24 taken 49 times.
✗ Branch 11 → 27 not taken.
49 if((ret = pixelize_map(&pquality_map, iw, ih,
240 quality_map, mw, mh, blocksize))){
241 return(ret);
242 }
243
244 /* Foreach minutiae detected ... */
245
2/2
✓ Branch 24 → 12 taken 3590 times.
✓ Branch 24 → 25 taken 49 times.
3639 for(i = 0; i < minutiae->num; i++){
246 /* Assign minutia pointer. */
247 3590 minutia = minutiae->list[i];
248
249 /* Compute reliability from stdev and mean of pixel neighborhood. */
250 3590 gs_reliability = grayscale_reliability(minutia,
251 idata, iw, ih, radius_pix);
252
253 /* Lookup quality map value. */
254 /* Compute minutia pixel index. */
255 3590 index = (minutia->y * iw) + minutia->x;
256 /* Switch on pixel's quality value ... */
257 3590 qmap_value = pquality_map[index];
258
259 /* Combine grayscale reliability and quality map value. */
260
5/6
✓ Branch 13 → 14 taken 364 times.
✓ Branch 13 → 15 taken 1128 times.
✓ Branch 13 → 16 taken 1508 times.
✓ Branch 13 → 17 taken 557 times.
✗ Branch 13 → 18 not taken.
✓ Branch 13 → 23 taken 33 times.
3590 switch(qmap_value){
261 /* Quality A : [50..99]% */
262 364 case 4 :
263 364 reliability = 0.50 + (0.49 * gs_reliability);
264 364 break;
265 /* Quality B : [25..49]% */
266 1128 case 3 :
267 1128 reliability = 0.25 + (0.24 * gs_reliability);
268 1128 break;
269 /* Quality C : [10..24]% */
270 1508 case 2 :
271 1508 reliability = 0.10 + (0.14 * gs_reliability);
272 1508 break;
273 /* Quality D : [5..9]% */
274 557 case 1 :
275 557 reliability = 0.05 + (0.04 * gs_reliability);
276 557 break;
277 /* Quality E : 1% */
278 case 0 :
279 reliability = 0.01;
280 break;
281 /* Error if quality value not in range [0..4]. */
282 default:
283 fprintf(stderr, "ERROR : combined_miutia_quality : ");
284 fprintf(stderr, "unexpected quality map value %d ", qmap_value);
285 fprintf(stderr, "not in range [0..4]\n");
286 g_free(pquality_map);
287 return(-3);
288 }
289 3590 minutia->reliability = reliability;
290 }
291
292 /* NEW 05-08-2002 */
293 49 g_free(pquality_map);
294
295 /* Return normally. */
296 49 return(0);
297 }
298
299
300 /***********************************************************************
301 ************************************************************************
302 #cat: grayscale_reliability - Given a minutia point, computes a reliability
303 #cat: measure from the stdev and mean of its pixel neighborhood.
304
305 Code originally written by Austin Hicklin for FBI ATU
306 Modified by Michael D. Garris (NIST) Sept. 25, 2000
307
308 GrayScaleReliability - reasonable reliability heuristic, returns
309 0.0 .. 1.0 based on stdev and Mean of a localized histogram where
310 "ideal" stdev is >=64; "ideal" Mean is 127. In a 1 ridge radius
311 (11 pixels), if the bytevalue (shade of gray) in the image has a
312 stdev of >= 64 & a mean of 127, returns 1.0 (well defined
313 light & dark areas in equal proportions).
314
315 Input:
316 minutia - structure containing detected minutia
317 idata - 8-bit grayscale fingerprint image
318 iw - width (in pixels) of the image
319 ih - height (in pixels) of the image
320 radius_pix - pixel radius of surrounding neighborhood
321 Return Value:
322 reliability - computed reliability measure
323 ************************************************************************/
324 3590 double grayscale_reliability(MINUTIA *minutia, unsigned char *idata,
325 const int iw, const int ih, const int radius_pix)
326 {
327 3590 double mean, stdev;
328 3590 double reliability;
329
330 3590 get_neighborhood_stats(&mean, &stdev, minutia, idata, iw, ih, radius_pix);
331
332
4/6
✓ Branch 3 → 4 taken 3590 times.
✗ Branch 3 → 5 not taken.
✓ Branch 5 → 6 taken 3546 times.
✓ Branch 5 → 8 taken 44 times.
✓ Branch 6 → 7 taken 3546 times.
✗ Branch 6 → 8 not taken.
3590 reliability = min((stdev>IDEALSTDEV ? 1.0 : stdev/(double)IDEALSTDEV),
333 (1.0-(fabs(mean-IDEALMEAN)/(double)IDEALMEAN)));
334
335 3590 return(reliability);
336 }
337
338
339 /***********************************************************************
340 ************************************************************************
341 #cat: get_neighborhood_stats - Given a minutia point, computes the mean
342 #cat: and stdev of the 8-bit grayscale pixels values in a
343 #cat: surrounding neighborhood with specified radius.
344
345 Code originally written by Austin Hicklin for FBI ATU
346 Modified by Michael D. Garris (NIST) Sept. 25, 2000
347
348 Input:
349 minutia - structure containing detected minutia
350 idata - 8-bit grayscale fingerprint image
351 iw - width (in pixels) of the image
352 ih - height (in pixels) of the image
353 radius_pix - pixel radius of surrounding neighborhood
354 Output:
355 mean - mean of neighboring pixels
356 stdev - standard deviation of neighboring pixels
357 ************************************************************************/
358 3590 void get_neighborhood_stats(double *mean, double *stdev, MINUTIA *minutia,
359 unsigned char *idata, const int iw, const int ih,
360 const int radius_pix)
361 {
362 3590 int i, x, y, rows, cols;
363 3590 int n = 0, sumX = 0, sumXX = 0;
364 3590 int histogram[256];
365
366 /* Zero out histogram. */
367 3590 memset(histogram, 0, 256 * sizeof(int));
368
369 /* Set minutia's coordinate variables. */
370 3590 x = minutia->x;
371 3590 y = minutia->y;
372
373
374 /* If minutiae point is within sampleboxsize distance of image border, */
375 /* a value of 0 reliability is returned. */
376
3/6
✓ Branch 2 → 3 taken 3590 times.
✗ Branch 2 → 6 not taken.
✓ Branch 3 → 4 taken 3590 times.
✗ Branch 3 → 6 not taken.
✓ Branch 4 → 5 taken 3590 times.
✗ Branch 4 → 6 not taken.
3590 if ((x < radius_pix) || (x > iw-radius_pix-1) ||
377
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 3590 times.
3590 (y < radius_pix) || (y > ih-radius_pix-1)) {
378 *mean = 0.0;
379 *stdev = 0.0;
380 return;
381
382 }
383
384 /* Foreach row in neighborhood ... */
385 3590 for(rows = y - radius_pix;
386
2/2
✓ Branch 12 → 8 taken 4382 times.
✓ Branch 12 → 16 taken 3590 times.
7972 rows <= y + radius_pix;
387 4382 rows++){
388 /* Foreach column in neighborhood ... */
389 4382 for(cols = x - radius_pix;
390
2/2
✓ Branch 10 → 9 taken 22598 times.
✓ Branch 10 → 11 taken 4382 times.
26980 cols <= x + radius_pix;
391 22598 cols++){
392 /* Bump neighbor's pixel value bin in histogram. */
393 22598 histogram[*(idata+(rows * iw)+cols)]++;
394 }
395 }
396
397 /* Foreach grayscale pixel bin ... */
398
2/2
✓ Branch 16 → 13 taken 919040 times.
✓ Branch 16 → 17 taken 3590 times.
922630 for(i = 0; i < 256; i++){
399
2/2
✓ Branch 13 → 14 taken 8811 times.
✓ Branch 13 → 15 taken 910229 times.
919040 if(histogram[i]){
400 /* Accumulate Sum(X[i]) */
401 8811 sumX += (i * histogram[i]);
402 /* Accumulate Sum(X[i]^2) */
403 8811 sumXX += (i * i * histogram[i]);
404 /* Accumulate N samples */
405 8811 n += histogram[i];
406 }
407 }
408
409 /* Mean = Sum(X[i])/N */
410 3590 *mean = sumX/(double)n;
411 /* Stdev = sqrt((Sum(X[i]^2)/N) - Mean^2) */
412 3590 *stdev = sqrt((sumXX/(double)n) - ((*mean)*(*mean)));
413 }
414
415 /***********************************************************************
416 ************************************************************************
417 #cat: reliability_fr_quality_map - Takes a set of minutiae and assigns
418 #cat: each one a reliability measure based on 1 of 5 possible
419 #cat: quality levels from its location in a quality map.
420
421 Input:
422 minutiae - structure contining the detected minutia
423 quality_map - map with blocks assigned 1 of 5 quality levels
424 map_w - width (in blocks) of the map
425 map_h - height (in blocks) of the map
426 blocksize - size (in pixels) of each block in the map
427 Output:
428 minutiae - updated reliability members
429 Return Code:
430 Zero - successful completion
431 Negative - system error
432 ************************************************************************/
433