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 50 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 50 int *QualMap;
113 50 int thisX, thisY;
114 50 int compX, compY;
115 50 int arrayPos, arrayPos2;
116 50 int QualOffset;
117
118
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 50 times.
50 ASSERT_SIZE_MUL(map_w, map_h);
119
1/2
✓ Branch 4 → 5 taken 50 times.
✗ Branch 4 → 7 not taken.
50 ASSERT_SIZE_MUL(map_w * map_h, sizeof(int));
120
121 50 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 1812 times.
✓ Branch 35 → 37 taken 50 times.
1912 for(thisY=0; thisY<map_h; thisY++){
125 /* Foreach block in current row ... */
126
2/2
✓ Branch 33 → 8 taken 55834 times.
✓ Branch 33 → 34 taken 1812 times.
57646 for(thisX=0; thisX<map_w; thisX++) {
127 /* Compute block index. */
128 55834 arrayPos=(thisY*map_w)+thisX;
129 /* If current block has low contrast or INVALID direction ... */
130
4/4
✓ Branch 8 → 9 taken 48548 times.
✓ Branch 8 → 10 taken 7286 times.
✓ Branch 9 → 10 taken 7326 times.
✓ Branch 9 → 11 taken 41222 times.
55834 if(low_contrast_map[arrayPos] || direction_map[arrayPos]<0)
131 /* Set block's quality to 0/F. */
132 14612 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 24202 times.
✓ Branch 11 → 13 taken 17020 times.
✓ Branch 12 → 13 taken 856 times.
✓ Branch 12 → 14 taken 23346 times.
41222 if(low_flow_map[arrayPos] || high_curve_map[arrayPos])
138 /* Set block's quality initially to 3/B. */
139 17876 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 23346 QualMap[arrayPos]=4; /* offset will be 0..-2 */
144
145 /* If block within NEIGHBOR_DELTA of edge ... */
146
6/6
✓ Branch 15 → 16 taken 40016 times.
✓ Branch 15 → 19 taken 1206 times.
✓ Branch 16 → 17 taken 38802 times.
✓ Branch 16 → 19 taken 1214 times.
✓ Branch 17 → 18 taken 37562 times.
✓ Branch 17 → 19 taken 1240 times.
41222 if(thisY < NEIGHBOR_DELTA || thisY > map_h - 1 - NEIGHBOR_DELTA ||
147
2/2
✓ Branch 18 → 19 taken 1179 times.
✓ Branch 18 → 20 taken 36383 times.
37562 thisX < NEIGHBOR_DELTA || thisX > map_w - 1 - NEIGHBOR_DELTA)
148 /* Set block's quality to 1/E. */
149 4839 QualMap[arrayPos]=1;
150 /* Otherwise, test neighboring blocks ... */
151 else{
152 /* Initialize quality adjustment to 0. */
153 36383 QualOffset=0;
154 /* Foreach row in neighborhood ... */
155 36383 for(compY=thisY-NEIGHBOR_DELTA;
156
2/2
✓ Branch 30 → 21 taken 181915 times.
✓ Branch 30 → 31 taken 36383 times.
218298 compY<=thisY+NEIGHBOR_DELTA;compY++){
157 /* Foreach block in neighborhood */
158 /* (including current block)... */
159 181915 for(compX=thisX-NEIGHBOR_DELTA;
160
2/2
✓ Branch 28 → 22 taken 850694 times.
✓ Branch 28 → 29 taken 157155 times.
1007849 compX<=thisX+NEIGHBOR_DELTA;compX++) {
161 /* Compute neighboring block's index. */
162 850694 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 846576 times.
✓ Branch 22 → 29 taken 4118 times.
850694 if(low_contrast_map[arrayPos2] ||
166
2/2
✓ Branch 23 → 24 taken 825934 times.
✓ Branch 23 → 29 taken 20642 times.
846576 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 478844 times.
✓ Branch 24 → 26 taken 347090 times.
825934 else if(low_flow_map[arrayPos2] ||
175
2/2
✓ Branch 25 → 26 taken 16443 times.
✓ Branch 25 → 27 taken 462401 times.
478844 high_curve_map[arrayPos2]) {
176 /* Set quality to -1 if not already -2. */
177 363533 QualOffset=min(QualOffset,-1);
178 }
179 }
180 }
181 /* Decrement minutia quality by neighborhood adjustment. */
182 36383 QualMap[arrayPos]+=QualOffset;
183 }
184 }
185 }
186 }
187
188 /* Set output pointer. */
189 50 *oqmap = QualMap;
190 /* Return normally. */
191 50 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 50 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 50 int ret, i, index, radius_pix;
223 50 int *pquality_map, qmap_value;
224 50 MINUTIA *minutia;
225 50 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 50 times.
50 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 50 times.
50 radius_pix = sround(RADIUS_MM * ppmm);
237
238 /* Expand block map values to pixel map. */
239
1/2
✓ Branch 11 → 24 taken 50 times.
✗ Branch 11 → 27 not taken.
50 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 3709 times.
✓ Branch 24 → 25 taken 50 times.
3759 for(i = 0; i < minutiae->num; i++){
246 /* Assign minutia pointer. */
247 3709 minutia = minutiae->list[i];
248
249 /* Compute reliability from stdev and mean of pixel neighborhood. */
250 3709 gs_reliability = grayscale_reliability(minutia,
251 idata, iw, ih, radius_pix);
252
253 /* Lookup quality map value. */
254 /* Compute minutia pixel index. */
255 3709 index = (minutia->y * iw) + minutia->x;
256 /* Switch on pixel's quality value ... */
257 3709 qmap_value = pquality_map[index];
258
259 /* Combine grayscale reliability and quality map value. */
260
5/6
✓ Branch 13 → 14 taken 365 times.
✓ Branch 13 → 15 taken 1158 times.
✓ Branch 13 → 16 taken 1585 times.
✓ Branch 13 → 17 taken 568 times.
✗ Branch 13 → 18 not taken.
✓ Branch 13 → 23 taken 33 times.
3709 switch(qmap_value){
261 /* Quality A : [50..99]% */
262 365 case 4 :
263 365 reliability = 0.50 + (0.49 * gs_reliability);
264 365 break;
265 /* Quality B : [25..49]% */
266 1158 case 3 :
267 1158 reliability = 0.25 + (0.24 * gs_reliability);
268 1158 break;
269 /* Quality C : [10..24]% */
270 1585 case 2 :
271 1585 reliability = 0.10 + (0.14 * gs_reliability);
272 1585 break;
273 /* Quality D : [5..9]% */
274 568 case 1 :
275 568 reliability = 0.05 + (0.04 * gs_reliability);
276 568 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 3709 minutia->reliability = reliability;
290 }
291
292 /* NEW 05-08-2002 */
293 50 g_free(pquality_map);
294
295 /* Return normally. */
296 50 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 3709 double grayscale_reliability(MINUTIA *minutia, unsigned char *idata,
325 const int iw, const int ih, const int radius_pix)
326 {
327 3709 double mean, stdev;
328 3709 double reliability;
329
330 3709 get_neighborhood_stats(&mean, &stdev, minutia, idata, iw, ih, radius_pix);
331
332
4/6
✓ Branch 3 → 4 taken 3709 times.
✗ Branch 3 → 5 not taken.
✓ Branch 5 → 6 taken 3608 times.
✓ Branch 5 → 8 taken 101 times.
✓ Branch 6 → 7 taken 3608 times.
✗ Branch 6 → 8 not taken.
3709 reliability = min((stdev>IDEALSTDEV ? 1.0 : stdev/(double)IDEALSTDEV),
333 (1.0-(fabs(mean-IDEALMEAN)/(double)IDEALMEAN)));
334
335 3709 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 3709 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 3709 int i, x, y, rows, cols;
363 3709 int n = 0, sumX = 0, sumXX = 0;
364 3709 int histogram[256];
365
366 /* Zero out histogram. */
367 3709 memset(histogram, 0, 256 * sizeof(int));
368
369 /* Set minutia's coordinate variables. */
370 3709 x = minutia->x;
371 3709 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 3709 times.
✗ Branch 2 → 6 not taken.
✓ Branch 3 → 4 taken 3709 times.
✗ Branch 3 → 6 not taken.
✓ Branch 4 → 5 taken 3709 times.
✗ Branch 4 → 6 not taken.
3709 if ((x < radius_pix) || (x > iw-radius_pix-1) ||
377
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 3709 times.
3709 (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 3709 for(rows = y - radius_pix;
386
2/2
✓ Branch 12 → 8 taken 4501 times.
✓ Branch 12 → 16 taken 3709 times.
8210 rows <= y + radius_pix;
387 4501 rows++){
388 /* Foreach column in neighborhood ... */
389 4501 for(cols = x - radius_pix;
390
2/2
✓ Branch 10 → 9 taken 22717 times.
✓ Branch 10 → 11 taken 4501 times.
27218 cols <= x + radius_pix;
391 22717 cols++){
392 /* Bump neighbor's pixel value bin in histogram. */
393 22717 histogram[*(idata+(rows * iw)+cols)]++;
394 }
395 }
396
397 /* Foreach grayscale pixel bin ... */
398
2/2
✓ Branch 16 → 13 taken 949504 times.
✓ Branch 16 → 17 taken 3709 times.
953213 for(i = 0; i < 256; i++){
399
2/2
✓ Branch 13 → 14 taken 8930 times.
✓ Branch 13 → 15 taken 940574 times.
949504 if(histogram[i]){
400 /* Accumulate Sum(X[i]) */
401 8930 sumX += (i * histogram[i]);
402 /* Accumulate Sum(X[i]^2) */
403 8930 sumXX += (i * i * histogram[i]);
404 /* Accumulate N samples */
405 8930 n += histogram[i];
406 }
407 }
408
409 /* Mean = Sum(X[i])/N */
410 3709 *mean = sumX/(double)n;
411 /* Stdev = sqrt((Sum(X[i]^2)/N) - Mean^2) */
412 3709 *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