74bb899ce2
libfprint/nbis/mindtct/dft.c:212:30: warning: The left operand of '*' is a garbage value cospart += (rowsums[i] * wave->cos[i]); ~~~~~~~~~~ ^
379 lines
16 KiB
C
379 lines
16 KiB
C
/*******************************************************************************
|
|
|
|
License:
|
|
This software and/or related materials was developed at the National Institute
|
|
of Standards and Technology (NIST) by employees of the Federal Government
|
|
in the course of their official duties. Pursuant to title 17 Section 105
|
|
of the United States Code, this software is not subject to copyright
|
|
protection and is in the public domain.
|
|
|
|
This software and/or related materials have been determined to be not subject
|
|
to the EAR (see Part 734.3 of the EAR for exact details) because it is
|
|
a publicly available technology and software, and is freely distributed
|
|
to any interested party with no licensing requirements. Therefore, it is
|
|
permissible to distribute this software as a free download from the internet.
|
|
|
|
Disclaimer:
|
|
This software and/or related materials was developed to promote biometric
|
|
standards and biometric technology testing for the Federal Government
|
|
in accordance with the USA PATRIOT Act and the Enhanced Border Security
|
|
and Visa Entry Reform Act. Specific hardware and software products identified
|
|
in this software were used in order to perform the software development.
|
|
In no case does such identification imply recommendation or endorsement
|
|
by the National Institute of Standards and Technology, nor does it imply that
|
|
the products and equipment identified are necessarily the best available
|
|
for the purpose.
|
|
|
|
This software and/or related materials are provided "AS-IS" without warranty
|
|
of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY,
|
|
NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY
|
|
or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the
|
|
licensed product, however used. In no event shall NIST be liable for any
|
|
damages and/or costs, including but not limited to incidental or consequential
|
|
damages of any kind, including economic damage or injury to property and lost
|
|
profits, regardless of whether NIST shall be advised, have reason to know,
|
|
or in fact shall know of the possibility.
|
|
|
|
By using this software, you agree to bear all risk relating to quality,
|
|
use and performance of the software and/or related materials. You agree
|
|
to hold the Government harmless from any claim arising from your use
|
|
of the software.
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
/***********************************************************************
|
|
LIBRARY: LFS - NIST Latent Fingerprint System
|
|
|
|
FILE: DFT.C
|
|
AUTHOR: Michael D. Garris
|
|
DATE: 03/16/1999
|
|
UPDATED: 03/16/2005 by MDG
|
|
|
|
Contains routines responsible for conducting Discrete Fourier
|
|
Transforms (DFT) analysis on a block of image data as part of
|
|
the NIST Latent Fingerprint System (LFS).
|
|
|
|
***********************************************************************
|
|
ROUTINES:
|
|
dft_dir_powers()
|
|
sum_rot_block_rows()
|
|
dft_power()
|
|
dft_power_stats()
|
|
get_max_norm()
|
|
sort_dft_waves()
|
|
***********************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <lfs.h>
|
|
|
|
/*************************************************************************
|
|
**************************************************************************
|
|
#cat: dft_dir_powers - Conducts the DFT analysis on a block of image data.
|
|
#cat: The image block is sampled across a range of orientations
|
|
#cat: (directions) and multiple wave forms of varying frequency are
|
|
#cat: applied at each orientation. At each orentation, pixels are
|
|
#cat: accumulated along each rotated pixel row, creating a vector
|
|
#cat: of pixel row sums. Each DFT wave form is then applied
|
|
#cat: individually to this vector of pixel row sums. A DFT power
|
|
#cat: value is computed for each wave form (frequency0 at each
|
|
#cat: orientaion within the image block. Therefore, the resulting DFT
|
|
#cat: power vectors are of dimension (N Waves X M Directions).
|
|
#cat: The power signatures derived form this process are used to
|
|
#cat: determine dominant direction flow within the image block.
|
|
|
|
Input:
|
|
pdata - the padded input image. It is important that the image
|
|
be properly padded, or else the sampling at various block
|
|
orientations may result in accessing unkown memory.
|
|
blkoffset - the pixel offset form the origin of the padded image to
|
|
the origin of the current block in the image
|
|
pw - the width (in pixels) of the padded input image
|
|
ph - the height (in pixels) of the padded input image
|
|
dftwaves - structure containing the DFT wave forms
|
|
dftgrids - structure containing the rotated pixel grid offsets
|
|
Output:
|
|
powers - DFT power computed from each wave form frequencies at each
|
|
orientation (direction) in the current image block
|
|
Return Code:
|
|
Zero - successful completion
|
|
Negative - system error
|
|
**************************************************************************/
|
|
int dft_dir_powers(double **powers, unsigned char *pdata,
|
|
const int blkoffset, const int pw, const int ph,
|
|
const DFTWAVES *dftwaves, const ROTGRIDS *dftgrids)
|
|
{
|
|
int w, dir;
|
|
int *rowsums;
|
|
unsigned char *blkptr;
|
|
|
|
/* Allocate line sum vector, and initialize to zeros */
|
|
/* This routine requires square block (grid), so ERROR otherwise. */
|
|
if(dftgrids->grid_w != dftgrids->grid_h){
|
|
fprintf(stderr, "ERROR : dft_dir_powers : DFT grids must be square\n");
|
|
return(-90);
|
|
}
|
|
rowsums = (int *)malloc(dftgrids->grid_w * sizeof(int));
|
|
if(rowsums == (int *)NULL){
|
|
fprintf(stderr, "ERROR : dft_dir_powers : malloc : rowsums\n");
|
|
return(-91);
|
|
}
|
|
memset(rowsums, 0, dftgrids->grid_w * sizeof(int));
|
|
|
|
/* Foreach direction ... */
|
|
for(dir = 0; dir < dftgrids->ngrids; dir++){
|
|
/* Compute vector of line sums from rotated grid */
|
|
blkptr = pdata + blkoffset;
|
|
sum_rot_block_rows(rowsums, blkptr,
|
|
dftgrids->grids[dir], dftgrids->grid_w);
|
|
|
|
/* Foreach DFT wave ... */
|
|
for(w = 0; w < dftwaves->nwaves; w++){
|
|
dft_power(&(powers[w][dir]), rowsums,
|
|
dftwaves->waves[w], dftwaves->wavelen);
|
|
}
|
|
}
|
|
|
|
/* Deallocate working memory. */
|
|
free(rowsums);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*************************************************************************
|
|
**************************************************************************
|
|
#cat: sum_rot_block_rows - Computes a vector or pixel row sums by sampling
|
|
#cat: the current image block at a given orientation. The
|
|
#cat: sampling is conducted using a precomputed set of rotated
|
|
#cat: pixel offsets (called a grid) relative to the orgin of
|
|
#cat: the image block.
|
|
|
|
Input:
|
|
blkptr - the pixel address of the origin of the current image block
|
|
grid_offsets - the rotated pixel offsets for a block-sized grid
|
|
rotated according to a specific orientation
|
|
blocksize - the width and height of the image block and thus the size
|
|
of the rotated grid
|
|
Output:
|
|
rowsums - the resulting vector of pixel row sums
|
|
**************************************************************************/
|
|
void sum_rot_block_rows(int *rowsums, const unsigned char *blkptr,
|
|
const int *grid_offsets, const int blocksize)
|
|
{
|
|
int ix, iy, gi;
|
|
|
|
/* Initialize rotation offset index. */
|
|
gi = 0;
|
|
|
|
/* For each row in block ... */
|
|
for(iy = 0; iy < blocksize; iy++){
|
|
/* The sums are accumlated along the rotated rows of the grid, */
|
|
/* so initialize row sum to 0. */
|
|
rowsums[iy] = 0;
|
|
/* Foreach column in block ... */
|
|
for(ix = 0; ix < blocksize; ix++){
|
|
/* Accumulate pixel value at rotated grid position in image */
|
|
rowsums[iy] += *(blkptr + grid_offsets[gi]);
|
|
gi++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*************************************************************************
|
|
**************************************************************************
|
|
#cat: dft_power - Computes the DFT power by applying a specific wave form
|
|
#cat: frequency to a vector of pixel row sums computed from a
|
|
#cat: specific orientation of the block image
|
|
|
|
Input:
|
|
rowsums - accumulated rows of pixels from within a rotated grid
|
|
overlaying an input image block
|
|
wave - the wave form (cosine and sine components) at a specific
|
|
frequency
|
|
wavelen - the length of the wave form (must match the height of the
|
|
image block which is the length of the rowsum vector)
|
|
Output:
|
|
power - the computed DFT power for the given wave form at the
|
|
given orientation within the image block
|
|
**************************************************************************/
|
|
void dft_power(double *power, const int *rowsums,
|
|
const DFTWAVE *wave, const int wavelen)
|
|
{
|
|
int i;
|
|
double cospart, sinpart;
|
|
|
|
/* Initialize accumulators */
|
|
cospart = 0.0;
|
|
sinpart = 0.0;
|
|
|
|
/* Accumulate cos and sin components of DFT. */
|
|
for(i = 0; i < wavelen; i++){
|
|
/* Multiply each rotated row sum by its */
|
|
/* corresponding cos or sin point in DFT wave. */
|
|
cospart += (rowsums[i] * wave->cos[i]);
|
|
sinpart += (rowsums[i] * wave->sin[i]);
|
|
}
|
|
|
|
/* Power is the sum of the squared cos and sin components */
|
|
*power = (cospart * cospart) + (sinpart * sinpart);
|
|
}
|
|
|
|
/*************************************************************************
|
|
**************************************************************************
|
|
#cat: dft_power_stats - Derives statistics from a set of DFT power vectors.
|
|
#cat: Statistics are computed for all but the lowest frequency
|
|
#cat: wave form, including the Maximum power for each wave form,
|
|
#cat: the direction at which the maximum power occured, and a
|
|
#cat: normalized value for the maximum power. In addition, the
|
|
#cat: statistics are ranked in descending order based on normalized
|
|
#cat: squared maximum power. These statistics are fundamental
|
|
#cat: to selecting a dominant direction flow for the current
|
|
#cat: input image block.
|
|
|
|
Input:
|
|
powers - DFT power vectors (N Waves X M Directions) computed for
|
|
the current image block from which the values in the
|
|
statistics arrays are derived
|
|
fw - the beginning of the range of wave form indices from which
|
|
the statistcs are to derived
|
|
tw - the ending of the range of wave form indices from which
|
|
the statistcs are to derived (last index is tw-1)
|
|
ndirs - number of orientations (directions) at which the DFT
|
|
analysis was conducted
|
|
Output:
|
|
wis - list of ranked wave form indicies of the corresponding
|
|
statistics based on normalized squared maximum power. These
|
|
indices will be used as indirect addresses when processing
|
|
the power statistics in descending order of "dominance"
|
|
powmaxs - array holding the maximum DFT power for each wave form
|
|
(other than the lowest frequecy)
|
|
powmax_dirs - array to holding the direction corresponding to
|
|
each maximum power value in powmaxs
|
|
pownorms - array to holding the normalized maximum powers corresponding
|
|
to each value in powmaxs
|
|
Return Code:
|
|
Zero - successful completion
|
|
Negative - system error
|
|
**************************************************************************/
|
|
int dft_power_stats(int *wis, double *powmaxs, int *powmax_dirs,
|
|
double *pownorms, double **powers,
|
|
const int fw, const int tw, const int ndirs)
|
|
{
|
|
int w, i;
|
|
int ret; /* return code */
|
|
|
|
for(w = fw, i = 0; w < tw; w++, i++){
|
|
get_max_norm(&(powmaxs[i]), &(powmax_dirs[i]),
|
|
&(pownorms[i]), powers[w], ndirs);
|
|
}
|
|
|
|
/* Get sorted order of applied DFT waves based on normalized power */
|
|
if((ret = sort_dft_waves(wis, powmaxs, pownorms, tw-fw)))
|
|
return(ret);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*************************************************************************
|
|
**************************************************************************
|
|
#cat: get_max_norm - Analyses a DFT power vector for a specific wave form
|
|
#cat: applied at different orientations (directions) to the
|
|
#cat: current image block. The routine retuns the maximum
|
|
#cat: power value in the vector, the direction at which the
|
|
#cat: maximum occurs, and a normalized power value. The
|
|
#cat: normalized power is computed as the maximum power divided
|
|
#cat: by the average power across all the directions. These
|
|
#cat: simple statistics are fundamental to the selection of
|
|
#cat: a dominant direction flow for the image block.
|
|
|
|
Input:
|
|
power_vector - the DFT power values derived form a specific wave form
|
|
applied at different directions
|
|
ndirs - the number of directions to which the wave form was applied
|
|
Output:
|
|
powmax - the maximum power value in the DFT power vector
|
|
powmax_dir - the direciton at which the maximum power value occured
|
|
pownorm - the normalized power corresponding to the maximum power
|
|
**************************************************************************/
|
|
void get_max_norm(double *powmax, int *powmax_dir,
|
|
double *pownorm, const double *power_vector, const int ndirs)
|
|
{
|
|
int dir;
|
|
double max_v, powsum;
|
|
int max_i;
|
|
double powmean;
|
|
|
|
/* Find max power value and store corresponding direction */
|
|
max_v = power_vector[0];
|
|
max_i = 0;
|
|
|
|
/* Sum the total power in a block at a given direction */
|
|
powsum = power_vector[0];
|
|
|
|
/* For each direction ... */
|
|
for(dir = 1; dir < ndirs; dir++){
|
|
powsum += power_vector[dir];
|
|
if(power_vector[dir] > max_v){
|
|
max_v = power_vector[dir];
|
|
max_i = dir;
|
|
}
|
|
}
|
|
|
|
*powmax = max_v;
|
|
*powmax_dir = max_i;
|
|
|
|
/* Powmean is used as denominator for pownorm, so setting */
|
|
/* a non-zero minimum avoids possible division by zero. */
|
|
powmean = max(powsum, MIN_POWER_SUM)/(double)ndirs;
|
|
|
|
*pownorm = *powmax / powmean;
|
|
}
|
|
|
|
/*************************************************************************
|
|
**************************************************************************
|
|
#cat: sort_dft_waves - Creates a ranked list of DFT wave form statistics
|
|
#cat: by sorting on the normalized squared maximum power.
|
|
|
|
Input:
|
|
powmaxs - maximum DFT power for each wave form used to derive
|
|
statistics
|
|
pownorms - normalized maximum power corresponding to values in powmaxs
|
|
nstats - number of wave forms used to derive statistics (N Wave - 1)
|
|
Output:
|
|
wis - sorted list of indices corresponding to the ranked set of
|
|
wave form statistics. These indices will be used as
|
|
indirect addresses when processing the power statistics
|
|
in descending order of "dominance"
|
|
Return Code:
|
|
Zero - successful completion
|
|
Negative - system error
|
|
**************************************************************************/
|
|
int sort_dft_waves(int *wis, const double *powmaxs, const double *pownorms,
|
|
const int nstats)
|
|
{
|
|
int i;
|
|
double *pownorms2;
|
|
|
|
/* Allocate normalized power^2 array */
|
|
pownorms2 = (double *)malloc(nstats * sizeof(double));
|
|
if(pownorms2 == (double *)NULL){
|
|
fprintf(stderr, "ERROR : sort_dft_waves : malloc : pownorms2\n");
|
|
return(-100);
|
|
}
|
|
|
|
for(i = 0; i < nstats; i++){
|
|
/* Wis will hold the sorted statistic indices when all is done. */
|
|
wis[i] = i;
|
|
/* This is normalized squared max power. */
|
|
pownorms2[i] = powmaxs[i] * pownorms[i];
|
|
}
|
|
|
|
/* Sort the statistic indices on the normalized squared power. */
|
|
bubble_sort_double_dec_2(pownorms2, wis, nstats);
|
|
|
|
/* Deallocate the working memory. */
|
|
free(pownorms2);
|
|
|
|
return(0);
|
|
}
|
|
|