GCC Code Coverage Report


Directory: ./
File: libfprint/nbis/mindtct/imgutil.c
Date: 2024-09-16 14:36:32
Exec Total Coverage
Lines: 123 123 100.0%
Functions: 6 6 100.0%
Branches: 43 44 97.7%

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 48 void bits_8to6(unsigned char *idata, const int iw, const int ih)
107 {
108 48 int i, isize;
109 48 unsigned char *iptr;
110
111 48 isize = iw * ih;
112 48 iptr = idata;
113
2/2
✓ Branch 0 taken 3880414 times.
✓ Branch 1 taken 48 times.
3880462 for(i = 0; i < isize; i++){
114 /* Divide every pixel value by 4 so that [0..256) -> [0..64) */
115 3880414 *iptr++ >>= 2;
116 }
117 48 }
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 96 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 96 int i;
143
144
2/2
✓ Branch 0 taken 6383192 times.
✓ Branch 1 taken 96 times.
6383288 for(i = 0; i < iw*ih; i++){
145
2/2
✓ Branch 0 taken 3193951 times.
✓ Branch 1 taken 3189241 times.
6383192 if(bdata[i] >= thresh)
146 3193951 bdata[i] = (unsigned char)greater_pix;
147 else
148 3189241 bdata[i] = (unsigned char)less_pix;
149 }
150 96 }
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 48 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 48 unsigned char *pdata, *pptr, *iptr;
182 48 int i, pw, ph;
183 48 int pad2, psize;
184
185 /* Account for pad on both sides of image */
186 48 pad2 = pad<<1;
187
188 /* Compute new pad sizes */
189 48 pw = iw + pad2;
190 48 ph = ih + pad2;
191 48 psize = pw * ph;
192
193 /* Allocate padded image */
194 48 pdata = (unsigned char *)g_malloc(psize * sizeof(unsigned char));
195
196 /* Initialize values to a constant PAD value */
197 48 memset(pdata, pad_value, psize);
198
199 /* Copy input image into padded image one scanline at a time */
200 48 iptr = idata;
201 48 pptr = pdata + (pad * pw) + pad;
202
2/2
✓ Branch 0 taken 13261 times.
✓ Branch 1 taken 48 times.
13309 for(i = 0; i < ih; i++){
203 13261 memcpy(pptr, iptr, iw);
204 13261 iptr += iw;
205 13261 pptr += pw;
206 }
207
208 48 *optr = pdata;
209 48 *ow = pw;
210 48 *oh = ph;
211 48 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 144 void fill_holes(unsigned char *bdata, const int iw, const int ih)
231 {
232 144 int ix, iy, iw2;
233 144 unsigned char *lptr, *mptr, *rptr, *tptr, *bptr, *sptr;
234
235 /* 1. Fill 1-pixel wide holes in horizontal runs first ... */
236 144 sptr = bdata + 1;
237 /* Foreach row in image ... */
238
2/2
✓ Branch 0 taken 39783 times.
✓ Branch 1 taken 144 times.
39927 for(iy = 0; iy < ih; iy++){
239 /* Initialize pointers to start of next line ... */
240 39783 lptr = sptr-1; /* Left pixel */
241 39783 mptr = sptr; /* Middle pixel */
242 39783 rptr = sptr+1; /* Right pixel */
243 /* Foreach column in image (less far left and right pixels) ... */
244
2/2
✓ Branch 0 taken 9451777 times.
✓ Branch 1 taken 39783 times.
9491560 for(ix = 1; ix < iw-1; ix++){
245 /* Do we have a horizontal hole of length 1? */
246
4/4
✓ Branch 0 taken 1365623 times.
✓ Branch 1 taken 8086154 times.
✓ Branch 2 taken 43445 times.
✓ Branch 3 taken 1322178 times.
9451777 if((*lptr != *mptr) && (*lptr == *rptr)){
247 /* If so, then fill it. */
248 43445 *mptr = *lptr;
249 /* Bump passed right pixel because we know it will not */
250 /* be a hole. */
251 43445 lptr+=2;
252 43445 mptr+=2;
253 43445 rptr+=2;
254 /* We bump ix once here and then the FOR bumps it again. */
255 43445 ix++;
256 }
257 else{
258 /* Otherwise, bump to the next pixel to the right. */
259 9408332 lptr++;
260 9408332 mptr++;
261 9408332 rptr++;
262 }
263 }
264 /* Bump to start of next row. */
265 39783 sptr += iw;
266 }
267
268 /* 2. Now, fill 1-pixel wide holes in vertical runs ... */
269 144 iw2 = iw<<1;
270 /* Start processing column one row down from the top of the image. */
271 144 sptr = bdata + iw;
272 /* Foreach column in image ... */
273
2/2
✓ Branch 0 taken 35952 times.
✓ Branch 1 taken 144 times.
36096 for(ix = 0; ix < iw; ix++){
274 /* Initialize pointers to start of next column ... */
275 35952 tptr = sptr-iw; /* Top pixel */
276 35952 mptr = sptr; /* Middle pixel */
277 35952 bptr = sptr+iw; /* Bottom pixel */
278 /* Foreach row in image (less top and bottom row) ... */
279
2/2
✓ Branch 0 taken 9453817 times.
✓ Branch 1 taken 35952 times.
9489769 for(iy = 1; iy < ih-1; iy++){
280 /* Do we have a vertical hole of length 1? */
281
4/4
✓ Branch 0 taken 1679955 times.
✓ Branch 1 taken 7773862 times.
✓ Branch 2 taken 49067 times.
✓ Branch 3 taken 1630888 times.
9453817 if((*tptr != *mptr) && (*tptr == *bptr)){
282 /* If so, then fill it. */
283 49067 *mptr = *tptr;
284 /* Bump passed bottom pixel because we know it will not */
285 /* be a hole. */
286 49067 tptr+=iw2;
287 49067 mptr+=iw2;
288 49067 bptr+=iw2;
289 /* We bump iy once here and then the FOR bumps it again. */
290 49067 iy++;
291 }
292 else{
293 /* Otherwise, bump to the next pixel below. */
294 9404750 tptr+=iw;
295 9404750 mptr+=iw;
296 9404750 bptr+=iw;
297 }
298 }
299 /* Bump to start of next column. */
300 35952 sptr++;
301 }
302 144 }
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 795 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 795 int *x_list, *y_list, num;
330 795 int ret;
331 795 int i, trans, preval, nextval;
332
333 /* Compute points along line segment between the two points. */
334
1/2
✓ Branch 1 taken 795 times.
✗ Branch 2 not taken.
795 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 795 trans = 0;
339 /* Get the pixel value of first point along line segment. */
340 795 preval = *(bdata+(y1*iw)+x1);
341
342 /* Foreach remaining point along line segment ... */
343
2/2
✓ Branch 0 taken 3324 times.
✓ Branch 1 taken 742 times.
4066 for(i = 1; i < num; i++){
344 /* Get pixel value of next point along line segment. */
345 3324 nextval = *(bdata+(y_list[i]*iw)+x_list[i]);
346
347 /* If next pixel value different from previous pixel value ... */
348
2/2
✓ Branch 0 taken 1643 times.
✓ Branch 1 taken 1681 times.
3324 if(nextval != preval){
349 /* Then we have detected a transition, so bump counter. */
350 1643 trans++;
351 /* If number of transitions seen > than threshold (ex. 2) ... */
352
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 1590 times.
1643 if(trans > lfsparms->maxtrans){
353 /* Deallocate the line segment's coordinate lists. */
354 53 g_free(x_list);
355 53 g_free(y_list);
356 /* Return free path to be FALSE. */
357 53 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 742 g_free(x_list);
370 742 g_free(y_list);
371
372 /* Return free path to be TRUE. */
373 742 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 4634 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 4634 int i, x, y, px, py;
410 4634 double fx, fy;
411
412 /* Set previous point to starting point. */
413 4634 px = strt_x;
414 4634 py = strt_y;
415 /* Set floating point accumulators to starting point. */
416 4634 fx = (double)strt_x;
417 4634 fy = (double)strt_y;
418
419 /* Foreach step up to the specified maximum ... */
420
2/2
✓ Branch 0 taken 20363 times.
✓ Branch 1 taken 153 times.
20516 for(i = 0; i < maxsteps; i++){
421
422 /* Increment accumulators. */
423 20363 fx += delta_x;
424 20363 fy += delta_y;
425 /* Round to get next step. */
426
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 20348 times.
20363 x = sround(fx);
427
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 20325 times.
20363 y = sround(fy);
428
429 /* If we stepped outside the image boundaries ... */
430
2/2
✓ Branch 0 taken 20348 times.
✓ Branch 1 taken 15 times.
20363 if((x < 0) || (x >= iw) ||
431
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 20327 times.
20348 (y < 0) || (y >= ih)){
432 /* Return FALSE (we did not find what we were looking for). */
433 36 *ox = -1;
434 36 *oy = -1;
435 36 *oex = -1;
436 36 *oey = -1;
437 36 return(FALSE);
438 }
439
440 /* Otherwise, test to see if we found our pixel with value 'pix'. */
441
2/2
✓ Branch 0 taken 4445 times.
✓ Branch 1 taken 15882 times.
20327 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 4445 fix_edge_pixel_pair(&x, &y, &px, &py, bdata, iw, ih);
451
452 /* Return TRUE (we found what we were looking for). */
453 4445 *ox = x;
454 4445 *oy = y;
455 4445 *oex = px;
456 4445 *oey = py;
457 4445 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 15882 px = x;
463 15882 py = y;
464 }
465
466 /* Return FALSE (we did not find what we were looking for). */
467 153 *ox = -1;
468 153 *oy = -1;
469 153 *oex = -1;
470 153 *oey = -1;
471 153 return(FALSE);
472 }
473
474