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 50 void bits_8to6(unsigned char *idata, const int iw, const int ih)
107 {
108 50 int i, isize;
109 50 unsigned char *iptr;
110
111 50 isize = iw * ih;
112 50 iptr = idata;
113
2/2
✓ Branch 4 → 3 taken 4250394 times.
✓ Branch 4 → 5 taken 50 times.
4250444 for(i = 0; i < isize; i++){
114 /* Divide every pixel value by 4 so that [0..256) -> [0..64) */
115 4250394 *iptr++ >>= 2;
116 }
117 50 }
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 100 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 100 int i;
143
144
2/2
✓ Branch 6 → 3 taken 7032152 times.
✓ Branch 6 → 7 taken 100 times.
7032252 for(i = 0; i < iw*ih; i++){
145
2/2
✓ Branch 3 → 4 taken 3516932 times.
✓ Branch 3 → 5 taken 3515220 times.
7032152 if(bdata[i] >= thresh)
146 bdata[i] = (unsigned char)greater_pix;
147 else
148 3516932 bdata[i] = (unsigned char)less_pix;
149 }
150 100 }
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 50 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 50 unsigned char *pdata, *pptr, *iptr;
182 50 int i, pw, ph;
183 50 int pad2, psize;
184
185 /* Account for pad on both sides of image */
186 50 pad2 = pad<<1;
187
188 /* Compute new pad sizes */
189 50 pw = iw + pad2;
190 50 ph = ih + pad2;
191 50 psize = pw * ph;
192
193 /* Allocate padded image */
194 50 pdata = (unsigned char *)g_malloc(psize * sizeof(unsigned char));
195
196 /* Initialize values to a constant PAD value */
197 50 memset(pdata, pad_value, psize);
198
199 /* Copy input image into padded image one scanline at a time */
200 50 iptr = idata;
201 50 pptr = pdata + (pad * pw) + pad;
202
2/2
✓ Branch 5 → 4 taken 14371 times.
✓ Branch 5 → 6 taken 50 times.
14421 for(i = 0; i < ih; i++){
203 14371 memcpy(pptr, iptr, iw);
204 14371 iptr += iw;
205 14371 pptr += pw;
206 }
207
208 50 *optr = pdata;
209 50 *ow = pw;
210 50 *oh = ph;
211 50 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 150 void fill_holes(unsigned char *bdata, const int iw, const int ih)
231 {
232 150 int ix, iy, iw2;
233 150 unsigned char *lptr, *mptr, *rptr, *tptr, *bptr, *sptr;
234
235 /* 1. Fill 1-pixel wide holes in horizontal runs first ... */
236 150 sptr = bdata + 1;
237 /* Foreach row in image ... */
238
2/2
✓ Branch 11 → 3 taken 43113 times.
✓ Branch 11 → 12 taken 150 times.
43263 for(iy = 0; iy < ih; iy++){
239 /* Initialize pointers to start of next line ... */
240 43113 lptr = sptr-1; /* Left pixel */
241 43113 mptr = sptr; /* Middle pixel */
242 43113 rptr = sptr+1; /* Right pixel */
243 /* Foreach column in image (less far left and right pixels) ... */
244
2/2
✓ Branch 9 → 4 taken 10418289 times.
✓ Branch 9 → 10 taken 43113 times.
10461402 for(ix = 1; ix < iw-1; ix++){
245 /* Do we have a horizontal hole of length 1? */
246
4/4
✓ Branch 4 → 5 taken 1395023 times.
✓ Branch 4 → 7 taken 9023266 times.
✓ Branch 5 → 6 taken 43713 times.
✓ Branch 5 → 7 taken 1351310 times.
10418289 if((*lptr != *mptr) && (*lptr == *rptr)){
247 /* If so, then fill it. */
248 43713 *mptr = *lptr;
249 /* Bump passed right pixel because we know it will not */
250 /* be a hole. */
251 43713 lptr+=2;
252 43713 mptr+=2;
253 43713 rptr+=2;
254 /* We bump ix once here and then the FOR bumps it again. */
255 43713 ix++;
256 }
257 else{
258 /* Otherwise, bump to the next pixel to the right. */
259 10374576 lptr++;
260 10374576 mptr++;
261 10374576 rptr++;
262 }
263 }
264 /* Bump to start of next row. */
265 43113 sptr += iw;
266 }
267
268 /* 2. Now, fill 1-pixel wide holes in vertical runs ... */
269 150 iw2 = iw<<1;
270 /* Start processing column one row down from the top of the image. */
271 150 sptr = bdata + iw;
272 /* Foreach column in image ... */
273
2/2
✓ Branch 21 → 13 taken 37716 times.
✓ Branch 21 → 22 taken 150 times.
37866 for(ix = 0; ix < iw; ix++){
274 /* Initialize pointers to start of next column ... */
275 37716 tptr = sptr-iw; /* Top pixel */
276 37716 mptr = sptr; /* Middle pixel */
277 37716 bptr = sptr+iw; /* Bottom pixel */
278 /* Foreach row in image (less top and bottom row) ... */
279
2/2
✓ Branch 19 → 14 taken 10422841 times.
✓ Branch 19 → 20 taken 37716 times.
10460557 for(iy = 1; iy < ih-1; iy++){
280 /* Do we have a vertical hole of length 1? */
281
4/4
✓ Branch 14 → 15 taken 1764725 times.
✓ Branch 14 → 17 taken 8658116 times.
✓ Branch 15 → 16 taken 49955 times.
✓ Branch 15 → 17 taken 1714770 times.
10422841 if((*tptr != *mptr) && (*tptr == *bptr)){
282 /* If so, then fill it. */
283 49955 *mptr = *tptr;
284 /* Bump passed bottom pixel because we know it will not */
285 /* be a hole. */
286 49955 tptr+=iw2;
287 49955 mptr+=iw2;
288 49955 bptr+=iw2;
289 /* We bump iy once here and then the FOR bumps it again. */
290 49955 iy++;
291 }
292 else{
293 /* Otherwise, bump to the next pixel below. */
294 10372886 tptr+=iw;
295 10372886 mptr+=iw;
296 10372886 bptr+=iw;
297 }
298 }
299 /* Bump to start of next column. */
300 37716 sptr++;
301 }
302 150 }
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 870 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 870 int *x_list, *y_list, num;
330 870 int ret;
331 870 int i, trans, preval, nextval;
332
333 /* Compute points along line segment between the two points. */
334
1/2
✓ Branch 3 → 4 taken 870 times.
✗ Branch 3 → 15 not taken.
870 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 870 trans = 0;
339 /* Get the pixel value of first point along line segment. */
340 870 preval = *(bdata+(y1*iw)+x1);
341
342 /* Foreach remaining point along line segment ... */
343
2/2
✓ Branch 11 → 5 taken 3650 times.
✓ Branch 11 → 12 taken 835 times.
4485 for(i = 1; i < num; i++){
344 /* Get pixel value of next point along line segment. */
345 3650 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 1769 times.
✓ Branch 5 → 10 taken 1881 times.
3650 if(nextval != preval){
349 /* Then we have detected a transition, so bump counter. */
350 1769 trans++;
351 /* If number of transitions seen > than threshold (ex. 2) ... */
352
2/2
✓ Branch 6 → 7 taken 35 times.
✓ Branch 6 → 10 taken 1734 times.
1769 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 835 g_free(x_list);
370 835 g_free(y_list);
371
372 /* Return free path to be TRUE. */
373 835 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 4655 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 4655 int i, x, y, px, py;
410 4655 double fx, fy;
411
412 /* Set previous point to starting point. */
413 4655 px = strt_x;
414 4655 py = strt_y;
415 /* Set floating point accumulators to starting point. */
416 4655 fx = (double)strt_x;
417 4655 fy = (double)strt_y;
418
419 /* Foreach step up to the specified maximum ... */
420
2/2
✓ Branch 16 → 3 taken 21456 times.
✓ Branch 16 → 17 taken 200 times.
21656 for(i = 0; i < maxsteps; i++){
421
422 /* Increment accumulators. */
423 21456 fx += delta_x;
424 21456 fy += delta_y;
425 /* Round to get next step. */
426
2/2
✓ Branch 3 → 4 taken 7 times.
✓ Branch 3 → 5 taken 21449 times.
21456 x = sround(fx);
427
2/2
✓ Branch 6 → 7 taken 11 times.
✓ Branch 6 → 8 taken 21445 times.
21456 y = sround(fy);
428
429 /* If we stepped outside the image boundaries ... */
430
2/2
✓ Branch 9 → 10 taken 21442 times.
✓ Branch 9 → 11 taken 14 times.
21456 if((x < 0) || (x >= iw) ||
431
2/2
✓ Branch 10 → 11 taken 9 times.
✓ Branch 10 → 12 taken 21433 times.
21442 (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 4432 times.
✓ Branch 12 → 15 taken 17001 times.
21433 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 4432 fix_edge_pixel_pair(&x, &y, &px, &py, bdata, iw, ih);
451
452 /* Return TRUE (we found what we were looking for). */
453 4432 *ox = x;
454 4432 *oy = y;
455 4432 *oex = px;
456 4432 *oey = py;
457 4432 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 17001 px = x;
463 17001 py = y;
464 }
465
466 /* Return FALSE (we did not find what we were looking for). */
467 200 *ox = -1;
468 200 *oy = -1;
469 200 *oex = -1;
470 200 *oey = -1;
471 200 return(FALSE);
472 }
473
474