| 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: DFT.C | ||
| 49 | AUTHOR: Michael D. Garris | ||
| 50 | DATE: 03/16/1999 | ||
| 51 | UPDATED: 03/16/2005 by MDG | ||
| 52 | |||
| 53 | Contains routines responsible for conducting Discrete Fourier | ||
| 54 | Transforms (DFT) analysis on a block of image data as part of | ||
| 55 | the NIST Latent Fingerprint System (LFS). | ||
| 56 | |||
| 57 | *********************************************************************** | ||
| 58 | ROUTINES: | ||
| 59 | dft_dir_powers() | ||
| 60 | sum_rot_block_rows() | ||
| 61 | dft_power() | ||
| 62 | dft_power_stats() | ||
| 63 | get_max_norm() | ||
| 64 | sort_dft_waves() | ||
| 65 | ***********************************************************************/ | ||
| 66 | |||
| 67 | #include <stdio.h> | ||
| 68 | #include <lfs.h> | ||
| 69 | |||
| 70 | /************************************************************************* | ||
| 71 | ************************************************************************** | ||
| 72 | #cat: dft_dir_powers - Conducts the DFT analysis on a block of image data. | ||
| 73 | #cat: The image block is sampled across a range of orientations | ||
| 74 | #cat: (directions) and multiple wave forms of varying frequency are | ||
| 75 | #cat: applied at each orientation. At each orentation, pixels are | ||
| 76 | #cat: accumulated along each rotated pixel row, creating a vector | ||
| 77 | #cat: of pixel row sums. Each DFT wave form is then applied | ||
| 78 | #cat: individually to this vector of pixel row sums. A DFT power | ||
| 79 | #cat: value is computed for each wave form (frequency0 at each | ||
| 80 | #cat: orientaion within the image block. Therefore, the resulting DFT | ||
| 81 | #cat: power vectors are of dimension (N Waves X M Directions). | ||
| 82 | #cat: The power signatures derived form this process are used to | ||
| 83 | #cat: determine dominant direction flow within the image block. | ||
| 84 | |||
| 85 | Input: | ||
| 86 | pdata - the padded input image. It is important that the image | ||
| 87 | be properly padded, or else the sampling at various block | ||
| 88 | orientations may result in accessing unkown memory. | ||
| 89 | blkoffset - the pixel offset form the origin of the padded image to | ||
| 90 | the origin of the current block in the image | ||
| 91 | pw - the width (in pixels) of the padded input image | ||
| 92 | ph - the height (in pixels) of the padded input image | ||
| 93 | dftwaves - structure containing the DFT wave forms | ||
| 94 | dftgrids - structure containing the rotated pixel grid offsets | ||
| 95 | Output: | ||
| 96 | powers - DFT power computed from each wave form frequencies at each | ||
| 97 | orientation (direction) in the current image block | ||
| 98 | Return Code: | ||
| 99 | Zero - successful completion | ||
| 100 | Negative - system error | ||
| 101 | **************************************************************************/ | ||
| 102 | 46139 | int dft_dir_powers(double **powers, unsigned char *pdata, | |
| 103 | const int blkoffset, const int pw, const int ph, | ||
| 104 | const DFTWAVES *dftwaves, const ROTGRIDS *dftgrids) | ||
| 105 | { | ||
| 106 | 46139 | int w, dir; | |
| 107 | 46139 | int *rowsums; | |
| 108 | 46139 | unsigned char *blkptr; | |
| 109 | |||
| 110 | /* Allocate line sum vector, and initialize to zeros */ | ||
| 111 | /* This routine requires square block (grid), so ERROR otherwise. */ | ||
| 112 |
1/2✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→5) taken 46139 times.
|
46139 | if(dftgrids->grid_w != dftgrids->grid_h){ |
| 113 | ✗ | fprintf(stderr, "ERROR : dft_dir_powers : DFT grids must be square\n"); | |
| 114 | ✗ | return(-90); | |
| 115 | } | ||
| 116 | 46139 | rowsums = (int *)g_malloc(dftgrids->grid_w * sizeof(int)); | |
| 117 | 46139 | memset(rowsums, 0, dftgrids->grid_w * sizeof(int)); | |
| 118 | |||
| 119 | /* Foreach direction ... */ | ||
| 120 |
2/2✓ Branch 0 (13→7) taken 738224 times.
✓ Branch 1 (13→14) taken 46139 times.
|
784363 | for(dir = 0; dir < dftgrids->ngrids; dir++){ |
| 121 | /* Compute vector of line sums from rotated grid */ | ||
| 122 | 738224 | blkptr = pdata + blkoffset; | |
| 123 | 738224 | sum_rot_block_rows(rowsums, blkptr, | |
| 124 | 738224 | dftgrids->grids[dir], dftgrids->grid_w); | |
| 125 | |||
| 126 | /* Foreach DFT wave ... */ | ||
| 127 |
2/2✓ Branch 0 (11→9) taken 2952896 times.
✓ Branch 1 (11→12) taken 738224 times.
|
4429344 | for(w = 0; w < dftwaves->nwaves; w++){ |
| 128 | 2952896 | dft_power(&(powers[w][dir]), rowsums, | |
| 129 | 2952896 | dftwaves->waves[w], dftwaves->wavelen); | |
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | /* Deallocate working memory. */ | ||
| 134 | 46139 | g_free(rowsums); | |
| 135 | |||
| 136 | 46139 | return(0); | |
| 137 | } | ||
| 138 | |||
| 139 | /************************************************************************* | ||
| 140 | ************************************************************************** | ||
| 141 | #cat: sum_rot_block_rows - Computes a vector or pixel row sums by sampling | ||
| 142 | #cat: the current image block at a given orientation. The | ||
| 143 | #cat: sampling is conducted using a precomputed set of rotated | ||
| 144 | #cat: pixel offsets (called a grid) relative to the orgin of | ||
| 145 | #cat: the image block. | ||
| 146 | |||
| 147 | Input: | ||
| 148 | blkptr - the pixel address of the origin of the current image block | ||
| 149 | grid_offsets - the rotated pixel offsets for a block-sized grid | ||
| 150 | rotated according to a specific orientation | ||
| 151 | blocksize - the width and height of the image block and thus the size | ||
| 152 | of the rotated grid | ||
| 153 | Output: | ||
| 154 | rowsums - the resulting vector of pixel row sums | ||
| 155 | **************************************************************************/ | ||
| 156 | 738224 | void sum_rot_block_rows(int *rowsums, const unsigned char *blkptr, | |
| 157 | const int *grid_offsets, const int blocksize) | ||
| 158 | { | ||
| 159 | 738224 | int ix, iy, gi; | |
| 160 | |||
| 161 | /* Initialize rotation offset index. */ | ||
| 162 | 738224 | gi = 0; | |
| 163 | |||
| 164 | /* For each row in block ... */ | ||
| 165 |
2/2✓ Branch 0 (7→3) taken 17717376 times.
✓ Branch 1 (7→8) taken 738224 times.
|
18455600 | for(iy = 0; iy < blocksize; iy++){ |
| 166 | /* The sums are accumlated along the rotated rows of the grid, */ | ||
| 167 | /* so initialize row sum to 0. */ | ||
| 168 | 17717376 | rowsums[iy] = 0; | |
| 169 | /* Foreach column in block ... */ | ||
| 170 |
2/2✓ Branch 0 (5→4) taken 425217024 times.
✓ Branch 1 (5→6) taken 17717376 times.
|
442934400 | for(ix = 0; ix < blocksize; ix++){ |
| 171 | /* Accumulate pixel value at rotated grid position in image */ | ||
| 172 | 425217024 | rowsums[iy] += *(blkptr + grid_offsets[gi]); | |
| 173 | 425217024 | gi++; | |
| 174 | } | ||
| 175 | } | ||
| 176 | 738224 | } | |
| 177 | |||
| 178 | /************************************************************************* | ||
| 179 | ************************************************************************** | ||
| 180 | #cat: dft_power - Computes the DFT power by applying a specific wave form | ||
| 181 | #cat: frequency to a vector of pixel row sums computed from a | ||
| 182 | #cat: specific orientation of the block image | ||
| 183 | |||
| 184 | Input: | ||
| 185 | rowsums - accumulated rows of pixels from within a rotated grid | ||
| 186 | overlaying an input image block | ||
| 187 | wave - the wave form (cosine and sine components) at a specific | ||
| 188 | frequency | ||
| 189 | wavelen - the length of the wave form (must match the height of the | ||
| 190 | image block which is the length of the rowsum vector) | ||
| 191 | Output: | ||
| 192 | power - the computed DFT power for the given wave form at the | ||
| 193 | given orientation within the image block | ||
| 194 | **************************************************************************/ | ||
| 195 | 2952896 | void dft_power(double *power, const int *rowsums, | |
| 196 | const DFTWAVE *wave, const int wavelen) | ||
| 197 | { | ||
| 198 | 2952896 | int i; | |
| 199 | 2952896 | double cospart, sinpart; | |
| 200 | |||
| 201 | /* Initialize accumulators */ | ||
| 202 | 2952896 | cospart = 0.0; | |
| 203 | 2952896 | sinpart = 0.0; | |
| 204 | |||
| 205 | /* Accumulate cos and sin components of DFT. */ | ||
| 206 |
2/2✓ Branch 0 (4→3) taken 70869504 times.
✓ Branch 1 (4→5) taken 2952896 times.
|
73822400 | for(i = 0; i < wavelen; i++){ |
| 207 | /* Multiply each rotated row sum by its */ | ||
| 208 | /* corresponding cos or sin point in DFT wave. */ | ||
| 209 | 70869504 | cospart += (rowsums[i] * wave->cos[i]); | |
| 210 | 70869504 | sinpart += (rowsums[i] * wave->sin[i]); | |
| 211 | } | ||
| 212 | |||
| 213 | /* Power is the sum of the squared cos and sin components */ | ||
| 214 | 2952896 | *power = (cospart * cospart) + (sinpart * sinpart); | |
| 215 | 2952896 | } | |
| 216 | |||
| 217 | /************************************************************************* | ||
| 218 | ************************************************************************** | ||
| 219 | #cat: dft_power_stats - Derives statistics from a set of DFT power vectors. | ||
| 220 | #cat: Statistics are computed for all but the lowest frequency | ||
| 221 | #cat: wave form, including the Maximum power for each wave form, | ||
| 222 | #cat: the direction at which the maximum power occured, and a | ||
| 223 | #cat: normalized value for the maximum power. In addition, the | ||
| 224 | #cat: statistics are ranked in descending order based on normalized | ||
| 225 | #cat: squared maximum power. These statistics are fundamental | ||
| 226 | #cat: to selecting a dominant direction flow for the current | ||
| 227 | #cat: input image block. | ||
| 228 | |||
| 229 | Input: | ||
| 230 | powers - DFT power vectors (N Waves X M Directions) computed for | ||
| 231 | the current image block from which the values in the | ||
| 232 | statistics arrays are derived | ||
| 233 | fw - the beginning of the range of wave form indices from which | ||
| 234 | the statistcs are to derived | ||
| 235 | tw - the ending of the range of wave form indices from which | ||
| 236 | the statistcs are to derived (last index is tw-1) | ||
| 237 | ndirs - number of orientations (directions) at which the DFT | ||
| 238 | analysis was conducted | ||
| 239 | Output: | ||
| 240 | wis - list of ranked wave form indicies of the corresponding | ||
| 241 | statistics based on normalized squared maximum power. These | ||
| 242 | indices will be used as indirect addresses when processing | ||
| 243 | the power statistics in descending order of "dominance" | ||
| 244 | powmaxs - array holding the maximum DFT power for each wave form | ||
| 245 | (other than the lowest frequecy) | ||
| 246 | powmax_dirs - array to holding the direction corresponding to | ||
| 247 | each maximum power value in powmaxs | ||
| 248 | pownorms - array to holding the normalized maximum powers corresponding | ||
| 249 | to each value in powmaxs | ||
| 250 | Return Code: | ||
| 251 | Zero - successful completion | ||
| 252 | Negative - system error | ||
| 253 | **************************************************************************/ | ||
| 254 | 46139 | int dft_power_stats(int *wis, double *powmaxs, int *powmax_dirs, | |
| 255 | double *pownorms, double **powers, | ||
| 256 | const int fw, const int tw, const int ndirs) | ||
| 257 | { | ||
| 258 | 46139 | int w, i; | |
| 259 | 46139 | int ret; /* return code */ | |
| 260 | |||
| 261 |
2/2✓ Branch 0 (5→3) taken 138417 times.
✓ Branch 1 (5→6) taken 46139 times.
|
184556 | for(w = fw, i = 0; w < tw; w++, i++){ |
| 262 | 138417 | get_max_norm(&(powmaxs[i]), &(powmax_dirs[i]), | |
| 263 | 138417 | &(pownorms[i]), powers[w], ndirs); | |
| 264 | } | ||
| 265 | |||
| 266 | /* Get sorted order of applied DFT waves based on normalized power */ | ||
| 267 | 46139 | if((ret = sort_dft_waves(wis, powmaxs, pownorms, tw-fw))) | |
| 268 | return(ret); | ||
| 269 | |||
| 270 | return(0); | ||
| 271 | } | ||
| 272 | |||
| 273 | /************************************************************************* | ||
| 274 | ************************************************************************** | ||
| 275 | #cat: get_max_norm - Analyses a DFT power vector for a specific wave form | ||
| 276 | #cat: applied at different orientations (directions) to the | ||
| 277 | #cat: current image block. The routine retuns the maximum | ||
| 278 | #cat: power value in the vector, the direction at which the | ||
| 279 | #cat: maximum occurs, and a normalized power value. The | ||
| 280 | #cat: normalized power is computed as the maximum power divided | ||
| 281 | #cat: by the average power across all the directions. These | ||
| 282 | #cat: simple statistics are fundamental to the selection of | ||
| 283 | #cat: a dominant direction flow for the image block. | ||
| 284 | |||
| 285 | Input: | ||
| 286 | power_vector - the DFT power values derived form a specific wave form | ||
| 287 | applied at different directions | ||
| 288 | ndirs - the number of directions to which the wave form was applied | ||
| 289 | Output: | ||
| 290 | powmax - the maximum power value in the DFT power vector | ||
| 291 | powmax_dir - the direciton at which the maximum power value occured | ||
| 292 | pownorm - the normalized power corresponding to the maximum power | ||
| 293 | **************************************************************************/ | ||
| 294 | 138417 | void get_max_norm(double *powmax, int *powmax_dir, | |
| 295 | double *pownorm, const double *power_vector, const int ndirs) | ||
| 296 | { | ||
| 297 | 138417 | int dir; | |
| 298 | 138417 | double max_v, powsum; | |
| 299 | 138417 | int max_i; | |
| 300 | 138417 | double powmean; | |
| 301 | |||
| 302 | /* Find max power value and store corresponding direction */ | ||
| 303 | 138417 | max_v = power_vector[0]; | |
| 304 | 138417 | max_i = 0; | |
| 305 | |||
| 306 | /* Sum the total power in a block at a given direction */ | ||
| 307 | 138417 | powsum = power_vector[0]; | |
| 308 | |||
| 309 | /* For each direction ... */ | ||
| 310 |
2/2✓ Branch 0 (6→3) taken 2076255 times.
✓ Branch 1 (6→7) taken 138417 times.
|
2214672 | for(dir = 1; dir < ndirs; dir++){ |
| 311 | 2076255 | powsum += power_vector[dir]; | |
| 312 |
2/2✓ Branch 0 (3→4) taken 405763 times.
✓ Branch 1 (3→5) taken 1670492 times.
|
2076255 | if(power_vector[dir] > max_v){ |
| 313 | 405763 | max_v = power_vector[dir]; | |
| 314 | 405763 | max_i = dir; | |
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 318 | 138417 | *powmax = max_v; | |
| 319 | 138417 | *powmax_dir = max_i; | |
| 320 | |||
| 321 | /* Powmean is used as denominator for pownorm, so setting */ | ||
| 322 | /* a non-zero minimum avoids possible division by zero. */ | ||
| 323 | 138417 | powmean = max(powsum, MIN_POWER_SUM)/(double)ndirs; | |
| 324 | |||
| 325 | 138417 | *pownorm = *powmax / powmean; | |
| 326 | 138417 | } | |
| 327 | |||
| 328 | /************************************************************************* | ||
| 329 | ************************************************************************** | ||
| 330 | #cat: sort_dft_waves - Creates a ranked list of DFT wave form statistics | ||
| 331 | #cat: by sorting on the normalized squared maximum power. | ||
| 332 | |||
| 333 | Input: | ||
| 334 | powmaxs - maximum DFT power for each wave form used to derive | ||
| 335 | statistics | ||
| 336 | pownorms - normalized maximum power corresponding to values in powmaxs | ||
| 337 | nstats - number of wave forms used to derive statistics (N Wave - 1) | ||
| 338 | Output: | ||
| 339 | wis - sorted list of indices corresponding to the ranked set of | ||
| 340 | wave form statistics. These indices will be used as | ||
| 341 | indirect addresses when processing the power statistics | ||
| 342 | in descending order of "dominance" | ||
| 343 | Return Code: | ||
| 344 | Zero - successful completion | ||
| 345 | Negative - system error | ||
| 346 | **************************************************************************/ | ||
| 347 | 46139 | int sort_dft_waves(int *wis, const double *powmaxs, const double *pownorms, | |
| 348 | const int nstats) | ||
| 349 | { | ||
| 350 | 46139 | int i; | |
| 351 | 46139 | double *pownorms2; | |
| 352 | |||
| 353 | /* Allocate normalized power^2 array */ | ||
| 354 | 46139 | pownorms2 = (double *)g_malloc(nstats * sizeof(double)); | |
| 355 | |||
| 356 |
2/2✓ Branch 0 (5→4) taken 138417 times.
✓ Branch 1 (5→6) taken 46139 times.
|
230695 | for(i = 0; i < nstats; i++){ |
| 357 | /* Wis will hold the sorted statistic indices when all is done. */ | ||
| 358 | 138417 | wis[i] = i; | |
| 359 | /* This is normalized squared max power. */ | ||
| 360 | 138417 | pownorms2[i] = powmaxs[i] * pownorms[i]; | |
| 361 | } | ||
| 362 | |||
| 363 | /* Sort the statistic indices on the normalized squared power. */ | ||
| 364 | 46139 | bubble_sort_double_dec_2(pownorms2, wis, nstats); | |
| 365 | |||
| 366 | /* Deallocate the working memory. */ | ||
| 367 | 46139 | g_free(pownorms2); | |
| 368 | |||
| 369 | 46139 | return(0); | |
| 370 | } | ||
| 371 | |||
| 372 |