GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 122 / 0 / 122
Functions: 100.0% 6 / 0 / 6
Branches: 97.7% 43 / 0 / 44

libfprint/nbis/mindtct/imgutil.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: IMGUTIL.C
49 AUTHOR: Michael D. Garris
50 DATE: 03/16/1999
51 UPDATED: 03/16/2005 by MDG
52
53 Contains general support image routines required by the NIST
54 Latent Fingerprint System (LFS).
55
56 ***********************************************************************
57 ROUTINES:
58 bits_6to8()
59 bits_8to6()
60 gray2bin()
61 pad_uchar_image()
62 fill_holes()
63 free_path()
64 search_in_direction()
65
66 ***********************************************************************/
67
68 #include <stdio.h>
69 #include <memory.h>
70 #include <lfs.h>
71
72 /*************************************************************************
73 **************************************************************************
74 #cat: bits_6to8 - Takes an array of unsigned characters and bitwise shifts
75 #cat: each value 2 postitions to the left. This is equivalent
76 #cat: to multiplying each value by 4. This puts original values
77 #cat: on the range [0..64) now on the range [0..256). Another
78 #cat: way to say this, is the original 6-bit values now fit in
79 #cat: 8 bits. This is to be used to undo the effects of bits_8to6.
80
81 Input:
82 idata - input array of unsigned characters
83 iw - width (in characters) of the input array
84 ih - height (in characters) of the input array
85 Output:
86 idata - contains the bit-shifted results
87 **************************************************************************/
88
89 /*************************************************************************
90 **************************************************************************
91 #cat: bits_8to6 - Takes an array of unsigned characters and bitwise shifts
92 #cat: each value 2 postitions to the right. This is equivalent
93 #cat: to dividing each value by 4. This puts original values
94 #cat: on the range [0..256) now on the range [0..64). Another
95 #cat: way to say this, is the original 8-bit values now fit in
96 #cat: 6 bits. I would really like to make this dependency
97 #cat: go away.
98
99 Input:
100 idata - input array of unsigned characters
101 iw - width (in characters) of the input array
102 ih - height (in characters) of the input array
103 Output:
104 idata - contains the bit-shifted results
105 **************************************************************************/
106 49 void bits_8to6(unsigned char *idata, const int iw, const int ih)
107 {
108 49 int i, isize;
109 49 unsigned char *iptr;
110
111 49 isize = iw * ih;
112 49 iptr = idata;
113
2/2
✓ Branch 4 → 3 taken 4019290 times.
✓ Branch 4 → 5 taken 49 times.
4019339 for(i = 0; i < isize; i++){
114 /* Divide every pixel value by 4 so that [0..256) -> [0..64) */
115 4019290 *iptr++ >>= 2;
116 }
117 49 }
118
119 /*************************************************************************
120 **************************************************************************
121 #cat: gray2bin - Takes an 8-bit threshold value and two 8-bit pixel values.
122 #cat: Those pixels in the image less than the threhsold are set
123 #cat: to the first specified pixel value, whereas those pixels
124 #cat: greater than or equal to the threshold are set to the second
125 #cat: specified pixel value. On application for this routine is
126 #cat: to convert binary images from 8-bit pixels valued {0,255} to
127 #cat: {1,0} and vice versa.
128
129 Input:
130 thresh - 8-bit pixel threshold
131 less_pix - pixel value used when image pixel is < threshold
132 greater_pix - pixel value used when image pixel is >= threshold
133 bdata - 8-bit image data
134 iw - width (in pixels) of the image
135 ih - height (in pixels) of the image
136 Output:
137 bdata - altered 8-bit image data
138 **************************************************************************/
139 98 void gray2bin(const int thresh, const int less_pix, const int greater_pix,
140 unsigned char *bdata, const int iw, const int ih)
141 {
142 98 int i;
143
144
2/2
✓ Branch 6 → 3 taken 6623192 times.
✓ Branch 6 → 7 taken 98 times.
6623290 for(i = 0; i < iw*ih; i++){
145
2/2
✓ Branch 3 → 4 taken 3312690 times.
✓ Branch 3 → 5 taken 3310502 times.
6623192 if(bdata[i] >= thresh)
146 bdata[i] = (unsigned char)greater_pix;
147 else
148 3312690 bdata[i] = (unsigned char)less_pix;
149 }
150 98 }
151
152 /*************************************************************************
153 **************************************************************************
154 #cat: pad_uchar_image - Copies an 8-bit grayscale images into a larger
155 #cat: output image centering the input image so as to
156 #cat: add a specified amount of pixel padding along the
157 #cat: entire perimeter of the input image. The amount of
158 #cat: pixel padding and the intensity of the pixel padding
159 #cat: are specified. An alternative to padding with a
160 #cat: constant intensity would be to copy the edge pixels
161 #cat: of the centered image into the adjacent pad area.
162
163 Input:
164 idata - input 8-bit grayscale image
165 iw - width (in pixels) of the input image
166 ih - height (in pixels) of the input image
167 pad - size of padding (in pixels) to be added
168 pad_value - intensity of the padded area
169 Output:
170 optr - points to the newly padded image
171 ow - width (in pixels) of the padded image
172 oh - height (in pixels) of the padded image
173 Return Code:
174 Zero - successful completion
175 Negative - system error
176 **************************************************************************/
177 49 int pad_uchar_image(unsigned char **optr, int *ow, int *oh,
178 unsigned char *idata, const int iw, const int ih,
179 const int pad, const int pad_value)
180 {
181 49 unsigned char *pdata, *pptr, *iptr;
182 49 int i, pw, ph;
183 49 int pad2, psize;
184
185 /* Account for pad on both sides of image */
186 49 pad2 = pad<<1;
187
188 /* Compute new pad sizes */
189 49 pw = iw + pad2;
190 49 ph = ih + pad2;
191 49 psize = pw * ph;
192
193 /* Allocate padded image */
194 49 pdata = (unsigned char *)g_malloc(psize * sizeof(unsigned char));
195
196 /* Initialize values to a constant PAD value */
197 49 memset(pdata, pad_value, psize);
198
199 /* Copy input image into padded image one scanline at a time */
200 49 iptr = idata;
201 49 pptr = pdata + (pad * pw) + pad;
202
2/2
✓ Branch 5 → 4 taken 13661 times.
✓ Branch 5 → 6 taken 49 times.
13710 for(i = 0; i < ih; i++){
203 13661 memcpy(pptr, iptr, iw);
204 13661 iptr += iw;
205 13661 pptr += pw;
206 }
207
208 49 *optr = pdata;
209 49 *ow = pw;
210 49 *oh = ph;
211 49 return(0);
212 }
213
214 /*************************************************************************
215 **************************************************************************
216 #cat: fill_holes - Takes an input image and analyzes triplets of horizontal
217 #cat: pixels first and then triplets of vertical pixels, filling
218 #cat: in holes of width 1. A hole is defined as the case where
219 #cat: the neighboring 2 pixels are equal, AND the center pixel
220 #cat: is different. Each hole is filled with the value of its
221 #cat: immediate neighbors. This routine modifies the input image.
222
223 Input:
224 bdata - binary image data to be processed
225 iw - width (in pixels) of the binary input image
226 ih - height (in pixels) of the binary input image
227 Output:
228 bdata - points to the results
229 **************************************************************************/
230 147 void fill_holes(unsigned char *bdata, const int iw, const int ih)
231 {
232 147 int ix, iy, iw2;
233 147 unsigned char *lptr, *mptr, *rptr, *tptr, *bptr, *sptr;
234
235 /* 1. Fill 1-pixel wide holes in horizontal runs first ... */
236 147 sptr = bdata + 1;
237 /* Foreach row in image ... */
238
2/2
✓ Branch 11 → 3 taken 40983 times.
✓ Branch 11 → 12 taken 147 times.
41130 for(iy = 0; iy < ih; iy++){
239 /* Initialize pointers to start of next line ... */
240 40983 lptr = sptr-1; /* Left pixel */
241 40983 mptr = sptr; /* Middle pixel */
242 40983 rptr = sptr+1; /* Right pixel */
243 /* Foreach column in image (less far left and right pixels) ... */
244
2/2
✓ Branch 9 → 4 taken 9810961 times.
✓ Branch 9 → 10 taken 40983 times.
9851944 for(ix = 1; ix < iw-1; ix++){
245 /* Do we have a horizontal hole of length 1? */
246
4/4
✓ Branch 4 → 5 taken 1359657 times.
✓ Branch 4 → 7 taken 8451304 times.
✓ Branch 5 → 6 taken 41861 times.
✓ Branch 5 → 7 taken 1317796 times.
9810961 if((*lptr != *mptr) && (*lptr == *rptr)){
247 /* If so, then fill it. */
248 41861 *mptr = *lptr;
249 /* Bump passed right pixel because we know it will not */
250 /* be a hole. */
251 41861 lptr+=2;
252 41861 mptr+=2;
253 41861 rptr+=2;
254 /* We bump ix once here and then the FOR bumps it again. */
255 41861 ix++;
256 }
257 else{
258 /* Otherwise, bump to the next pixel to the right. */
259 9769100 lptr++;
260 9769100 mptr++;
261 9769100 rptr++;
262 }
263 }
264 /* Bump to start of next row. */
265 40983 sptr += iw;
266 }
267
268 /* 2. Now, fill 1-pixel wide holes in vertical runs ... */
269 147 iw2 = iw<<1;
270 /* Start processing column one row down from the top of the image. */
271 147 sptr = bdata + iw;
272 /* Foreach column in image ... */
273
2/2
✓ Branch 21 → 13 taken 36852 times.
✓ Branch 21 → 22 taken 147 times.
36999 for(ix = 0; ix < iw; ix++){
274 /* Initialize pointers to start of next column ... */
275 36852 tptr = sptr-iw; /* Top pixel */
276 36852 mptr = sptr; /* Middle pixel */
277 36852 bptr = sptr+iw; /* Bottom pixel */
278 /* Foreach row in image (less top and bottom row) ... */
279
2/2
✓ Branch 19 → 14 taken 9813569 times.
✓ Branch 19 → 20 taken 36852 times.
9850421 for(iy = 1; iy < ih-1; iy++){
280 /* Do we have a vertical hole of length 1? */
281
4/4
✓ Branch 14 → 15 taken 1698843 times.
✓ Branch 14 → 17 taken 8114726 times.
✓ Branch 15 → 16 taken 47515 times.
✓ Branch 15 → 17 taken 1651328 times.
9813569 if((*tptr != *mptr) && (*tptr == *bptr)){
282 /* If so, then fill it. */
283 47515 *mptr = *tptr;
284 /* Bump passed bottom pixel because we know it will not */
285 /* be a hole. */
286 47515 tptr+=iw2;
287 47515 mptr+=iw2;
288 47515 bptr+=iw2;
289 /* We bump iy once here and then the FOR bumps it again. */
290 47515 iy++;
291 }
292 else{
293 /* Otherwise, bump to the next pixel below. */
294 9766054 tptr+=iw;
295 9766054 mptr+=iw;
296 9766054 bptr+=iw;
297 }
298 }
299 /* Bump to start of next column. */
300 36852 sptr++;
301 }
302 147 }
303
304 /*************************************************************************
305 **************************************************************************
306 #cat: free_path - Traverses a straight line between 2 pixel points in an
307 #cat: image and determines if a "free path" exists between the
308 #cat: 2 points by counting the number of pixel value transitions
309 #cat: between adjacent pixels along the trajectory.
310
311 Input:
312 x1 - x-pixel coord of first point
313 y1 - y-pixel coord of first point
314 x2 - x-pixel coord of second point
315 y2 - y-pixel coord of second point
316 bdata - binary image data (0==while & 1==black)
317 iw - width (in pixels) of image
318 ih - height (in pixels) of image
319 lfsparms - parameters and threshold for controlling LFS
320 Return Code:
321 TRUE - free path determined to exist
322 FALSE - free path determined not to exist
323 Negative - system error
324 **************************************************************************/
325 841 int free_path(const int x1, const int y1, const int x2, const int y2,
326 unsigned char *bdata, const int iw, const int ih,
327 const LFSPARMS *lfsparms)
328 {
329 841 int *x_list, *y_list, num;
330 841 int ret;
331 841 int i, trans, preval, nextval;
332
333 /* Compute points along line segment between the two points. */
334
1/2
✓ Branch 3 → 4 taken 841 times.
✗ Branch 3 → 15 not taken.
841 if((ret = line_points(&x_list, &y_list, &num, x1, y1, x2, y2)))
335 return(ret);
336
337 /* Intialize the number of transitions to 0. */
338 841 trans = 0;
339 /* Get the pixel value of first point along line segment. */
340 841 preval = *(bdata+(y1*iw)+x1);
341
342 /* Foreach remaining point along line segment ... */
343
2/2
✓ Branch 11 → 5 taken 3516 times.
✓ Branch 11 → 12 taken 806 times.
4322 for(i = 1; i < num; i++){
344 /* Get pixel value of next point along line segment. */
345 3516 nextval = *(bdata+(y_list[i]*iw)+x_list[i]);
346
347 /* If next pixel value different from previous pixel value ... */
348
2/2
✓ Branch 5 → 6 taken 1713 times.
✓ Branch 5 → 10 taken 1803 times.
3516 if(nextval != preval){
349 /* Then we have detected a transition, so bump counter. */
350 1713 trans++;
351 /* If number of transitions seen > than threshold (ex. 2) ... */
352
2/2
✓ Branch 6 → 7 taken 35 times.
✓ Branch 6 → 10 taken 1678 times.
1713 if(trans > lfsparms->maxtrans){
353 /* Deallocate the line segment's coordinate lists. */
354 35 g_free(x_list);
355 35 g_free(y_list);
356 /* Return free path to be FALSE. */
357 35 return(FALSE);
358 }
359 /* Otherwise, maximum number of transitions not yet exceeded. */
360 /* Assign the next pixel value to the previous pixel value. */
361 preval = nextval;
362 }
363 /* Otherwise, no transition detected this interation. */
364
365 }
366
367 /* If we get here we did not exceed the maximum allowable number */
368 /* of transitions. So, deallocate the line segment's coordinate lists. */
369 806 g_free(x_list);
370 806 g_free(y_list);
371
372 /* Return free path to be TRUE. */
373 806 return(TRUE);
374 }
375
376 /*************************************************************************
377 **************************************************************************
378 #cat: search_in_direction - Takes a specified maximum number of steps in a
379 #cat: specified direction looking for the first occurence of
380 #cat: a pixel with specified value. (Once found, adjustments
381 #cat: are potentially made to make sure the resulting pixel
382 #cat: and its associated edge pixel are 4-connected.)
383
384 Input:
385 pix - value of pixel to be searched for
386 strt_x - x-pixel coord to start search
387 strt_y - y-pixel coord to start search
388 delta_x - increment in x for each step
389 delta_y - increment in y for each step
390 maxsteps - maximum number of steps to conduct search
391 bdata - binary image data (0==while & 1==black)
392 iw - width (in pixels) of image
393 ih - height (in pixels) of image
394 Output:
395 ox - x coord of located pixel
396 oy - y coord of located pixel
397 oex - x coord of associated edge pixel
398 oey - y coord of associated edge pixel
399 Return Code:
400 TRUE - pixel of specified value found
401 FALSE - pixel of specified value NOT found
402 **************************************************************************/
403 4396 int search_in_direction(int *ox, int *oy, int *oex, int *oey, const int pix,
404 const int strt_x, const int strt_y,
405 const double delta_x, const double delta_y, const int maxsteps,
406 unsigned char *bdata, const int iw, const int ih)
407 {
408
409 4396 int i, x, y, px, py;
410 4396 double fx, fy;
411
412 /* Set previous point to starting point. */
413 4396 px = strt_x;
414 4396 py = strt_y;
415 /* Set floating point accumulators to starting point. */
416 4396 fx = (double)strt_x;
417 4396 fy = (double)strt_y;
418
419 /* Foreach step up to the specified maximum ... */
420
2/2
✓ Branch 16 → 3 taken 20145 times.
✓ Branch 16 → 17 taken 180 times.
20325 for(i = 0; i < maxsteps; i++){
421
422 /* Increment accumulators. */
423 20145 fx += delta_x;
424 20145 fy += delta_y;
425 /* Round to get next step. */
426
2/2
✓ Branch 3 → 4 taken 7 times.
✓ Branch 3 → 5 taken 20138 times.
20145 x = sround(fx);
427
2/2
✓ Branch 6 → 7 taken 11 times.
✓ Branch 6 → 8 taken 20134 times.
20145 y = sround(fy);
428
429 /* If we stepped outside the image boundaries ... */
430
2/2
✓ Branch 9 → 10 taken 20131 times.
✓ Branch 9 → 11 taken 14 times.
20145 if((x < 0) || (x >= iw) ||
431
2/2
✓ Branch 10 → 11 taken 9 times.
✓ Branch 10 → 12 taken 20122 times.
20131 (y < 0) || (y >= ih)){
432 /* Return FALSE (we did not find what we were looking for). */
433 23 *ox = -1;
434 23 *oy = -1;
435 23 *oex = -1;
436 23 *oey = -1;
437 23 return(FALSE);
438 }
439
440 /* Otherwise, test to see if we found our pixel with value 'pix'. */
441
2/2
✓ Branch 12 → 13 taken 4193 times.
✓ Branch 12 → 15 taken 15929 times.
20122 if(*(bdata+(y*iw)+x) == pix){
442 /* The previous and current pixels form a feature, edge pixel */
443 /* pair, which we would like to use for edge following. The */
444 /* previous pixel may be a diagonal neighbor however to the */
445 /* current pixel, in which case the pair could not be used by */
446 /* the contour tracing (which requires the edge pixel in the */
447 /* pair neighbor to the N,S,E or W. */
448 /* This routine adjusts the pair so that the results may be */
449 /* used by the contour tracing. */
450 4193 fix_edge_pixel_pair(&x, &y, &px, &py, bdata, iw, ih);
451
452 /* Return TRUE (we found what we were looking for). */
453 4193 *ox = x;
454 4193 *oy = y;
455 4193 *oex = px;
456 4193 *oey = py;
457 4193 return(TRUE);
458 }
459
460 /* Otherwise, still haven't found pixel with desired value, */
461 /* so set current point to previous and take another step. */
462 15929 px = x;
463 15929 py = y;
464 }
465
466 /* Return FALSE (we did not find what we were looking for). */
467 180 *ox = -1;
468 180 *oy = -1;
469 180 *oex = -1;
470 180 *oey = -1;
471 180 return(FALSE);
472 }
473
474