| 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: BINAR.C | ||
| 49 | AUTHOR: Michael D. Garris | ||
| 50 | DATE: 03/16/1999 | ||
| 51 | UPDATED: 10/04/1999 Version 2 by MDG | ||
| 52 | UPDATED: 03/16/2005 by MDG | ||
| 53 | |||
| 54 | Contains routines responsible for binarizing a grayscale image based | ||
| 55 | on an arbitrarily-sized image and its precomputed direcitonal ridge | ||
| 56 | flow (IMAP) as part of the NIST Latent Fingerprint System (LFS). | ||
| 57 | |||
| 58 | *********************************************************************** | ||
| 59 | ROUTINES: | ||
| 60 | binarize() | ||
| 61 | binarize_V2() | ||
| 62 | binarize_image() | ||
| 63 | binarize_image_V2() | ||
| 64 | dirbinarize() | ||
| 65 | isobinarize() | ||
| 66 | |||
| 67 | ***********************************************************************/ | ||
| 68 | |||
| 69 | #include <stdio.h> | ||
| 70 | #include <lfs.h> | ||
| 71 | |||
| 72 | /************************************************************************* | ||
| 73 | ************************************************************************** | ||
| 74 | #cat: binarize - Takes a padded grayscale input image and its associated ridge | ||
| 75 | #cat: direction flow NMAP and produces a binarized version of the | ||
| 76 | #cat: image. It then fills horizontal and vertical "holes" in the | ||
| 77 | #cat: binary image results. | ||
| 78 | |||
| 79 | Input: | ||
| 80 | pdata - padded input grayscale image | ||
| 81 | pw - padded width (in pixels) of input image | ||
| 82 | ph - padded height (in pixels) of input image | ||
| 83 | nmap - 2-D vector of IMAP directions and other codes | ||
| 84 | mw - width (in blocks) of the NMAP | ||
| 85 | mh - height (in blocks) of the NMAP | ||
| 86 | dirbingrids - set of rotated grid offsets used for directional | ||
| 87 | binarization | ||
| 88 | lfsparms - parameters and thresholds for controlling LFS | ||
| 89 | Output: | ||
| 90 | optr - points to created (unpadded) binary image | ||
| 91 | ow - width of binary image | ||
| 92 | oh - height of binary image | ||
| 93 | Return Code: | ||
| 94 | Zero - successful completion | ||
| 95 | Negative - system error | ||
| 96 | **************************************************************************/ | ||
| 97 | |||
| 98 | /************************************************************************* | ||
| 99 | ************************************************************************** | ||
| 100 | #cat: binarize_V2 - Takes a padded grayscale input image and its associated | ||
| 101 | #cat: Direction Map and produces a binarized version of the | ||
| 102 | #cat: image. It then fills horizontal and vertical "holes" in | ||
| 103 | #cat: the binary image results. Note that the input image must | ||
| 104 | #cat: be padded sufficiently to contain in memory rotated | ||
| 105 | #cat: directional binarization grids applied to pixels along the | ||
| 106 | #cat: perimeter of the input image. | ||
| 107 | |||
| 108 | Input: | ||
| 109 | pdata - padded input grayscale image | ||
| 110 | pw - padded width (in pixels) of input image | ||
| 111 | ph - padded height (in pixels) of input image | ||
| 112 | direction_map - 2-D vector of discrete ridge flow directions | ||
| 113 | mw - width (in blocks) of the map | ||
| 114 | mh - height (in blocks) of the map | ||
| 115 | dirbingrids - set of rotated grid offsets used for directional | ||
| 116 | binarization | ||
| 117 | lfsparms - parameters and thresholds for controlling LFS | ||
| 118 | Output: | ||
| 119 | odata - points to created (unpadded) binary image | ||
| 120 | ow - width of binary image | ||
| 121 | oh - height of binary image | ||
| 122 | Return Code: | ||
| 123 | Zero - successful completion | ||
| 124 | Negative - system error | ||
| 125 | **************************************************************************/ | ||
| 126 | 48 | int binarize_V2(unsigned char **odata, int *ow, int *oh, | |
| 127 | unsigned char *pdata, const int pw, const int ph, | ||
| 128 | int *direction_map, const int mw, const int mh, | ||
| 129 | const ROTGRIDS *dirbingrids, const LFSPARMS *lfsparms) | ||
| 130 | { | ||
| 131 | 48 | unsigned char *bdata; | |
| 132 | 48 | int i, bw, bh, ret; /* return code */ | |
| 133 | |||
| 134 | /* 1. Binarize the padded input image using directional block info. */ | ||
| 135 |
1/2✓ Branch 0 (3→6) taken 48 times.
✗ Branch 1 (3→8) not taken.
|
48 | if((ret = binarize_image_V2(&bdata, &bw, &bh, pdata, pw, ph, |
| 136 | direction_map, mw, mh, | ||
| 137 | 48 | lfsparms->blocksize, dirbingrids))){ | |
| 138 | return(ret); | ||
| 139 | } | ||
| 140 | |||
| 141 | /* 2. Fill black and white holes in binary image. */ | ||
| 142 | /* LFS scans the binary image, filling holes, 3 times. */ | ||
| 143 |
2/2✓ Branch 0 (6→4) taken 144 times.
✓ Branch 1 (6→7) taken 48 times.
|
192 | for(i = 0; i < lfsparms->num_fill_holes; i++) |
| 144 | 144 | fill_holes(bdata, bw, bh); | |
| 145 | |||
| 146 | /* Return binarized input image. */ | ||
| 147 | 48 | *odata = bdata; | |
| 148 | 48 | *ow = bw; | |
| 149 | 48 | *oh = bh; | |
| 150 | 48 | return(0); | |
| 151 | } | ||
| 152 | |||
| 153 | /************************************************************************* | ||
| 154 | ************************************************************************** | ||
| 155 | #cat: binarize_image - Takes a grayscale input image and its associated | ||
| 156 | #cat: NMAP and generates a binarized version of the image. | ||
| 157 | |||
| 158 | Input: | ||
| 159 | pdata - padded input grayscale image | ||
| 160 | pw - padded width (in pixels) of input image | ||
| 161 | ph - padded height (in pixels) of input image | ||
| 162 | nmap - 2-D vector of IMAP directions and other codes | ||
| 163 | mw - width (in blocks) of the NMAP | ||
| 164 | mh - height (in blocks) of the NMAP | ||
| 165 | imap_blocksize - dimension (in pixels) of each NMAP block | ||
| 166 | dirbingrids - set of rotated grid offsets used for directional | ||
| 167 | binarization | ||
| 168 | isobin_grid_dim - dimension (in pixels) of grid used for isotropic | ||
| 169 | binarization | ||
| 170 | Output: | ||
| 171 | optr - points to binary image results | ||
| 172 | ow - points to binary image width | ||
| 173 | oh - points to binary image height | ||
| 174 | Return Code: | ||
| 175 | Zero - successful completion | ||
| 176 | Negative - system error | ||
| 177 | **************************************************************************/ | ||
| 178 | |||
| 179 | /************************************************************************* | ||
| 180 | ************************************************************************** | ||
| 181 | #cat: binarize_image_V2 - Takes a grayscale input image and its associated | ||
| 182 | #cat: Direction Map and generates a binarized version of the | ||
| 183 | #cat: image. Note that there is no "Isotropic" binarization | ||
| 184 | #cat: used in this version. | ||
| 185 | |||
| 186 | Input: | ||
| 187 | pdata - padded input grayscale image | ||
| 188 | pw - padded width (in pixels) of input image | ||
| 189 | ph - padded height (in pixels) of input image | ||
| 190 | direction_map - 2-D vector of discrete ridge flow directions | ||
| 191 | mw - width (in blocks) of the map | ||
| 192 | mh - height (in blocks) of the map | ||
| 193 | blocksize - dimension (in pixels) of each NMAP block | ||
| 194 | dirbingrids - set of rotated grid offsets used for directional | ||
| 195 | binarization | ||
| 196 | Output: | ||
| 197 | odata - points to binary image results | ||
| 198 | ow - points to binary image width | ||
| 199 | oh - points to binary image height | ||
| 200 | Return Code: | ||
| 201 | Zero - successful completion | ||
| 202 | Negative - system error | ||
| 203 | **************************************************************************/ | ||
| 204 | 48 | int binarize_image_V2(unsigned char **odata, int *ow, int *oh, | |
| 205 | unsigned char *pdata, const int pw, const int ph, | ||
| 206 | const int *direction_map, const int mw, const int mh, | ||
| 207 | const int blocksize, const ROTGRIDS *dirbingrids) | ||
| 208 | { | ||
| 209 | 48 | int ix, iy, bw, bh, bx, by, mapval; | |
| 210 | 48 | unsigned char *bdata, *bptr; | |
| 211 | 48 | unsigned char *pptr, *spptr; | |
| 212 | |||
| 213 | /* Compute dimensions of "unpadded" binary image results. */ | ||
| 214 | 48 | bw = pw - (dirbingrids->pad<<1); | |
| 215 | 48 | bh = ph - (dirbingrids->pad<<1); | |
| 216 | |||
| 217 | 48 | bdata = (unsigned char *)g_malloc(bw * bh * sizeof(unsigned char)); | |
| 218 | |||
| 219 | 48 | bptr = bdata; | |
| 220 | 48 | spptr = pdata + (dirbingrids->pad * pw) + dirbingrids->pad; | |
| 221 |
2/2✓ Branch 0 (11→12) taken 13261 times.
✓ Branch 1 (11→13) taken 48 times.
|
13309 | for(iy = 0; iy < bh; iy++){ |
| 222 | /* Set pixel pointer to start of next row in grid. */ | ||
| 223 | pptr = spptr; | ||
| 224 |
2/2✓ Branch 0 (9→4) taken 3191596 times.
✓ Branch 1 (9→10) taken 13261 times.
|
3204857 | for(ix = 0; ix < bw; ix++){ |
| 225 | |||
| 226 | /* Compute which block the current pixel is in. */ | ||
| 227 | 3191596 | bx = (int)(ix/blocksize); | |
| 228 | 3191596 | by = (int)(iy/blocksize); | |
| 229 | /* Get corresponding value in Direction Map. */ | ||
| 230 | 3191596 | mapval = *(direction_map + (by*mw) + bx); | |
| 231 | /* If current block has has INVALID direction ... */ | ||
| 232 |
2/2✓ Branch 0 (4→5) taken 697516 times.
✓ Branch 1 (4→6) taken 2494080 times.
|
3191596 | if(mapval == INVALID_DIR) |
| 233 | /* Set binary pixel to white (255). */ | ||
| 234 | 697516 | *bptr = WHITE_PIXEL; | |
| 235 | /* Otherwise, if block has a valid direction ... */ | ||
| 236 | else /*if(mapval >= 0)*/ | ||
| 237 | /* Use directional binarization based on block's direction. */ | ||
| 238 | 2494080 | *bptr = dirbinarize(pptr, mapval, dirbingrids); | |
| 239 | |||
| 240 | /* Bump input and output pixel pointers. */ | ||
| 241 | 3191596 | pptr++; | |
| 242 | 3191596 | bptr++; | |
| 243 | } | ||
| 244 | /* Bump pointer to the next row in padded input image. */ | ||
| 245 | 13261 | spptr += pw; | |
| 246 | } | ||
| 247 | |||
| 248 | 48 | *odata = bdata; | |
| 249 | 48 | *ow = bw; | |
| 250 | 48 | *oh = bh; | |
| 251 | 48 | return(0); | |
| 252 | } | ||
| 253 | |||
| 254 | /************************************************************************* | ||
| 255 | ************************************************************************** | ||
| 256 | #cat: dirbinarize - Determines the binary value of a grayscale pixel based | ||
| 257 | #cat: on a VALID IMAP ridge flow direction. | ||
| 258 | |||
| 259 | CAUTION: The image to which the input pixel points must be appropriately | ||
| 260 | padded to account for the radius of the rotated grid. Otherwise, | ||
| 261 | this routine may access "unkown" memory. | ||
| 262 | |||
| 263 | Input: | ||
| 264 | pptr - pointer to current grayscale pixel | ||
| 265 | idir - IMAP integer direction associated with the block the | ||
| 266 | current is in | ||
| 267 | dirbingrids - set of precomputed rotated grid offsets | ||
| 268 | Return Code: | ||
| 269 | BLACK_PIXEL - pixel intensity for BLACK | ||
| 270 | WHITE_PIXEL - pixel intensity of WHITE | ||
| 271 | **************************************************************************/ | ||
| 272 | 2494080 | int dirbinarize(const unsigned char *pptr, const int idir, | |
| 273 | const ROTGRIDS *dirbingrids) | ||
| 274 | { | ||
| 275 | 2494080 | int gx, gy, gi, cy; | |
| 276 | 2494080 | int rsum, gsum, csum = 0; | |
| 277 | 2494080 | int *grid; | |
| 278 | 2494080 | double dcy; | |
| 279 | |||
| 280 | /* Assign nickname pointer. */ | ||
| 281 | 2494080 | grid = dirbingrids->grids[idir]; | |
| 282 | /* Calculate center (0-oriented) row in grid. */ | ||
| 283 | 2494080 | dcy = (dirbingrids->grid_h-1)/(double)2.0; | |
| 284 | /* Need to truncate precision so that answers are consistent */ | ||
| 285 | /* on different computer architectures when rounding doubles. */ | ||
| 286 |
1/2✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 2494080 times.
|
2494080 | dcy = trunc_dbl_precision(dcy, TRUNC_SCALE); |
| 287 |
1/2✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 2494080 times.
|
2494080 | cy = sround(dcy); |
| 288 | /* Initialize grid's pixel offset index to zero. */ | ||
| 289 | 2494080 | gi = 0; | |
| 290 | /* Initialize grid's pixel accumulator to zero */ | ||
| 291 | 2494080 | gsum = 0; | |
| 292 | |||
| 293 | /* Foreach row in grid ... */ | ||
| 294 |
2/2✓ Branch 0 (14→10) taken 22446720 times.
✓ Branch 1 (14→15) taken 2494080 times.
|
24940800 | for(gy = 0; gy < dirbingrids->grid_h; gy++){ |
| 295 | /* Initialize row pixel sum to zero. */ | ||
| 296 | rsum = 0; | ||
| 297 | /* Foreach column in grid ... */ | ||
| 298 |
2/2✓ Branch 0 (10→9) taken 157127040 times.
✓ Branch 1 (10→11) taken 22446720 times.
|
179573760 | for(gx = 0; gx < dirbingrids->grid_w; gx++){ |
| 299 | /* Accumulate next pixel along rotated row in grid. */ | ||
| 300 | 157127040 | rsum += *(pptr+grid[gi]); | |
| 301 | /* Bump grid's pixel offset index. */ | ||
| 302 | 157127040 | gi++; | |
| 303 | } | ||
| 304 | /* Accumulate row sum into grid pixel sum. */ | ||
| 305 | 22446720 | gsum += rsum; | |
| 306 | /* If current row is center row, then save row sum separately. */ | ||
| 307 |
2/2✓ Branch 0 (11→12) taken 2494080 times.
✓ Branch 1 (11→13) taken 19952640 times.
|
22446720 | if(gy == cy) |
| 308 | 2494080 | csum = rsum; | |
| 309 | } | ||
| 310 | |||
| 311 | /* If the center row sum treated as an average is less than the */ | ||
| 312 | /* total pixel sum in the rotated grid ... */ | ||
| 313 |
2/2✓ Branch 0 (15→16) taken 1199374 times.
✓ Branch 1 (15→17) taken 1294706 times.
|
2494080 | if((csum * dirbingrids->grid_h) < gsum) |
| 314 | /* Set the binary pixel to BLACK. */ | ||
| 315 | return(BLACK_PIXEL); | ||
| 316 | else | ||
| 317 | /* Otherwise set the binary pixel to WHITE. */ | ||
| 318 | 1199374 | return(WHITE_PIXEL); | |
| 319 | } | ||
| 320 | |||
| 321 | /************************************************************************* | ||
| 322 | ************************************************************************** | ||
| 323 | #cat: isobinarize - Determines the binary value of a grayscale pixel based | ||
| 324 | #cat: on comparing the grayscale value with a surrounding | ||
| 325 | #cat: neighborhood grid of pixels. If the current pixel (treated | ||
| 326 | #cat: as an average) is less than the sum of the pixels in | ||
| 327 | #cat: the neighborhood, then the binary value is set to BLACK, | ||
| 328 | #cat: otherwise it is set to WHITE. This binarization technique | ||
| 329 | #cat: is used when there is no VALID IMAP direction for the | ||
| 330 | #cat: block in which the current pixel resides. | ||
| 331 | |||
| 332 | CAUTION: The image to which the input pixel points must be appropriately | ||
| 333 | padded to account for the radius of the neighborhood. Otherwise, | ||
| 334 | this routine may access "unkown" memory. | ||
| 335 | |||
| 336 | Input: | ||
| 337 | pptr - pointer to curent grayscale pixel | ||
| 338 | pw - padded width (in pixels) of the grayscale image | ||
| 339 | ph - padded height (in pixels) of the grayscale image | ||
| 340 | isobin_grid_dim - dimension (in pixels) of the neighborhood | ||
| 341 | Return Code: | ||
| 342 | BLACK_PIXEL - pixel intensity for BLACK | ||
| 343 | WHITE_PIXEL - pixel intensity of WHITE | ||
| 344 | **************************************************************************/ | ||
| 345 |