GCC Code Coverage Report


Directory: ./
File: libfprint/nbis/mindtct/quality.c
Date: 2024-05-04 14:54:39
Exec Total Coverage
Lines: 92 105 87.6%
Functions: 4 4 100.0%
Branches: 59 70 84.3%

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 48 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 48 int *QualMap;
113 48 int thisX, thisY;
114 48 int compX, compY;
115 48 int arrayPos, arrayPos2;
116 48 int QualOffset;
117
118
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 ASSERT_SIZE_MUL(map_w, map_h);
119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 ASSERT_SIZE_MUL(map_w * map_h, sizeof(int));
120
121 48 QualMap = (int *)g_malloc(map_w * map_h * sizeof(int));
122
123 /* Foreach row of blocks in maps ... */
124
2/2
✓ Branch 1 taken 1673 times.
✓ Branch 2 taken 48 times.
1769 for(thisY=0; thisY<map_h; thisY++){
125 /* Foreach block in current row ... */
126
2/2
✓ Branch 0 taken 50730 times.
✓ Branch 1 taken 1673 times.
52403 for(thisX=0; thisX<map_w; thisX++) {
127 /* Compute block index. */
128 50730 arrayPos=(thisY*map_w)+thisX;
129 /* If current block has low contrast or INVALID direction ... */
130
4/4
✓ Branch 0 taken 46139 times.
✓ Branch 1 taken 4591 times.
✓ Branch 2 taken 7169 times.
✓ Branch 3 taken 38970 times.
50730 if(low_contrast_map[arrayPos] || direction_map[arrayPos]<0)
131 /* Set block's quality to 0/F. */
132 11760 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 0 taken 24012 times.
✓ Branch 1 taken 14958 times.
✓ Branch 2 taken 811 times.
✓ Branch 3 taken 23201 times.
38970 if(low_flow_map[arrayPos] || high_curve_map[arrayPos])
138 /* Set block's quality initially to 3/B. */
139 15769 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 23201 QualMap[arrayPos]=4; /* offset will be 0..-2 */
144
145 /* If block within NEIGHBOR_DELTA of edge ... */
146
6/6
✓ Branch 0 taken 37764 times.
✓ Branch 1 taken 1206 times.
✓ Branch 2 taken 36581 times.
✓ Branch 3 taken 1183 times.
✓ Branch 4 taken 35350 times.
✓ Branch 5 taken 1231 times.
38970 if(thisY < NEIGHBOR_DELTA || thisY > map_h - 1 - NEIGHBOR_DELTA ||
147
2/2
✓ Branch 0 taken 1086 times.
✓ Branch 1 taken 34264 times.
35350 thisX < NEIGHBOR_DELTA || thisX > map_w - 1 - NEIGHBOR_DELTA)
148 /* Set block's quality to 1/E. */
149 4706 QualMap[arrayPos]=1;
150 /* Otherwise, test neighboring blocks ... */
151 else{
152 /* Initialize quality adjustment to 0. */
153 34264 QualOffset=0;
154 /* Foreach row in neighborhood ... */
155 34264 for(compY=thisY-NEIGHBOR_DELTA;
156
2/2
✓ Branch 0 taken 171320 times.
✓ Branch 1 taken 34264 times.
205584 compY<=thisY+NEIGHBOR_DELTA;compY++){
157 /* Foreach block in neighborhood */
158 /* (including current block)... */
159 171320 for(compX=thisX-NEIGHBOR_DELTA;
160
2/2
✓ Branch 0 taken 800842 times.
✓ Branch 1 taken 147621 times.
948463 compX<=thisX+NEIGHBOR_DELTA;compX++) {
161 /* Compute neighboring block's index. */
162 800842 arrayPos2 = (compY*map_w)+compX;
163 /* If neighbor block (which might be itself) has */
164 /* low contrast or INVALID direction .. */
165
2/2
✓ Branch 0 taken 797757 times.
✓ Branch 1 taken 3085 times.
800842 if(low_contrast_map[arrayPos2] ||
166
2/2
✓ Branch 0 taken 777143 times.
✓ Branch 1 taken 20614 times.
797757 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 0 taken 474406 times.
✓ Branch 1 taken 302737 times.
777143 else if(low_flow_map[arrayPos2] ||
175
2/2
✓ Branch 0 taken 16534 times.
✓ Branch 1 taken 457872 times.
474406 high_curve_map[arrayPos2]) {
176 /* Set quality to -1 if not already -2. */
177 319271 QualOffset=min(QualOffset,-1);
178 }
179 }
180 }
181 /* Decrement minutia quality by neighborhood adjustment. */
182 34264 QualMap[arrayPos]+=QualOffset;
183 }
184 }
185 }
186 }
187
188 /* Set output pointer. */
189 48 *oqmap = QualMap;
190 /* Return normally. */
191 48 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 48 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 48 int ret, i, index, radius_pix;
223 48 int *pquality_map, qmap_value;
224 48 MINUTIA *minutia;
225 48 double gs_reliability, reliability;
226
227 /* If image is not 8-bit grayscale ... */
228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 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 0 not taken.
✓ Branch 1 taken 48 times.
48 radius_pix = sround(RADIUS_MM * ppmm);
237
238 /* Expand block map values to pixel map. */
239
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 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 0 taken 3495 times.
✓ Branch 1 taken 48 times.
3543 for(i = 0; i < minutiae->num; i++){
246 /* Assign minutia pointer. */
247 3495 minutia = minutiae->list[i];
248
249 /* Compute reliability from stdev and mean of pixel neighborhood. */
250 3495 gs_reliability = grayscale_reliability(minutia,
251 idata, iw, ih, radius_pix);
252
253 /* Lookup quality map value. */
254 /* Compute minutia pixel index. */
255 3495 index = (minutia->y * iw) + minutia->x;
256 /* Switch on pixel's quality value ... */
257 3495 qmap_value = pquality_map[index];
258
259 /* Combine grayscale reliability and quality map value. */
260
5/6
✓ Branch 0 taken 359 times.
✓ Branch 1 taken 938 times.
✓ Branch 2 taken 1599 times.
✓ Branch 3 taken 596 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
3495 switch(qmap_value){
261 /* Quality A : [50..99]% */
262 359 case 4 :
263 359 reliability = 0.50 + (0.49 * gs_reliability);
264 359 break;
265 /* Quality B : [25..49]% */
266 938 case 3 :
267 938 reliability = 0.25 + (0.24 * gs_reliability);
268 938 break;
269 /* Quality C : [10..24]% */
270 1599 case 2 :
271 1599 reliability = 0.10 + (0.14 * gs_reliability);
272 1599 break;
273 /* Quality D : [5..9]% */
274 596 case 1 :
275 596 reliability = 0.05 + (0.04 * gs_reliability);
276 596 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 3495 minutia->reliability = reliability;
290 }
291
292 /* NEW 05-08-2002 */
293 48 g_free(pquality_map);
294
295 /* Return normally. */
296 48 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 3495 double grayscale_reliability(MINUTIA *minutia, unsigned char *idata,
325 const int iw, const int ih, const int radius_pix)
326 {
327 3495 double mean, stdev;
328 3495 double reliability;
329
330 3495 get_neighborhood_stats(&mean, &stdev, minutia, idata, iw, ih, radius_pix);
331
332
3/4
✓ Branch 0 taken 3495 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3474 times.
✓ Branch 3 taken 21 times.
3495 reliability = min((stdev>IDEALSTDEV ? 1.0 : stdev/(double)IDEALSTDEV),
333 (1.0-(fabs(mean-IDEALMEAN)/(double)IDEALMEAN)));
334
335 3495 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 3495 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 3495 int i, x, y, rows, cols;
363 3495 int n = 0, sumX = 0, sumXX = 0;
364 3495 int histogram[256];
365
366 /* Zero out histogram. */
367 3495 memset(histogram, 0, 256 * sizeof(int));
368
369 /* Set minutia's coordinate variables. */
370 3495 x = minutia->x;
371 3495 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 0 taken 3495 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3495 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3495 times.
✗ Branch 5 not taken.
3495 if ((x < radius_pix) || (x > iw-radius_pix-1) ||
377
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3495 times.
3495 (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 3495 for(rows = y - radius_pix;
386
2/2
✓ Branch 0 taken 3495 times.
✓ Branch 1 taken 3495 times.
6990 rows <= y + radius_pix;
387 3495 rows++){
388 /* Foreach column in neighborhood ... */
389 3495 for(cols = x - radius_pix;
390
2/2
✓ Branch 0 taken 3495 times.
✓ Branch 1 taken 3495 times.
6990 cols <= x + radius_pix;
391 3495 cols++){
392 /* Bump neighbor's pixel value bin in histogram. */
393 3495 histogram[*(idata+(rows * iw)+cols)]++;
394 }
395 }
396
397 /* Foreach grayscale pixel bin ... */
398
2/2
✓ Branch 0 taken 894720 times.
✓ Branch 1 taken 3495 times.
898215 for(i = 0; i < 256; i++){
399
2/2
✓ Branch 0 taken 3495 times.
✓ Branch 1 taken 891225 times.
894720 if(histogram[i]){
400 /* Accumulate Sum(X[i]) */
401 3495 sumX += (i * histogram[i]);
402 /* Accumulate Sum(X[i]^2) */
403 3495 sumXX += (i * i * histogram[i]);
404 /* Accumulate N samples */
405 3495 n += histogram[i];
406 }
407 }
408
409 /* Mean = Sum(X[i])/N */
410 3495 *mean = sumX/(double)n;
411 /* Stdev = sqrt((Sum(X[i]^2)/N) - Mean^2) */
412 3495 *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