NBIS cleanup

Part 1 of many. Remove some unused/pointless code, and made some code
static.
This commit is contained in:
Daniel Drake 2007-10-28 15:45:28 +00:00
parent 6b8d17ef26
commit 4e5cfdf92a
15 changed files with 405 additions and 2442 deletions

1
.gitignore vendored
View file

@ -20,3 +20,4 @@ depcomp
install-sh install-sh
.deps .deps
.libs .libs
compile

View file

@ -33,10 +33,8 @@ NBIS_SRC = \
nbis/mindtct/matchpat.c \ nbis/mindtct/matchpat.c \
nbis/mindtct/minutia.c \ nbis/mindtct/minutia.c \
nbis/mindtct/morph.c \ nbis/mindtct/morph.c \
nbis/mindtct/mytime.c \
nbis/mindtct/quality.c \ nbis/mindtct/quality.c \
nbis/mindtct/remove.c \ nbis/mindtct/remove.c \
nbis/mindtct/results.c \
nbis/mindtct/ridges.c \ nbis/mindtct/ridges.c \
nbis/mindtct/shape.c \ nbis/mindtct/shape.c \
nbis/mindtct/sort.c \ nbis/mindtct/sort.c \

View file

@ -701,24 +701,15 @@ typedef struct lfsparms{
/*************************************************************************/ /*************************************************************************/
/* binar.c */ /* binar.c */
extern int binarize(unsigned char **, int *, int *,
unsigned char *, const int, const int,
int *, const int, const int,
const ROTGRIDS *, const LFSPARMS *);
extern int binarize_V2(unsigned char **, int *, int *, extern int binarize_V2(unsigned char **, int *, int *,
unsigned char *, const int, const int, unsigned char *, const int, const int,
int *, const int, const int, int *, const int, const int,
const ROTGRIDS *, const LFSPARMS *); const ROTGRIDS *, const LFSPARMS *);
extern int binarize_image(unsigned char **, int *, int *,
unsigned char *, const int, const int,
const int *, const int, const int, const int,
const ROTGRIDS *, const int);
extern int binarize_image_V2(unsigned char **, int *, int *, extern int binarize_image_V2(unsigned char **, int *, int *,
unsigned char *, const int, const int, unsigned char *, const int, const int,
const int *, const int, const int, const int *, const int, const int,
const int, const ROTGRIDS *); const int, const ROTGRIDS *);
extern int dirbinarize(const unsigned char *, const int, const ROTGRIDS *); extern int dirbinarize(const unsigned char *, const int, const ROTGRIDS *);
extern int isobinarize(unsigned char *, const int, const int, const int);
/* block.c */ /* block.c */
extern int block_offsets(int **, int *, int *, const int, const int, extern int block_offsets(int **, int *, int *, const int, const int,
@ -763,12 +754,6 @@ extern void fix_edge_pixel_pair(int *, int *, int *, int *,
unsigned char *, const int, const int); unsigned char *, const int, const int);
/* detect.c */ /* detect.c */
extern int lfs_detect_minutiae( MINUTIAE **,
int **, int **, int *, int *,
unsigned char **, int *, int *,
unsigned char *, const int, const int,
const LFSPARMS *);
extern int lfs_detect_minutiae_V2(MINUTIAE **, extern int lfs_detect_minutiae_V2(MINUTIAE **,
int **, int **, int **, int **, int *, int *, int **, int **, int **, int **, int *, int *,
unsigned char **, int *, int *, unsigned char **, int *, int *,
@ -779,13 +764,8 @@ extern int lfs_detect_minutiae_V2(MINUTIAE **,
extern int dft_dir_powers(double **, unsigned char *, const int, extern int dft_dir_powers(double **, unsigned char *, const int,
const int, const int, const DFTWAVES *, const int, const int, const DFTWAVES *,
const ROTGRIDS *); const ROTGRIDS *);
extern void sum_rot_block_rows(int *, const unsigned char *, const int *,
const int);
extern void dft_power(double *, const int *, const DFTWAVE *, const int);
extern int dft_power_stats(int *, double *, int *, double *, double **, extern int dft_power_stats(int *, double *, int *, double *, double **,
const int, const int, const int); const int, const int, const int);
extern void get_max_norm(double *, int *, double *, const double *, const int);
extern int sort_dft_waves(int *, const double *, const double *, const int);
/* free.c */ /* free.c */
extern void free_dir2rad(DIR2RAD *); extern void free_dir2rad(DIR2RAD *);
@ -818,7 +798,6 @@ extern int search_in_direction(int *, int *, int *, int *, const int,
/* init.c */ /* init.c */
extern int init_dir2rad(DIR2RAD **, const int); extern int init_dir2rad(DIR2RAD **, const int);
extern int init_dftwaves(DFTWAVES **, const double *, const int, const int); extern int init_dftwaves(DFTWAVES **, const double *, const int, const int);
extern int get_max_padding(const int, const int, const int, const int);
extern int get_max_padding_V2(const int, const int, const int, const int); extern int get_max_padding_V2(const int, const int, const int, const int);
extern int init_rotgrids(ROTGRIDS **, const int, const int, const int, extern int init_rotgrids(ROTGRIDS **, const int, const int, const int,
const double, const int, const int, const int, const int); const double, const int, const int, const int, const int);
@ -833,8 +812,6 @@ extern int is_qmap_empty(int *, const int, const int);
/* line.c */ /* line.c */
extern int line_points(int **, int **, int *, extern int line_points(int **, int **, int *,
const int, const int, const int, const int); const int, const int, const int, const int);
extern int bresenham_line_points(int **, int **, int *,
const int, const int, const int, const int);
/* link.c */ /* link.c */
extern int link_minutiae(MINUTIAE *, unsigned char *, const int, const int, extern int link_minutiae(MINUTIAE *, unsigned char *, const int, const int,
@ -872,16 +849,8 @@ extern int process_loop_V2(MINUTIAE *, const int *, const int *,
const int *, const int *, const int, const int *, const int *, const int,
unsigned char *, const int, const int, unsigned char *, const int, const int,
int *, const LFSPARMS *); int *, const LFSPARMS *);
extern void get_loop_aspect(int *, int *, double *, int *, int *, double *,
const int *, const int *, const int);
extern int fill_loop(const int *, const int *, const int, extern int fill_loop(const int *, const int *, const int,
unsigned char *, const int, const int); unsigned char *, const int, const int);
extern void fill_partial_row(const int, const int, const int, const int,
unsigned char *, const int, const int);
extern void flood_loop(const int *, const int *, const int,
unsigned char *, const int, const int);
extern void flood_fill4(const int, const int, const int,
unsigned char *, const int, const int);
/* maps.c */ /* maps.c */
extern int gen_image_maps(int **, int **, int **, int **, int *, int *, extern int gen_image_maps(int **, int **, int **, int **, int *, int *,
@ -901,10 +870,6 @@ extern void smooth_direction_map(int *, int *, const int, const int,
const DIR2RAD *, const LFSPARMS *); const DIR2RAD *, const LFSPARMS *);
extern int gen_high_curve_map(int **, int *, const int, const int, extern int gen_high_curve_map(int **, int *, const int, const int,
const LFSPARMS *); const LFSPARMS *);
extern int gen_imap(int **, int *, int *,
unsigned char *, const int, const int,
const DIR2RAD *, const DFTWAVES *, const ROTGRIDS *,
const LFSPARMS *);
extern int gen_initial_imap(int **, int *, const int, const int, extern int gen_initial_imap(int **, int *, const int, const int,
unsigned char *, const int, const int, unsigned char *, const int, const int,
const DFTWAVES *, const ROTGRIDS *, const LFSPARMS *); const DFTWAVES *, const ROTGRIDS *, const LFSPARMS *);
@ -935,7 +900,6 @@ extern void average_8nbr_dir(int *, double *, int *, int *, const int,
extern int num_valid_8nbrs(int *, const int, const int, const int, const int); extern int num_valid_8nbrs(int *, const int, const int, const int, const int);
extern void smooth_imap(int *, const int, const int, const DIR2RAD *, extern void smooth_imap(int *, const int, const int, const DIR2RAD *,
const LFSPARMS *); const LFSPARMS *);
extern int gen_nmap(int **, int *, const int, const int, const LFSPARMS *);
extern int vorticity(int *, const int, const int, const int, const int, extern int vorticity(int *, const int, const int, const int, const int,
const int); const int);
extern void accum_nbr_vorticity(int *, const int, const int, const int); extern void accum_nbr_vorticity(int *, const int, const int, const int);
@ -954,9 +918,6 @@ extern void skip_repeated_vertical_pair(int *, const int,
/* minutia.c */ /* minutia.c */
extern int alloc_minutiae(MINUTIAE **, const int); extern int alloc_minutiae(MINUTIAE **, const int);
extern int realloc_minutiae(MINUTIAE *, const int); extern int realloc_minutiae(MINUTIAE *, const int);
extern int detect_minutiae(MINUTIAE *, unsigned char *, const int, const int,
const int *, const int *, const int, const int,
const LFSPARMS *);
extern int detect_minutiae_V2(MINUTIAE *, extern int detect_minutiae_V2(MINUTIAE *,
unsigned char *, const int, const int, unsigned char *, const int, const int,
int *, int *, int *, const int, const int, int *, int *, int *, const int, const int,
@ -1083,58 +1044,6 @@ extern int remove_false_minutia_V2(MINUTIAE *,
unsigned char *, const int, const int, unsigned char *, const int, const int,
int *, int *, int *, const int, const int, int *, int *, int *, const int, const int,
const LFSPARMS *); const LFSPARMS *);
extern int remove_holes(MINUTIAE *, unsigned char *, const int, const int,
const LFSPARMS *);
extern int remove_hooks(MINUTIAE *,
unsigned char *, const int, const int, const LFSPARMS *);
extern int remove_hooks_islands_lakes_overlaps(MINUTIAE *, unsigned char *,
const int, const int, const LFSPARMS *);
extern int remove_islands_and_lakes(MINUTIAE *,
unsigned char *, const int, const int, const LFSPARMS *);
extern int remove_malformations(MINUTIAE *,
unsigned char *, const int, const int,
int *, const int, const int, const LFSPARMS *);
extern int remove_near_invblock(MINUTIAE *, int *, const int, const int,
const LFSPARMS *);
extern int remove_near_invblock_V2(MINUTIAE *, int *,
const int, const int, const LFSPARMS *);
extern int remove_pointing_invblock(MINUTIAE *, int *, const int, const int,
const LFSPARMS *);
extern int remove_pointing_invblock_V2(MINUTIAE *,
int *, const int, const int, const LFSPARMS *);
extern int remove_overlaps(MINUTIAE *,
unsigned char *, const int, const int, const LFSPARMS *);
extern int remove_pores(MINUTIAE *,
unsigned char *, const int, const int,
int *, const int, const int, const LFSPARMS *);
extern int remove_pores_V2(MINUTIAE *,
unsigned char *, const int, const int,
int *, int *, int *, const int, const int,
const LFSPARMS *);
extern int remove_or_adjust_side_minutiae(MINUTIAE *, unsigned char *,
const int, const int, const LFSPARMS *);
extern int remove_or_adjust_side_minutiae_V2(MINUTIAE *,
unsigned char *, const int, const int,
int *, const int, const int, const LFSPARMS *);
/* results.c */
extern int write_text_results(char *, const int, const int, const int,
const MINUTIAE *, int *, int *, int *, int *, int *,
const int, const int);
extern int write_minutiae_XYTQ(char *ofile, const int,
const MINUTIAE *, const int, const int);
extern void dump_map(FILE *, int *, const int, const int);
extern int drawimap(int *, const int, const int, unsigned char *,
const int, const int, const ROTGRIDS *, const int);
extern void drawimap2(int *, const int *, const int, const int,
unsigned char *, const int, const int,
const double, const int, const int);
extern void drawblocks(const int *, const int, const int,
unsigned char *, const int, const int, const int );
extern int drawrotgrid(const ROTGRIDS *, const int, unsigned char *,
const int, const int, const int, const int);
extern void dump_link_table(FILE *, const int *, const int *, const int *,
const int, const int, const int, const MINUTIAE *);
/* ridges.c */ /* ridges.c */
extern int count_minutiae_ridges(MINUTIAE *, extern int count_minutiae_ridges(MINUTIAE *,
@ -1159,11 +1068,8 @@ extern int validate_ridge_crossing(const int, const int,
unsigned char *, const int, const int, const int); unsigned char *, const int, const int, const int);
/* shape.c */ /* shape.c */
extern int alloc_shape(SHAPE **, const int, const int, const int, const int);
extern void free_shape(SHAPE *); extern void free_shape(SHAPE *);
extern void dump_shape(FILE *, const SHAPE *);
extern int shape_from_contour(SHAPE **, const int *, const int *, const int); extern int shape_from_contour(SHAPE **, const int *, const int *, const int);
extern void sort_row_on_x(ROW *);
/* sort.c */ /* sort.c */
extern int sort_indices_int_inc(int **, int *, const int); extern int sort_indices_int_inc(int **, int *, const int);

View file

@ -1,80 +0,0 @@
/*******************************************************************************
License:
This software 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. NIST assumes no responsibility whatsoever for
its use by other parties, and makes no guarantees, expressed or implied,
about its quality, reliability, or any other characteristic.
Disclaimer:
This software 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.
*******************************************************************************/
#ifndef _MYTIME_H
#define _MYTIME_H
/* this file needed to support timer and ticks */
/* UPDATED: 03/16/2005 by MDG */
#ifdef TIMER
#include <sys/types.h>
#include <sys/times.h>
#endif
#ifdef TIMER
#define set_timer(_timer_); \
{ \
_timer_ = (unsigned long)ticks();
#else
#define set_timer(_timer_);
#endif
#ifdef TIMER
#define time_accum(_timer_, _var_); \
_var_ += ((unsigned long)ticks() - _timer_)/(float)ticksPerSec(); \
}
#else
#define time_accum(_timer_, _var_);
#endif
#ifdef TIMER
#define print_time(_fp_, _fmt_, _var_); \
fprintf(_fp_, _fmt_, _var_);
#else
#define print_time(_fp_, _fmt_, _var_);
#endif
extern unsigned long ticks(void);
extern int ticksPerSec(void);
extern unsigned long total_timer;
extern float total_time;
extern unsigned long imap_timer;
extern float imap_time;
extern unsigned long bin_timer;
extern float bin_time;
extern unsigned long minutia_timer;
extern float minutia_time;
extern unsigned long rm_minutia_timer;
extern float rm_minutia_time;
extern unsigned long ridge_count_timer;
extern float ridge_count_time;
#endif

View file

@ -36,12 +36,9 @@ identified are necessarily the best available for the purpose.
*********************************************************************** ***********************************************************************
ROUTINES: ROUTINES:
binarize()
binarize_V2() binarize_V2()
binarize_image()
binarize_image_V2() binarize_image_V2()
dirbinarize() dirbinarize()
isobinarize()
***********************************************************************/ ***********************************************************************/
@ -49,58 +46,6 @@ identified are necessarily the best available for the purpose.
#include <stdlib.h> #include <stdlib.h>
#include <lfs.h> #include <lfs.h>
/*************************************************************************
**************************************************************************
#cat: binarize - Takes a padded grayscale input image and its associated ridge
#cat: direction flow NMAP and produces a binarized version of the
#cat: image. It then fills horizontal and vertical "holes" in the
#cat: binary image results.
Input:
pdata - padded input grayscale image
pw - padded width (in pixels) of input image
ph - padded height (in pixels) of input image
nmap - 2-D vector of IMAP directions and other codes
mw - width (in blocks) of the NMAP
mh - height (in blocks) of the NMAP
dirbingrids - set of rotated grid offsets used for directional
binarization
lfsparms - parameters and thresholds for controlling LFS
Output:
optr - points to created (unpadded) binary image
ow - width of binary image
oh - height of binary image
Return Code:
Zero - successful completion
Negative - system error
**************************************************************************/
int binarize(unsigned char **optr, int *ow, int *oh,
unsigned char *pdata, const int pw, const int ph,
int *nmap, const int mw, const int mh,
const ROTGRIDS *dirbingrids, const LFSPARMS *lfsparms)
{
unsigned char *bdata;
int i, bw, bh, ret; /* return code */
/* 1. Binarize the padded input image using NMAP information. */
if((ret = binarize_image(&bdata, &bw, &bh, pdata, pw, ph,
nmap, mw, mh, lfsparms->blocksize,
dirbingrids, lfsparms->isobin_grid_dim))){
return(ret);
}
/* 2. Fill black and white holes in binary image. */
/* LFS scans the binary image, filling holes, 3 times. */
for(i = 0; i < lfsparms->num_fill_holes; i++)
fill_holes(bdata, bw, bh);
/* Return binarized input image. */
*optr = bdata;
*ow = bw;
*oh = bh;
return(0);
}
/************************************************************************* /*************************************************************************
************************************************************************** **************************************************************************
#cat: binarize_V2 - Takes a padded grayscale input image and its associated #cat: binarize_V2 - Takes a padded grayscale input image and its associated
@ -156,89 +101,6 @@ int binarize_V2(unsigned char **odata, int *ow, int *oh,
return(0); return(0);
} }
/*************************************************************************
**************************************************************************
#cat: binarize_image - Takes a grayscale input image and its associated
#cat: NMAP and generates a binarized version of the image.
Input:
pdata - padded input grayscale image
pw - padded width (in pixels) of input image
ph - padded height (in pixels) of input image
nmap - 2-D vector of IMAP directions and other codes
mw - width (in blocks) of the NMAP
mh - height (in blocks) of the NMAP
imap_blocksize - dimension (in pixels) of each NMAP block
dirbingrids - set of rotated grid offsets used for directional
binarization
isobin_grid_dim - dimension (in pixels) of grid used for isotropic
binarization
Output:
optr - points to binary image results
ow - points to binary image width
oh - points to binary image height
Return Code:
Zero - successful completion
Negative - system error
**************************************************************************/
int binarize_image(unsigned char **optr, int *ow, int *oh,
unsigned char *pdata, const int pw, const int ph,
const int *nmap, const int mw, const int mh,
const int imap_blocksize, const ROTGRIDS *dirbingrids,
const int isobin_grid_dim)
{
int ix, iy, bw, bh, bx, by, nmapval;
unsigned char *bdata, *bptr;
unsigned char *pptr, *spptr;
/* Compute dimensions of "unpadded" binary image results. */
bw = pw - (dirbingrids->pad<<1);
bh = ph - (dirbingrids->pad<<1);
bdata = (unsigned char *)malloc(bw*bh*sizeof(unsigned char));
if(bdata == (unsigned char *)NULL){
fprintf(stderr, "ERROR : binarize_image : malloc : bdata\n");
return(-110);
}
bptr = bdata;
spptr = pdata + (dirbingrids->pad * pw) + dirbingrids->pad;
for(iy = 0; iy < bh; iy++){
/* Set pixel pointer to start of next row in grid. */
pptr = spptr;
for(ix = 0; ix < bw; ix++){
/* Compute which block the current pixel is in. */
bx = (int)(ix/imap_blocksize);
by = (int)(iy/imap_blocksize);
/* Get corresponding value in NMAP */
nmapval = *(nmap + (by*mw) + bx);
/* If current block has no neighboring blocks with */
/* VALID directions ... */
if(nmapval == NO_VALID_NBRS)
/* Set binary pixel to white (255). */
*bptr = WHITE_PIXEL;
/* Otherwise, if block's NMAP has a valid direction ... */
else if(nmapval >= 0)
/* Use directional binarization based on NMAP direction. */
*bptr = dirbinarize(pptr, nmapval, dirbingrids);
else
/* Otherwise, the block's NMAP is either INVALID or */
/* HIGH-CURVATURE, so use isotropic binarization. */
*bptr = isobinarize(pptr, pw, ph, isobin_grid_dim);
/* Bump input and output pixel pointers. */
pptr++;
bptr++;
}
/* Bump pointer to the next row in padded input image. */
spptr += pw;
}
*optr = bdata;
*ow = bw;
*oh = bh;
return(0);
}
/************************************************************************* /*************************************************************************
************************************************************************** **************************************************************************
#cat: binarize_image_V2 - Takes a grayscale input image and its associated #cat: binarize_image_V2 - Takes a grayscale input image and its associated
@ -385,71 +247,3 @@ int dirbinarize(const unsigned char *pptr, const int idir,
return(WHITE_PIXEL); return(WHITE_PIXEL);
} }
/*************************************************************************
**************************************************************************
#cat: isobinarize - Determines the binary value of a grayscale pixel based
#cat: on comparing the grayscale value with a surrounding
#cat: neighborhood grid of pixels. If the current pixel (treated
#cat: as an average) is less than the sum of the pixels in
#cat: the neighborhood, then the binary value is set to BLACK,
#cat: otherwise it is set to WHITE. This binarization technique
#cat: is used when there is no VALID IMAP direction for the
#cat: block in which the current pixel resides.
CAUTION: The image to which the input pixel points must be appropriately
padded to account for the radius of the neighborhood. Otherwise,
this routine may access "unkown" memory.
Input:
pptr - pointer to curent grayscale pixel
pw - padded width (in pixels) of the grayscale image
ph - padded height (in pixels) of the grayscale image
isobin_grid_dim - dimension (in pixels) of the neighborhood
Return Code:
BLACK_PIXEL - pixel intensity for BLACK
WHITE_PIXEL - pixel intensity of WHITE
**************************************************************************/
int isobinarize(unsigned char *pptr, const int pw, const int ph,
const int isobin_grid_dim)
{
unsigned char *sptr, *cptr;
int px, py;
int radius;
int bsum;
double drad;
/* Initialize grid pixel sum to zero. */
bsum = 0;
/* Compute radius from current pixel based on isobin_grid_dim. */
drad = (isobin_grid_dim - 1)/(double)2.0;
/* Need to truncate precision so that answers are consistent */
/* on different computer architectures when rounding doubles. */
drad = trunc_dbl_precision(drad, TRUNC_SCALE);
radius = sround(drad);
/* Set pointer to origin of grid centered on the current pixel. */
sptr = pptr - (radius*pw) - radius;
/* For each row in the grid ... */
for(py = 0; py < isobin_grid_dim; py++){
/* Set pixel pointer to start of next row in grid. */
cptr = sptr;
/* For each column in the grid ... */
for(px = 0; px < isobin_grid_dim; px++){
/* Accumulate next pixel in the grid. */
bsum += *cptr;
/* Bump pixel pointer. */
cptr++;
}
/* Bump to the start of the next row in the grid. */
sptr += pw;
}
/* If current (center) pixel when treated as an average for the */
/* entire grid is less than the total pixel sum of the grid ... */
if((*pptr * isobin_grid_dim * isobin_grid_dim) < bsum)
/* Set the binary pixel to BLACK. */
return(BLACK_PIXEL);
else
/* Otherwise, set the binary pixel to WHITE. */
return(WHITE_PIXEL);
}

View file

@ -35,7 +35,6 @@ identified are necessarily the best available for the purpose.
*********************************************************************** ***********************************************************************
ROUTINES: ROUTINES:
lfs_detect_minutiae()
lfs_detect_minutiae_V2() lfs_detect_minutiae_V2()
***********************************************************************/ ***********************************************************************/
@ -43,330 +42,8 @@ identified are necessarily the best available for the purpose.
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <lfs.h> #include <lfs.h>
#include <mytime.h>
#include <log.h> #include <log.h>
/*************************************************************************
#cat: lfs_detect_minutiae - Takes a grayscale fingerprint image (of arbitrary
#cat: size), and returns a map of directional ridge flow in the image
#cat: (2 versions), a binarized image designating ridges from valleys,
#cat: and a list of minutiae (including position, type, direction,
#cat: neighbors, and ridge counts to neighbors).
Input:
idata - input 8-bit grayscale fingerprint image data
iw - width (in pixels) of the image
ih - height (in pixels) of the image
lfsparms - parameters and thresholds for controlling LFS
Output:
ominutiae - resulting list of minutiae
oimap - resulting IMAP
{invalid (-1) or valid ridge directions}
onmap - resulting NMAP
{invalid (-1), high-curvature (-2), blanked blocks {-3} or
valid ridge directions}
omw - width (in blocks) of image maps
omh - height (in blocks) of image maps
obdata - resulting binarized image
{0 = black pixel (ridge) and 255 = white pixel (valley)}
obw - width (in pixels) of the binary image
obh - height (in pixels) of the binary image
Return Code:
Zero - successful completion
Negative - system error
**************************************************************************/
int lfs_detect_minutiae(MINUTIAE **ominutiae,
int **oimap, int **onmap, int *omw, int *omh,
unsigned char **obdata, int *obw, int *obh,
unsigned char *idata, const int iw, const int ih,
const LFSPARMS *lfsparms)
{
unsigned char *pdata, *bdata;
int pw, ph, bw, bh;
DIR2RAD *dir2rad;
DFTWAVES *dftwaves;
ROTGRIDS *dftgrids;
ROTGRIDS *dirbingrids;
int *imap, *nmap, mw, mh;
int ret, maxpad;
MINUTIAE *minutiae;
set_timer(total_timer);
/******************/
/* INITIALIZATION */
/******************/
/* If LOG_REPORT defined, open log report file. */
if((ret = open_logfile()))
/* If system error, exit with error code. */
return(ret);
/* Determine the maximum amount of image padding required to support */
/* LFS processes. */
maxpad = get_max_padding(lfsparms->blocksize,
lfsparms->dirbin_grid_w, lfsparms->dirbin_grid_h,
lfsparms->isobin_grid_dim);
/* Initialize lookup table for converting integer IMAP directions */
/* to angles in radians. */
if((ret = init_dir2rad(&dir2rad, lfsparms->num_directions))){
/* Free memory allocated to this point. */
return(ret);
}
/* Initialize wave form lookup tables for DFT analyses. */
/* used for direction binarization. */
if((ret = init_dftwaves(&dftwaves, dft_coefs, lfsparms->num_dft_waves,
lfsparms->blocksize))){
/* Free memory allocated to this point. */
free_dir2rad(dir2rad);
return(ret);
}
/* Initialize lookup table for pixel offsets to rotated grids */
/* used for DFT analyses. */
if((ret = init_rotgrids(&dftgrids, iw, ih, maxpad,
lfsparms->start_dir_angle, lfsparms->num_directions,
lfsparms->blocksize, lfsparms->blocksize,
RELATIVE2ORIGIN))){
/* Free memory allocated to this point. */
free_dir2rad(dir2rad);
free_dftwaves(dftwaves);
return(ret);
}
/* Pad input image based on max padding. */
if(maxpad > 0){ /* May not need to pad at all */
if((ret = pad_uchar_image(&pdata, &pw, &ph, idata, iw, ih,
maxpad, lfsparms->pad_value))){
/* Free memory allocated to this point. */
free_dir2rad(dir2rad);
free_dftwaves(dftwaves);
free_rotgrids(dftgrids);
return(ret);
}
}
else{
/* If padding is unnecessary, then copy the input image. */
pdata = (unsigned char *)malloc(iw*ih);
if(pdata == (unsigned char *)NULL){
/* Free memory allocated to this point. */
free_dir2rad(dir2rad);
free_dftwaves(dftwaves);
free_rotgrids(dftgrids);
fprintf(stderr, "ERROR : lfs_detect_minutiae : malloc : pdata\n");
return(-430);
}
memcpy(pdata, idata, iw*ih);
pw = iw;
ph = ih;
}
/* Scale input image to 6 bits [0..63] */
/* !!! Would like to remove this dependency eventualy !!! */
/* But, the DFT computations will need to be changed, and */
/* could not get this work upon first attempt. */
bits_8to6(pdata, pw, ph);
print2log("\nINITIALIZATION AND PADDING DONE\n");
/******************/
/* IMAP */
/******************/
set_timer(imap_timer);
/* Generate IMAP for the input image. */
if((ret = gen_imap(&imap, &mw, &mh, pdata, pw, ph, dir2rad,
dftwaves, dftgrids, lfsparms))){
/* Free memory allocated to this point. */
free_dir2rad(dir2rad);
free_dftwaves(dftwaves);
free_rotgrids(dftgrids);
free(pdata);
return(ret);
}
free_dir2rad(dir2rad);
free_dftwaves(dftwaves);
free_rotgrids(dftgrids);
print2log("\nIMAP DONE\n");
/* Generate NMAP from the IMAP of the input image. */
if((ret = gen_nmap(&nmap, imap, mw, mh, lfsparms))){
/* Free memory allocated to this point. */
free(pdata);
free(imap);
return(ret);
}
print2log("\nNMAP DONE\n");
time_accum(imap_timer, imap_time);
/******************/
/* BINARIZARION */
/******************/
set_timer(bin_timer);
/* Initialize lookup table for pixel offsets to rotated grids */
/* used for directional binarization. */
if((ret = init_rotgrids(&dirbingrids, iw, ih, maxpad,
lfsparms->start_dir_angle, lfsparms->num_directions,
lfsparms->dirbin_grid_w, lfsparms->dirbin_grid_h,
RELATIVE2CENTER))){
/* Free memory allocated to this point. */
free(pdata);
free(imap);
free(nmap);
return(ret);
}
/* Binarize input image based on NMAP information. */
if((ret = binarize(&bdata, &bw, &bh, pdata, pw, ph, nmap, mw, mh,
dirbingrids, lfsparms))){
/* Free memory allocated to this point. */
free(pdata);
free(imap);
free(nmap);
free_rotgrids(dirbingrids);
return(ret);
}
free_rotgrids(dirbingrids);
/* Check dimension of binary image. If they are different from */
/* the input image, then ERROR. */
if((iw != bw) || (ih != bh)){
/* Free memory allocated to this point. */
free(pdata);
free(imap);
free(nmap);
free(bdata);
fprintf(stderr,
"ERROR : lfs_detect_minutiae : binary image has bad dimensions : %d, %d\n",
bw, bh);
return(-431);
}
print2log("\nBINARIZATION DONE\n");
time_accum(bin_timer, bin_time);
/******************/
/* DETECTION */
/******************/
set_timer(minutia_timer);
/* Convert 8-bit grayscale binary image [0,255] to */
/* 8-bit binary image [0,1]. */
gray2bin(1, 1, 0, bdata, iw, ih);
/* Allocate list of maximum number of minutia pointers. */
if((ret = alloc_minutiae(&minutiae, MAX_MINUTIAE))){
return(ret);
}
/* Detect the minutiae in the binarized image. */
if((ret = detect_minutiae(minutiae, bdata, iw, ih, imap, nmap, mw, mh,
lfsparms))){
/* Free memory allocated to this point. */
free(pdata);
free(imap);
free(nmap);
free(bdata);
return(ret);
}
time_accum(minutia_timer, minutia_time);
set_timer(rm_minutia_timer);
if((ret = remove_false_minutia(minutiae, bdata, iw, ih, nmap, mw, mh,
lfsparms))){
/* Free memory allocated to this point. */
free(pdata);
free(imap);
free(nmap);
free(bdata);
free_minutiae(minutiae);
return(ret);
}
print2log("\nMINUTIA DETECTION DONE\n");
time_accum(rm_minutia_timer, rm_minutia_time);
/******************/
/* RIDGE COUNTS */
/******************/
set_timer(ridge_count_timer);
if((ret = count_minutiae_ridges(minutiae, bdata, iw, ih, lfsparms))){
/* Free memory allocated to this point. */
free(pdata);
free(imap);
free(nmap);
free(bdata);
free_minutiae(minutiae);
return(ret);
}
print2log("\nNEIGHBOR RIDGE COUNT DONE\n");
time_accum(ridge_count_timer, ridge_count_time);
/******************/
/* WRAP-UP */
/******************/
/* Convert 8-bit binary image [0,1] to 8-bit */
/* grayscale binary image [0,255]. */
gray2bin(1, 255, 0, bdata, iw, ih);
/* Deallocate working memory. */
free(pdata);
/* Assign results to output pointers. */
*oimap = imap;
*onmap = nmap;
*omw = mw;
*omh = mh;
*obdata = bdata;
*obw = bw;
*obh = bh;
*ominutiae = minutiae;
time_accum(total_timer, total_time);
/******************/
/* PRINT TIMINGS */
/******************/
/* These Timings will print when TIMER is defined. */
/* print IMAP generation timing statistics */
print_time(stderr, "TIMER: IMAP time = %f (secs)\n", imap_time);
/* print binarization timing statistics */
print_time(stderr, "TIMER: Binarization time = %f (secs)\n", bin_time);
/* print minutia detection timing statistics */
print_time(stderr, "TIMER: Minutia Detection time = %f (secs)\n",
minutia_time);
/* print minutia removal timing statistics */
print_time(stderr, "TIMER: Minutia Removal time = %f (secs)\n",
rm_minutia_time);
/* print neighbor ridge count timing statistics */
print_time(stderr, "TIMER: Neighbor Ridge Counting time = %f (secs)\n",
ridge_count_time);
/* print total timing statistics */
print_time(stderr, "TIMER: Total time = %f (secs)\n", total_time);
/* If LOG_REPORT defined, close log report file. */
if((ret = close_logfile()))
return(ret);
return(0);
}
/************************************************************************* /*************************************************************************
#cat: lfs_detect_minutiae_V2 - Takes a grayscale fingerprint image (of #cat: lfs_detect_minutiae_V2 - Takes a grayscale fingerprint image (of
#cat: arbitrary size), and returns a set of image block maps, #cat: arbitrary size), and returns a set of image block maps,
@ -421,8 +98,6 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
int ret, maxpad; int ret, maxpad;
MINUTIAE *minutiae; MINUTIAE *minutiae;
set_timer(total_timer);
/******************/ /******************/
/* INITIALIZATION */ /* INITIALIZATION */
/******************/ /******************/
@ -505,7 +180,6 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
/******************/ /******************/
/* MAPS */ /* MAPS */
/******************/ /******************/
set_timer(imap_timer);
/* Generate block maps from the input image. */ /* Generate block maps from the input image. */
if((ret = gen_image_maps(&direction_map, &low_contrast_map, if((ret = gen_image_maps(&direction_map, &low_contrast_map,
@ -525,12 +199,9 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
print2log("\nMAPS DONE\n"); print2log("\nMAPS DONE\n");
time_accum(imap_timer, imap_time);
/******************/ /******************/
/* BINARIZARION */ /* BINARIZARION */
/******************/ /******************/
set_timer(bin_timer);
/* Initialize lookup table for pixel offsets to rotated grids */ /* Initialize lookup table for pixel offsets to rotated grids */
/* used for directional binarization. */ /* used for directional binarization. */
@ -582,12 +253,9 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
print2log("\nBINARIZATION DONE\n"); print2log("\nBINARIZATION DONE\n");
time_accum(bin_timer, bin_time);
/******************/ /******************/
/* DETECTION */ /* DETECTION */
/******************/ /******************/
set_timer(minutia_timer);
/* Convert 8-bit grayscale binary image [0,255] to */ /* Convert 8-bit grayscale binary image [0,255] to */
/* 8-bit binary image [0,1]. */ /* 8-bit binary image [0,1]. */
@ -612,10 +280,6 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
return(ret); return(ret);
} }
time_accum(minutia_timer, minutia_time);
set_timer(rm_minutia_timer);
if((ret = remove_false_minutia_V2(minutiae, bdata, iw, ih, if((ret = remove_false_minutia_V2(minutiae, bdata, iw, ih,
direction_map, low_flow_map, high_curve_map, mw, mh, direction_map, low_flow_map, high_curve_map, mw, mh,
lfsparms))){ lfsparms))){
@ -632,13 +296,9 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
print2log("\nMINUTIA DETECTION DONE\n"); print2log("\nMINUTIA DETECTION DONE\n");
time_accum(rm_minutia_timer, rm_minutia_time);
/******************/ /******************/
/* RIDGE COUNTS */ /* RIDGE COUNTS */
/******************/ /******************/
set_timer(ridge_count_timer);
if((ret = count_minutiae_ridges(minutiae, bdata, iw, ih, lfsparms))){ if((ret = count_minutiae_ridges(minutiae, bdata, iw, ih, lfsparms))){
/* Free memory allocated to this point. */ /* Free memory allocated to this point. */
free(pdata); free(pdata);
@ -653,8 +313,6 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
print2log("\nNEIGHBOR RIDGE COUNT DONE\n"); print2log("\nNEIGHBOR RIDGE COUNT DONE\n");
time_accum(ridge_count_timer, ridge_count_time);
/******************/ /******************/
/* WRAP-UP */ /* WRAP-UP */
/******************/ /******************/
@ -678,28 +336,6 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
*obh = bh; *obh = bh;
*ominutiae = minutiae; *ominutiae = minutiae;
time_accum(total_timer, total_time);
/******************/
/* PRINT TIMINGS */
/******************/
/* These Timings will print when TIMER is defined. */
/* print MAP generation timing statistics */
print_time(stderr, "TIMER: MAPS time = %f (secs)\n", imap_time);
/* print binarization timing statistics */
print_time(stderr, "TIMER: Binarization time = %f (secs)\n", bin_time);
/* print minutia detection timing statistics */
print_time(stderr, "TIMER: Minutia Detection time = %f (secs)\n",
minutia_time);
/* print minutia removal timing statistics */
print_time(stderr, "TIMER: Minutia Removal time = %f (secs)\n",
rm_minutia_time);
/* print neighbor ridge count timing statistics */
print_time(stderr, "TIMER: Neighbor Ridge Counting time = %f (secs)\n",
ridge_count_time);
/* print total timing statistics */
print_time(stderr, "TIMER: Total time = %f (secs)\n", total_time);
/* If LOG_REPORT defined, close log report file. */ /* If LOG_REPORT defined, close log report file. */
if((ret = close_logfile())) if((ret = close_logfile()))
return(ret); return(ret);

View file

@ -47,6 +47,84 @@ identified are necessarily the best available for the purpose.
#include <stdlib.h> #include <stdlib.h>
#include <lfs.h> #include <lfs.h>
/*************************************************************************
**************************************************************************
#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
**************************************************************************/
static 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
**************************************************************************/
static 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_dir_powers - Conducts the DFT analysis on a block of image data. #cat: dft_dir_powers - Conducts the DFT analysis on a block of image data.
@ -121,80 +199,105 @@ int dft_dir_powers(double **powers, unsigned char *pdata,
/************************************************************************* /*************************************************************************
************************************************************************** **************************************************************************
#cat: sum_rot_block_rows - Computes a vector or pixel row sums by sampling #cat: get_max_norm - Analyses a DFT power vector for a specific wave form
#cat: the current image block at a given orientation. The #cat: applied at different orientations (directions) to the
#cat: sampling is conducted using a precomputed set of rotated #cat: current image block. The routine retuns the maximum
#cat: pixel offsets (called a grid) relative to the orgin of #cat: power value in the vector, the direction at which the
#cat: the image block. #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: Input:
blkptr - the pixel address of the origin of the current image block power_vector - the DFT power values derived form a specific wave form
grid_offsets - the rotated pixel offsets for a block-sized grid applied at different directions
rotated according to a specific orientation ndirs - the number of directions to which the wave form was applied
blocksize - the width and height of the image block and thus the size
of the rotated grid
Output: Output:
rowsums - the resulting vector of pixel row sums 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 sum_rot_block_rows(int *rowsums, const unsigned char *blkptr, static void get_max_norm(double *powmax, int *powmax_dir,
const int *grid_offsets, const int blocksize) double *pownorm, const double *power_vector, const int ndirs)
{ {
int ix, iy, gi; int dir;
double max_v, powsum;
int max_i;
double powmean;
/* Initialize rotation offset index. */ /* Find max power value and store corresponding direction */
gi = 0; max_v = power_vector[0];
max_i = 0;
/* For each row in block ... */ /* Sum the total power in a block at a given direction */
for(iy = 0; iy < blocksize; iy++){ powsum = power_vector[0];
/* The sums are accumlated along the rotated rows of the grid, */
/* so initialize row sum to 0. */ /* For each direction ... */
rowsums[iy] = 0; for(dir = 1; dir < ndirs; dir++){
/* Foreach column in block ... */ powsum += power_vector[dir];
for(ix = 0; ix < blocksize; ix++){ if(power_vector[dir] > max_v){
/* Accumulate pixel value at rotated grid position in image */ max_v = power_vector[dir];
rowsums[iy] += *(blkptr + grid_offsets[gi]); max_i = dir;
gi++;
} }
} }
*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: dft_power - Computes the DFT power by applying a specific wave form #cat: sort_dft_waves - Creates a ranked list of DFT wave form statistics
#cat: frequency to a vector of pixel row sums computed from a #cat: by sorting on the normalized squared maximum power.
#cat: specific orientation of the block image
Input: Input:
rowsums - accumulated rows of pixels from within a rotated grid powmaxs - maximum DFT power for each wave form used to derive
overlaying an input image block statistics
wave - the wave form (cosine and sine components) at a specific pownorms - normalized maximum power corresponding to values in powmaxs
frequency nstats - number of wave forms used to derive statistics (N Wave - 1)
wavelen - the length of the wave form (must match the height of the
image block which is the length of the rowsum vector)
Output: Output:
power - the computed DFT power for the given wave form at the wis - sorted list of indices corresponding to the ranked set of
given orientation within the image block 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
**************************************************************************/ **************************************************************************/
void dft_power(double *power, const int *rowsums, static int sort_dft_waves(int *wis, const double *powmaxs, const double *pownorms,
const DFTWAVE *wave, const int wavelen) const int nstats)
{ {
int i; int i;
double cospart, sinpart; double *pownorms2;
/* Initialize accumulators */ /* Allocate normalized power^2 array */
cospart = 0.0; pownorms2 = (double *)malloc(nstats * sizeof(double));
sinpart = 0.0; if(pownorms2 == (double *)NULL){
fprintf(stderr, "ERROR : sort_dft_waves : malloc : pownorms2\n");
/* Accumulate cos and sin components of DFT. */ return(-100);
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 */ for(i = 0; i < nstats; i++){
*power = (cospart * cospart) + (sinpart * sinpart); /* 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);
} }
/************************************************************************* /*************************************************************************
@ -253,106 +356,3 @@ int dft_power_stats(int *wis, double *powmaxs, int *powmax_dirs,
return(0); 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);
}

View file

@ -37,7 +37,6 @@ identified are necessarily the best available for the purpose.
ROUTINES: ROUTINES:
init_dir2rad() init_dir2rad()
init_dftwaves() init_dftwaves()
get_max_padding()
get_max_padding_V2() get_max_padding_V2()
init_rotgrids() init_rotgrids()
alloc_dir_powers() alloc_dir_powers()
@ -243,80 +242,6 @@ int init_dftwaves(DFTWAVES **optr, const double *dft_coefs,
return(0); return(0);
} }
/*************************************************************************
**************************************************************************
#cat: get_max_padding - Deterines the maximum amount of image pixel padding
#cat: required by all LFS processes. Padding is currently
#cat: required by the rotated grids used in DFT analyses,
#cat: rotated grids used in directional binarization,
#cat: and in the grid used for isotropic binarization.
#cat: The NIST generalized code enables the parameters
#cat: governing these processes to be redefined, so a check
#cat: at runtime is required to determine which process
#cat: requires the most padding. By using the maximum as
#cat: the padding factor, all processes will run safely
#cat: with a single padding of the input image avoiding the
#cat: need to repad for further processes.
Input:
imap_blocksize - the size (in pixels) of each IMAP block in the image
dirbin_grid_w - the width (in pixels) of the rotated grids used in
directional binarization
dirbin_grid_h - the height (in pixels) of the rotated grids used in
directional binarization
isobin_grid_dim - the dimension (in pixels) of the square grid used in
isotropic binarization
Return Code:
Non-negative - the maximum padding required for all processes
**************************************************************************/
int get_max_padding(const int imap_blocksize,
const int dirbin_grid_w, const int dirbin_grid_h,
const int isobin_grid_dim)
{
int dft_pad, dirbin_pad, isobin_pad, max_pad;
double diag;
double pad;
/* Compute pad required for rotated blocks used in DFT analyses. */
diag = sqrt((double)(2.0 * imap_blocksize * imap_blocksize));
/* Compute pad as difference between the IMAP blocksize */
/* and the diagonal distance of the block. */
/* Assumption: all block origins reside in valid/allocated memory. */
/* DFT grids are computed with pixel offsets RELATIVE2ORIGIN. */
pad = (diag-imap_blocksize)/(double)2.0;
/* Need to truncate precision so that answers are consistent */
/* on different computer architectures when rounding doubles. */
pad = trunc_dbl_precision(pad, TRUNC_SCALE);
dft_pad = sround(pad);
/* Compute pad required for rotated blocks used in directional */
/* binarization. */
diag = sqrt((double)((dirbin_grid_w*dirbin_grid_w)+
(dirbin_grid_h*dirbin_grid_h)));
/* Assumption: all grid centers reside in valid/allocated memory. */
/* dirbin grids are computed with pixel offsets RELATIVE2CENTER. */
pad = (diag-1)/(double)2.0;
/* Need to truncate precision so that answers are consistent */
/* on different computer architectures when rounding doubles. */
pad = trunc_dbl_precision(pad, TRUNC_SCALE);
dirbin_pad = sround(pad);
/* Compute pad required for grids used in isotropic binarization. */
pad = (isobin_grid_dim - 1)/(double)2.0;
/* Need to truncate precision so that answers are consistent */
/* on different computer architectures when rounding doubles. */
pad = trunc_dbl_precision(pad, TRUNC_SCALE);
isobin_pad = sround((isobin_grid_dim - 1)/(double)2.0);
max_pad = max(dft_pad, dirbin_pad);
max_pad = max(max_pad, isobin_pad);
/* Return the maximum of the three required paddings. This padding will */
/* be sufficiently large for all three purposes, so that padding of the */
/* input image will only be required once. */
return(max_pad);
}
/************************************************************************* /*************************************************************************
************************************************************************** **************************************************************************
#cat: get_max_padding_V2 - Deterines the maximum amount of image pixel padding #cat: get_max_padding_V2 - Deterines the maximum amount of image pixel padding

View file

@ -46,8 +46,6 @@ identified are necessarily the best available for the purpose.
get_loop_aspect() get_loop_aspect()
fill_loop() fill_loop()
fill_partial_row() fill_partial_row()
flood_loop()
flood_fill4()
***********************************************************************/ ***********************************************************************/
#include <stdio.h> #include <stdio.h>
@ -499,6 +497,107 @@ int is_loop_clockwise(const int *contour_x, const int *contour_y,
return(ret); return(ret);
} }
/*************************************************************************
**************************************************************************
#cat: get_loop_aspect - Takes a contour list (determined to form a complete
#cat: loop) and measures the loop's aspect (the largest and smallest
#cat: distances across the loop) and returns the points on the
#cat: loop where these distances occur.
Input:
contour_x - x-coord list for loop's contour points
contour_y - y-coord list for loop's contour points
ncontour - number of points in contour
Output:
omin_fr - contour point index where minimum aspect occurs
omin_to - opposite contour point index where minimum aspect occurs
omin_dist - the minimum distance across the loop
omax_fr - contour point index where maximum aspect occurs
omax_to - contour point index where maximum aspect occurs
omax_dist - the maximum distance across the loop
**************************************************************************/
static void get_loop_aspect(int *omin_fr, int *omin_to, double *omin_dist,
int *omax_fr, int *omax_to, double *omax_dist,
const int *contour_x, const int *contour_y, const int ncontour)
{
int halfway, limit;
int i, j;
double dist;
double min_dist, max_dist;
int min_i, max_i, min_j, max_j;
/* Compute half the perimeter of the loop. */
halfway = ncontour>>1;
/* Take opposite points on the contour and walk half way */
/* around the loop. */
i = 0;
j = halfway;
/* Compute squared distance between opposite points on loop. */
dist = squared_distance(contour_x[i], contour_y[i],
contour_x[j], contour_y[j]);
/* Initialize running minimum and maximum distances along loop. */
min_dist = dist;
min_i = i;
min_j = j;
max_dist = dist;
max_i = i;
max_j = j;
/* Bump to next pair of opposite points. */
i++;
/* Make sure j wraps around end of list. */
j++;
j %= ncontour;
/* If the loop is of even length, then we only need to walk half */
/* way around as the other half will be exactly redundant. If */
/* the loop is of odd length, then the second half will not be */
/* be exactly redundant and the difference "may" be meaningful. */
/* If execution speed is an issue, then probably get away with */
/* walking only the fist half of the loop under ALL conditions. */
/* If loop has odd length ... */
if(ncontour % 2)
/* Walk the loop's entire perimeter. */
limit = ncontour;
/* Otherwise the loop has even length ... */
else
/* Only walk half the perimeter. */
limit = halfway;
/* While we have not reached our perimeter limit ... */
while(i < limit){
/* Compute squared distance between opposite points on loop. */
dist = squared_distance(contour_x[i], contour_y[i],
contour_x[j], contour_y[j]);
/* Check the running minimum and maximum distances. */
if(dist < min_dist){
min_dist = dist;
min_i = i;
min_j = j;
}
if(dist > max_dist){
max_dist = dist;
max_i = i;
max_j = j;
}
/* Bump to next pair of opposite points. */
i++;
/* Make sure j wraps around end of list. */
j++;
j %= ncontour;
}
/* Assign minimum and maximum distances to output pointers. */
*omin_fr = min_i;
*omin_to = min_j;
*omin_dist = min_dist;
*omax_fr = max_i;
*omax_to = max_j;
*omax_dist = max_dist;
}
/************************************************************************* /*************************************************************************
************************************************************************** **************************************************************************
#cat: process_loop - Takes a contour list that has been determined to form #cat: process_loop - Takes a contour list that has been determined to form
@ -845,103 +944,39 @@ int process_loop_V2(MINUTIAE *minutiae,
/************************************************************************* /*************************************************************************
************************************************************************** **************************************************************************
#cat: get_loop_aspect - Takes a contour list (determined to form a complete #cat: fill_partial_row - Fills a specified range of contiguous pixels on
#cat: loop) and measures the loop's aspect (the largest and smallest #cat: a specified row of an 8-bit pixel image with a specified
#cat: distances across the loop) and returns the points on the #cat: pixel value. NOTE, the pixel coordinates are assumed to
#cat: loop where these distances occur. #cat: be within the image boundaries.
Input: Input:
contour_x - x-coord list for loop's contour points fill_pix - pixel value to fill with (should be on range [0..255]
contour_y - y-coord list for loop's contour points frx - x-pixel coord where fill should begin
ncontour - number of points in contour tox - x-pixel coord where fill should end (inclusive)
y - y-pixel coord of current row being filled
bdata - 8-bit image data
iw - width (in pixels) of image
ih - height (in pixels) of image
Output: Output:
omin_fr - contour point index where minimum aspect occurs bdata - 8-bit image data with partial row filled.
omin_to - opposite contour point index where minimum aspect occurs
omin_dist - the minimum distance across the loop
omax_fr - contour point index where maximum aspect occurs
omax_to - contour point index where maximum aspect occurs
omax_dist - the maximum distance across the loop
**************************************************************************/ **************************************************************************/
void get_loop_aspect(int *omin_fr, int *omin_to, double *omin_dist, static void fill_partial_row(const int fill_pix, const int frx, const int tox,
int *omax_fr, int *omax_to, double *omax_dist, const int y, unsigned char *bdata, const int iw, const int ih)
const int *contour_x, const int *contour_y, const int ncontour)
{ {
int halfway, limit; int x;
int i, j; unsigned char *bptr;
double dist;
double min_dist, max_dist;
int min_i, max_i, min_j, max_j;
/* Compute half the perimeter of the loop. */ /* Set pixel pointer to starting x-coord on current row. */
halfway = ncontour>>1; bptr = bdata+(y*iw)+frx;
/* Take opposite points on the contour and walk half way */ /* Foreach pixel between starting and ending x-coord on row */
/* around the loop. */ /* (including the end points) ... */
i = 0; for(x = frx; x <= tox; x++){
j = halfway; /* Set current pixel with fill pixel value. */
/* Compute squared distance between opposite points on loop. */ *bptr = fill_pix;
dist = squared_distance(contour_x[i], contour_y[i], /* Bump to next pixel in the row. */
contour_x[j], contour_y[j]); bptr++;
/* Initialize running minimum and maximum distances along loop. */
min_dist = dist;
min_i = i;
min_j = j;
max_dist = dist;
max_i = i;
max_j = j;
/* Bump to next pair of opposite points. */
i++;
/* Make sure j wraps around end of list. */
j++;
j %= ncontour;
/* If the loop is of even length, then we only need to walk half */
/* way around as the other half will be exactly redundant. If */
/* the loop is of odd length, then the second half will not be */
/* be exactly redundant and the difference "may" be meaningful. */
/* If execution speed is an issue, then probably get away with */
/* walking only the fist half of the loop under ALL conditions. */
/* If loop has odd length ... */
if(ncontour % 2)
/* Walk the loop's entire perimeter. */
limit = ncontour;
/* Otherwise the loop has even length ... */
else
/* Only walk half the perimeter. */
limit = halfway;
/* While we have not reached our perimeter limit ... */
while(i < limit){
/* Compute squared distance between opposite points on loop. */
dist = squared_distance(contour_x[i], contour_y[i],
contour_x[j], contour_y[j]);
/* Check the running minimum and maximum distances. */
if(dist < min_dist){
min_dist = dist;
min_i = i;
min_j = j;
}
if(dist > max_dist){
max_dist = dist;
max_i = i;
max_j = j;
}
/* Bump to next pair of opposite points. */
i++;
/* Make sure j wraps around end of list. */
j++;
j %= ncontour;
} }
/* Assign minimum and maximum distances to output pointers. */
*omin_fr = min_i;
*omin_to = min_j;
*omin_dist = min_dist;
*omax_fr = max_i;
*omax_to = max_j;
*omax_dist = max_dist;
} }
/************************************************************************* /*************************************************************************
@ -1075,154 +1110,3 @@ int fill_loop(const int *contour_x, const int *contour_y,
return(0); return(0);
} }
/*************************************************************************
**************************************************************************
#cat: fill_partial_row - Fills a specified range of contiguous pixels on
#cat: a specified row of an 8-bit pixel image with a specified
#cat: pixel value. NOTE, the pixel coordinates are assumed to
#cat: be within the image boundaries.
Input:
fill_pix - pixel value to fill with (should be on range [0..255]
frx - x-pixel coord where fill should begin
tox - x-pixel coord where fill should end (inclusive)
y - y-pixel coord of current row being filled
bdata - 8-bit image data
iw - width (in pixels) of image
ih - height (in pixels) of image
Output:
bdata - 8-bit image data with partial row filled.
**************************************************************************/
void fill_partial_row(const int fill_pix, const int frx, const int tox,
const int y, unsigned char *bdata, const int iw, const int ih)
{
int x;
unsigned char *bptr;
/* Set pixel pointer to starting x-coord on current row. */
bptr = bdata+(y*iw)+frx;
/* Foreach pixel between starting and ending x-coord on row */
/* (including the end points) ... */
for(x = frx; x <= tox; x++){
/* Set current pixel with fill pixel value. */
*bptr = fill_pix;
/* Bump to next pixel in the row. */
bptr++;
}
}
/*************************************************************************
**************************************************************************
#cat: flood_loop - Fills a given contour (determined to form a complete loop)
#cat: with a specified pixel value using a recursive flood-fill
#cat: technique.
#cat: NOTE, this fill approach will NOT always work with the
#cat: contours generated in this application because they
#cat: are NOT guaranteed to be ENTIRELY surrounded by 8-connected
#cat: pixels not equal to the fill pixel value. This is unfortunate
#cat: because the flood-fill is a simple algorithm that will handle
#cat: complex/concaved shapes.
Input:
contour_x - x-coord list for loop's contour points
contour_y - y-coord list for loop's contour points
ncontour - number of points in contour
bdata - binary image data (0==while & 1==black)
iw - width (in pixels) of image
ih - height (in pixels) of image
Output:
bdata - binary image data with loop filled
**************************************************************************/
void flood_loop(const int *contour_x, const int *contour_y,
const int ncontour, unsigned char *bdata,
const int iw, const int ih)
{
int feature_pix, fill_pix;
int i;
/* Get the pixel value of the minutia feauture. This is */
/* the pixel value we wish to replace with the flood. */
feature_pix = *(bdata + (contour_y[0] * iw) + contour_x[0]);
/* Flip the feature pixel value to the value we want to */
/* fill with and send this value to the flood routine. */
fill_pix = !feature_pix;
/* Flood-fill interior of contour using a 4-neighbor fill. */
/* We are using a 4-neighbor fill because the contour was */
/* collected using 8-neighbors, and the 4-neighbor fill */
/* will NOT escape the 8-neighbor based contour. */
/* The contour passed must be guarenteed to be complete for */
/* the flood-fill to work properly. */
/* We are initiating a flood-fill from each point on the */
/* contour to make sure complex patterns get filled in. */
/* The complex patterns we are concerned about are those */
/* that "pinch" the interior of the feature off due to */
/* skipping "exposed" corners along the contour. */
/* Simple shapes will fill upon invoking the first contour */
/* pixel, and the subsequent calls will immediately return */
/* as their seed pixel will have already been flipped. */
for(i = 0; i < ncontour; i++){
/* Start the recursive flooding. */
flood_fill4(fill_pix, contour_x[i], contour_y[i],
bdata, iw, ih);
}
}
/*************************************************************************
**************************************************************************
#cat: flood_fill4 - Recursively floods a region of an 8-bit pixel image with a
#cat: specified pixel value given a starting (seed) point. The
#cat: recursion is based neighbors being 4-connected.
Input:
fill_pix - 8-bit pixel value to be filled with (on range [0..255]
x - starting x-pixel coord
y - starting y-pixel coord
bdata - 8-bit pixel image data
iw - width (in pixels) of image
ih - height (in pixels) of image
Output:
bdata - 8-bit pixel image data with region filled
**************************************************************************/
void flood_fill4(const int fill_pix, const int x, const int y,
unsigned char *bdata, const int iw, const int ih)
{
unsigned char *pptr;
int y_north, y_south, x_east, x_west;
/* Get address of current pixel. */
pptr = bdata + (y*iw) + x;
/* If pixel needs to be filled ... */
if(*pptr != fill_pix){
/* Fill the current pixel. */
*pptr = fill_pix;
/* Recursively invoke flood on the pixel's 4 neighbors. */
/* Test to make sure neighbors are within image boudaries */
/* before invoking each flood. */
y_north = y-1;
y_south = y+1;
x_west = x-1;
x_east = x+1;
/* Invoke North */
if(y_north >= 0)
flood_fill4(fill_pix, x, y_north, bdata, iw, ih);
/* Invoke East */
if(x_east < iw)
flood_fill4(fill_pix, x_east, y, bdata, iw, ih);
/* Invoke South */
if(y_south < ih)
flood_fill4(fill_pix, x, y_south, bdata, iw, ih);
/* Invoke West */
if(x_west >= 0)
flood_fill4(fill_pix, x_west, y, bdata, iw, ih);
}
/* Otherwise, there is nothing to be done. */
}

View file

@ -46,7 +46,6 @@ identified are necessarily the best available for the purpose.
pixelize_map() pixelize_map()
smooth_direction_map() smooth_direction_map()
gen_high_curve_map() gen_high_curve_map()
gen_imap()
gen_initial_imap() gen_initial_imap()
primary_dir_test() primary_dir_test()
secondary_fork_test() secondary_fork_test()
@ -59,7 +58,6 @@ identified are necessarily the best available for the purpose.
average_8nbr_dir() average_8nbr_dir()
num_valid_8nbrs() num_valid_8nbrs()
smooth_imap() smooth_imap()
gen_nmap()
vorticity() vorticity()
accum_nbr_vorticity() accum_nbr_vorticity()
curvature() curvature()
@ -930,75 +928,6 @@ int gen_high_curve_map(int **ohcmap, int *direction_map,
return(0); return(0);
} }
/*************************************************************************
**************************************************************************
#cat: gen_imap - Computes an IMAP, which is a 2D vector of integer directions,
#cat: where each direction represents the dominant ridge flow in
#cat: a block of the input grayscale image. This routine will
#cat: generate an IMAP for arbitrarily sized, non-square, images.
Input:
pdata - padded input image data (8 bits [0..256) grayscale)
pw - padded width (in pixels) of the input image
ph - padded height (in pixels) of the input image
dir2rad - lookup table for converting integer directions
dftwaves - structure containing the DFT wave forms
dftgrids - structure containing the rotated pixel grid offsets
lfsparms - parameters and thresholds for controlling LFS
Output:
optr - points to the created IMAP
ow - width (in blocks) of the IMAP
oh - height (in blocks) of the IMAP
Return Code:
Zero - successful completion
Negative - system error
**************************************************************************/
int gen_imap(int **optr, int *ow, int *oh,
unsigned char *pdata, const int pw, const int ph,
const DIR2RAD *dir2rad, const DFTWAVES *dftwaves,
const ROTGRIDS *dftgrids, const LFSPARMS *lfsparms)
{
int *imap, mw, mh, iw, ih;
int *blkoffs;
int ret; /* return code */
/* 1. Compute block offsets for the entire image, accounting for pad */
/* Block_offsets() assumes square block (grid), so ERROR otherwise. */
if(dftgrids->grid_w != dftgrids->grid_h){
fprintf(stderr, "ERROR : gen_imap : DFT grids must be square\n");
return(-60);
}
/* Compute unpadded image dimensions. */
iw = pw - (dftgrids->pad<<1);
ih = ph - (dftgrids->pad<<1);
if((ret = block_offsets(&blkoffs, &mw, &mh, iw, ih,
dftgrids->pad, dftgrids->grid_w))){
return(ret);
}
/* 2. Generate initial imap */
if((ret = gen_initial_imap(&imap, blkoffs, mw, mh, pdata, pw, ph,
dftwaves, dftgrids, lfsparms))){
/* Free memory allocated to this point. */
free(blkoffs);
return(ret);
}
/* 3. Remove IMAP directions that are inconsistent with neighbors */
remove_incon_dirs(imap, mw, mh, dir2rad, lfsparms);
/* 4. Smooth imap values with their neighbors */
smooth_imap(imap, mw, mh, dir2rad, lfsparms);
/* Deallocate working memory. */
free(blkoffs);
*optr = imap;
*ow = mw;
*oh = mh;
return(0);
}
/************************************************************************* /*************************************************************************
************************************************************************** **************************************************************************
#cat: gen_initial_imap - Creates an initial IMAP from the given input image. #cat: gen_initial_imap - Creates an initial IMAP from the given input image.
@ -2160,100 +2089,6 @@ void smooth_imap(int *imap, const int mw, const int mh,
} }
} }
/*************************************************************************
**************************************************************************
#cat: gen_nmap - Computes an NMAP from its associated 2D vector of integer
#cat: directions (IMAP). Each value in the NMAP either represents
#cat: a direction of dominant ridge flow in a block of the input
#cat: grayscale image, or it contains a codes describing why such
#cat: a direction was not procuded.
#cat: For example, blocks near areas of high-curvature (such as
#cat: with cores and deltas) will not produce reliable IMAP
#cat: directions.
Input:
imap - associated input vector of IMAP directions
mw - the width (in blocks) of the IMAP
mh - the height (in blocks) of the IMAP
lfsparms - parameters and thresholds for controlling LFS
Output:
optr - points to the created NMAP
Return Code:
Zero - successful completion
Negative - system error
**************************************************************************/
int gen_nmap(int **optr, int *imap, const int mw, const int mh,
const LFSPARMS *lfsparms)
{
int *nmap, mapsize;
int *nptr, *iptr;
int bx, by;
int nvalid, cmeasure, vmeasure;
mapsize = mw*mh;
nmap = (int *)malloc(mapsize * sizeof(int));
if(nmap == (int *)NULL){
fprintf(stderr, "ERROR: gen_nmap : malloc : nmap\n");
return(-120);
}
nptr = nmap;
iptr = imap;
/* Foreach row in IMAP ... */
for(by = 0; by < mh; by++){
/* Foreach column in IMAP ... */
for(bx = 0; bx < mw; bx++){
/* Count number of valid neighbors around current block ... */
nvalid = num_valid_8nbrs(imap, bx, by, mw, mh);
/* If block has no valid neighbors ... */
if(nvalid == 0)
/* Set NMAP value to NO VALID NEIGHBORS */
*nptr = NO_VALID_NBRS;
else{
/* If current IMAP value is INVALID ... */
if(*iptr == INVALID_DIR){
/* If not enough VALID neighbors ... */
if(nvalid < lfsparms->vort_valid_nbr_min){
/* Set NMAP value to INVALID */
*nptr = INVALID_DIR;
}
else{
/* Otherwise measure vorticity of neighbors. */
vmeasure = vorticity(imap, bx, by, mw, mh,
lfsparms->num_directions);
/* If vorticity too low ... */
if(vmeasure < lfsparms->highcurv_vorticity_min)
*nptr = INVALID_DIR;
else
/* Otherwise high-curvature area (Ex. core or delta). */
*nptr = HIGH_CURVATURE;
}
}
/* Otherwise VALID IMAP value ... */
else{
/* Measure curvature around the VALID IMAP block. */
cmeasure = curvature(imap, bx, by, mw, mh,
lfsparms->num_directions);
/* If curvature is too high ... */
if(cmeasure >= lfsparms->highcurv_curvature_min)
*nptr = HIGH_CURVATURE;
else
/* Otherwise acceptable amount of curature, so assign */
/* VALID IMAP value to NMAP. */
*nptr = *iptr;
}
} /* end else (nvalid > 0) */
/* BUMP IMAP and NMAP pointers. */
iptr++;
nptr++;
} /* bx */
} /* by */
*optr = nmap;
return(0);
}
/************************************************************************* /*************************************************************************
************************************************************************** **************************************************************************
#cat: vorticity - Measures the amount of cummulative curvature incurred #cat: vorticity - Measures the amount of cummulative curvature incurred

View file

@ -37,7 +37,6 @@ identified are necessarily the best available for the purpose.
ROUTINES: ROUTINES:
alloc_minutiae() alloc_minutiae()
realloc_minutiae() realloc_minutiae()
detect_minutiae()
detect_minutiae_V2() detect_minutiae_V2()
update_minutiae() update_minutiae()
update_minutiae_V2() update_minutiae_V2()
@ -144,99 +143,6 @@ int realloc_minutiae(MINUTIAE *minutiae, const int incr_minutiae)
return(0); return(0);
} }
/*************************************************************************
**************************************************************************
#cat: detect_minutiae - Takes a binary image and its associated IMAP and
#cat: NMAP matrices and scans each image block for potential
#cat: minutia points.
Input:
bdata - binary image data (0==while & 1==black)
iw - width (in pixels) of image
ih - height (in pixels) of image
imap - matrix of ridge flow directions
nmap - IMAP augmented with blocks of HIGH-CURVATURE and
blocks which have no neighboring valid directions.
mw - width (in blocks) of IMAP and NMAP matrices.
mh - height (in blocks) of IMAP and NMAP matrices.
lfsparms - parameters and thresholds for controlling LFS
Output:
minutiae - points to a list of detected minutia structures
Return Code:
Zero - successful completion
Negative - system error
**************************************************************************/
int detect_minutiae(MINUTIAE *minutiae,
unsigned char *bdata, const int iw, const int ih,
const int *imap, const int *nmap, const int mw, const int mh,
const LFSPARMS *lfsparms)
{
int blk_i, blk_x, blk_y;
int scan_x, scan_y, scan_w, scan_h;
int scan_dir;
int ret;
/* Start with first block in IMAP. */
blk_i = 0;
/* Start with first scan line in image. */
scan_y = 0;
/* Foreach row of blocks in IMAP... */
for(blk_y = 0; blk_y < mh; blk_y++){
/* Reset to beginning of new block row. */
scan_x = 0;
/* Foreach block in current IMAP row... */
for(blk_x = 0; blk_x < mw; blk_x++){
/* If IMAP is VALID ... */
if(imap[blk_i] != INVALID_DIR){
/* Choose the feature scan direction based on the block's */
/* VALID IMAP direction. The scan direction will either */
/* be HORIZONTAL or VERTICAL. */
scan_dir = choose_scan_direction(imap[blk_i],
lfsparms->num_directions);
/* Set width of scan region. The image may not be an even */
/* multiple of "blocksize" in width and height, so we must */
/* account for this. */
/* Bump right by "blocksize" pixels, but not beyond the */
/* image boundary. */
scan_w = min(scan_x+lfsparms->blocksize, iw);
/* Make the resulting width relative to the region's starting */
/* x-pixel column. */
scan_w -= scan_x;
/* Bump down by "blocksize" pixels, but not beyond the */
/* image boundary. */
scan_h = min(scan_y+lfsparms->blocksize, ih);
/* Make the resulting height relative to the region's starting */
/* y-pixel row. */
scan_h -= scan_y;
/* Scan the defined region for minutia features. */
if((ret = scan4minutiae(minutiae, bdata, iw, ih,
imap, nmap, blk_x, blk_y, mw, mh,
scan_x, scan_y, scan_w, scan_h, scan_dir,
lfsparms))){
/* Return code may be: */
/* 1. ret<0 (implying system error) */
return(ret);
}
} /* Otherwise, IMAP is INVALID, so ignore the block. This seems */
/* quite drastic! */
/* Advance to the next IMAP block in the row in the image. */
scan_x += lfsparms->blocksize;
/* Advance to the next IMAP block in the row. */
blk_i++;
} /* End foreach blk_x */
/* Advance to the next IMAP row in the image. */
scan_y += lfsparms->blocksize;
} /* End foreach blk_y */
/* Return normally. */
return(0);
}
/************************************************************************* /*************************************************************************
************************************************************************** **************************************************************************
#cat: detect_minutiae_V2 - Takes a binary image and its associated #cat: detect_minutiae_V2 - Takes a binary image and its associated

View file

@ -1,60 +0,0 @@
/*******************************************************************************
License:
This software 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. NIST assumes no responsibility whatsoever for
its use by other parties, and makes no guarantees, expressed or implied,
about its quality, reliability, or any other characteristic.
Disclaimer:
This software 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.
*******************************************************************************/
/***********************************************************************
LIBRARY: LFS - NIST Latent Fingerprint System
FILE: MYTIME.C
AUTHOR: Michael D. Garris
DATE: 03/16/1999
Contains global variable definitions used to record timings by
the NIST Latent Fingerprint System (LFS).
***********************************************************************/
/* Total time: including all initializations */
/* : excluding all I/O except for required HO39 input image */
/* (This is done to contrast the fact that the NIST GENHO39 */
/* eliminates the need for this extra read.) */
unsigned long total_timer;
float total_time = 0.0; /* time accumulator */
/* IMAP generation time: excluding initialization */
unsigned long imap_timer;
float imap_time = 0.0; /* time accumulator */
/* Binarization time: excluding initialization */
unsigned long bin_timer;
float bin_time = 0.0; /* time accumulator */
/* Minutia Detection time */
unsigned long minutia_timer;
float minutia_time = 0.0; /* time accumulator */
/* Minutia Removal time */
unsigned long rm_minutia_timer;
float rm_minutia_time = 0.0; /* time accumulator */
/* Neighbor Ridge Counting time */
unsigned long ridge_count_timer;
float ridge_count_time = 0.0; /* time accumulator */

View file

@ -35,15 +35,14 @@ identified are necessarily the best available for the purpose.
*********************************************************************** ***********************************************************************
ROUTINES: ROUTINES:
remove_false_minutia()
remove_false_minutia_V2() remove_false_minutia_V2()
remove_holes() remove_holes()
remove_hooks() remove_hooks()
remove_hooks_islands_overlaps() remove_hooks_islands_lakes_overlaps()
remove_islands_and_lakes() remove_islands_and_lakes()
remove_malformations() remove_malformations()
remove_near_invblocks() remove_near_invblock()
remove_near_invblocks_V2() remove_near_invblock_V2()
remove_pointing_invblock() remove_pointing_invblock()
remove_pointing_invblock_V2() remove_pointing_invblock_V2()
remove_overlaps() remove_overlaps()
@ -58,169 +57,6 @@ identified are necessarily the best available for the purpose.
#include <lfs.h> #include <lfs.h>
#include <log.h> #include <log.h>
/*************************************************************************
**************************************************************************
#cat: remove_false_minutia - Takes a list of true and false minutiae and
#cat: attempts to detect and remove the false minutiae based
#cat: on a series of tests.
Input:
minutiae - list of true and false minutiae
bdata - binary image data (0==while & 1==black)
iw - width (in pixels) of image
ih - height (in pixels) of image
nmap - IMAP ridge flow matrix with invalid, high-curvature,
and no-valid-neighbor regions identified
mw - width in blocks of the NMAP
mh - height in blocks of the NMAP
lfsparms - parameters and thresholds for controlling LFS
Output:
minutiae - list of pruned minutiae
Return Code:
Zero - successful completion
Negative - system error
**************************************************************************/
int remove_false_minutia(MINUTIAE *minutiae,
unsigned char *bdata, const int iw, const int ih,
int *nmap, const int mw, const int mh,
const LFSPARMS *lfsparms)
{
int ret;
/* Sort minutiae points top-to-bottom and left-to-right. */
if((ret = sort_minutiae_y_x(minutiae, iw, ih))){
return(ret);
}
if((ret = link_minutiae(minutiae, bdata, iw, ih, nmap, mw, mh, lfsparms))){
return(ret);
}
if((ret = remove_hooks_islands_lakes_overlaps(minutiae, bdata, iw, ih,
lfsparms))){
return(ret);
}
if((ret = remove_pointing_invblock(minutiae, nmap, mw, mh, lfsparms))){
return(ret);
}
if((ret = remove_holes(minutiae, bdata, iw, ih, lfsparms))){
return(ret);
}
if((ret = remove_or_adjust_side_minutiae(minutiae,
bdata, iw, ih, lfsparms))){
return(ret);
}
if((ret = remove_near_invblock(minutiae, nmap, mw, mh, lfsparms))){
return(ret);
}
if((ret = remove_pores(minutiae, bdata, iw, ih, nmap, mw, mh, lfsparms))){
return(ret);
}
return(0);
}
/*************************************************************************
**************************************************************************
#cat: remove_false_minutia_V2 - Takes a list of true and false minutiae and
#cat: attempts to detect and remove the false minutiae based
#cat: on a series of tests.
Input:
minutiae - list of true and false minutiae
bdata - binary image data (0==while & 1==black)
iw - width (in pixels) of image
ih - height (in pixels) of image
direction_map - map of image blocks containing directional ridge flow
low_flow_map - map of image blocks flagged as LOW RIDGE FLOW
high_curve_map - map of image blocks flagged as HIGH CURVATURE
mw - width in blocks of the maps
mh - height in blocks of the maps
lfsparms - parameters and thresholds for controlling LFS
Output:
minutiae - list of pruned minutiae
Return Code:
Zero - successful completion
Negative - system error
**************************************************************************/
int remove_false_minutia_V2(MINUTIAE *minutiae,
unsigned char *bdata, const int iw, const int ih,
int *direction_map, int *low_flow_map, int *high_curve_map,
const int mw, const int mh, const LFSPARMS *lfsparms)
{
int ret;
/* 1. Sort minutiae points top-to-bottom and left-to-right. */
if((ret = sort_minutiae_y_x(minutiae, iw, ih))){
return(ret);
}
/* 2. Remove minutiae on lakes (filled with white pixels) and */
/* islands (filled with black pixels), both defined by a pair of */
/* minutia points. */
if((ret = remove_islands_and_lakes(minutiae, bdata, iw, ih, lfsparms))){
return(ret);
}
/* 3. Remove minutiae on holes in the binary image defined by a */
/* single point. */
if((ret = remove_holes(minutiae, bdata, iw, ih, lfsparms))){
return(ret);
}
/* 4. Remove minutiae that point sufficiently close to a block with */
/* INVALID direction. */
if((ret = remove_pointing_invblock_V2(minutiae, direction_map, mw, mh,
lfsparms))){
return(ret);
}
/* 5. Remove minutiae that are sufficiently close to a block with */
/* INVALID direction. */
if((ret = remove_near_invblock_V2(minutiae, direction_map, mw, mh,
lfsparms))){
return(ret);
}
/* 6. Remove or adjust minutiae that reside on the side of a ridge */
/* or valley. */
if((ret = remove_or_adjust_side_minutiae_V2(minutiae, bdata, iw, ih,
direction_map, mw, mh, lfsparms))){
return(ret);
}
/* 7. Remove minutiae that form a hook on the side of a ridge or valley. */
if((ret = remove_hooks(minutiae, bdata, iw, ih, lfsparms))){
return(ret);
}
/* 8. Remove minutiae that are on opposite sides of an overlap. */
if((ret = remove_overlaps(minutiae, bdata, iw, ih, lfsparms))){
return(ret);
}
/* 9. Remove minutiae that are "irregularly" shaped. */
if((ret = remove_malformations(minutiae, bdata, iw, ih,
low_flow_map, mw, mh, lfsparms))){
return(ret);
}
/* 10. Remove minutiae that form long, narrow, loops in the */
/* "unreliable" regions in the binary image. */
if((ret = remove_pores_V2(minutiae, bdata, iw, ih,
direction_map, low_flow_map, high_curve_map,
mw, mh, lfsparms))){
return(ret);
}
return(0);
}
/************************************************************************* /*************************************************************************
************************************************************************** **************************************************************************
#cat: remove_holes - Removes minutia points on small loops around valleys. #cat: remove_holes - Removes minutia points on small loops around valleys.
@ -237,7 +73,7 @@ int remove_false_minutia_V2(MINUTIAE *minutiae,
Zero - successful completion Zero - successful completion
Negative - system error Negative - system error
**************************************************************************/ **************************************************************************/
int remove_holes(MINUTIAE *minutiae, static int remove_holes(MINUTIAE *minutiae,
unsigned char *bdata, const int iw, const int ih, unsigned char *bdata, const int iw, const int ih,
const LFSPARMS *lfsparms) const LFSPARMS *lfsparms)
{ {
@ -308,7 +144,7 @@ int remove_holes(MINUTIAE *minutiae,
Zero - successful completion Zero - successful completion
Negative - system error Negative - system error
**************************************************************************/ **************************************************************************/
int remove_hooks(MINUTIAE *minutiae, static int remove_hooks(MINUTIAE *minutiae,
unsigned char *bdata, const int iw, const int ih, unsigned char *bdata, const int iw, const int ih,
const LFSPARMS *lfsparms) const LFSPARMS *lfsparms)
{ {
@ -532,7 +368,7 @@ int remove_hooks(MINUTIAE *minutiae,
Zero - successful completion Zero - successful completion
Negative - system error Negative - system error
**************************************************************************/ **************************************************************************/
int remove_hooks_islands_lakes_overlaps(MINUTIAE *minutiae, static int remove_hooks_islands_lakes_overlaps(MINUTIAE *minutiae,
unsigned char *bdata, const int iw, const int ih, unsigned char *bdata, const int iw, const int ih,
const LFSPARMS *lfsparms) const LFSPARMS *lfsparms)
{ {
@ -827,7 +663,7 @@ int remove_hooks_islands_lakes_overlaps(MINUTIAE *minutiae,
Zero - successful completion Zero - successful completion
Negative - system error Negative - system error
**************************************************************************/ **************************************************************************/
int remove_islands_and_lakes(MINUTIAE *minutiae, static int remove_islands_and_lakes(MINUTIAE *minutiae,
unsigned char *bdata, const int iw, const int ih, unsigned char *bdata, const int iw, const int ih,
const LFSPARMS *lfsparms) const LFSPARMS *lfsparms)
{ {
@ -1081,7 +917,7 @@ int remove_islands_and_lakes(MINUTIAE *minutiae,
Zero - successful completion Zero - successful completion
Negative - system error Negative - system error
**************************************************************************/ **************************************************************************/
int remove_malformations(MINUTIAE *minutiae, static int remove_malformations(MINUTIAE *minutiae,
unsigned char *bdata, const int iw, const int ih, unsigned char *bdata, const int iw, const int ih,
int *low_flow_map, const int mw, const int mh, int *low_flow_map, const int mw, const int mh,
const LFSPARMS *lfsparms) const LFSPARMS *lfsparms)
@ -1287,7 +1123,7 @@ int remove_malformations(MINUTIAE *minutiae,
Zero - successful completion Zero - successful completion
Negative - system error Negative - system error
**************************************************************************/ **************************************************************************/
int remove_near_invblock(MINUTIAE *minutiae, int *nmap, static int remove_near_invblock(MINUTIAE *minutiae, int *nmap,
const int mw, const int mh, const LFSPARMS *lfsparms) const int mw, const int mh, const LFSPARMS *lfsparms)
{ {
int i, ret; int i, ret;
@ -1517,7 +1353,7 @@ int remove_near_invblock(MINUTIAE *minutiae, int *nmap,
Zero - successful completion Zero - successful completion
Negative - system error Negative - system error
**************************************************************************/ **************************************************************************/
int remove_near_invblock_V2(MINUTIAE *minutiae, int *direction_map, static int remove_near_invblock_V2(MINUTIAE *minutiae, int *direction_map,
const int mw, const int mh, const LFSPARMS *lfsparms) const int mw, const int mh, const LFSPARMS *lfsparms)
{ {
int i, ret; int i, ret;
@ -1747,7 +1583,7 @@ int remove_near_invblock_V2(MINUTIAE *minutiae, int *direction_map,
Zero - successful completion Zero - successful completion
Negative - system error Negative - system error
**************************************************************************/ **************************************************************************/
int remove_pointing_invblock(MINUTIAE *minutiae, static int remove_pointing_invblock(MINUTIAE *minutiae,
int *nmap, const int mw, const int mh, int *nmap, const int mw, const int mh,
const LFSPARMS *lfsparms) const LFSPARMS *lfsparms)
{ {
@ -1839,7 +1675,7 @@ int remove_pointing_invblock(MINUTIAE *minutiae,
Zero - successful completion Zero - successful completion
Negative - system error Negative - system error
**************************************************************************/ **************************************************************************/
int remove_pointing_invblock_V2(MINUTIAE *minutiae, static int remove_pointing_invblock_V2(MINUTIAE *minutiae,
int *direction_map, const int mw, const int mh, int *direction_map, const int mw, const int mh,
const LFSPARMS *lfsparms) const LFSPARMS *lfsparms)
{ {
@ -1929,7 +1765,7 @@ int remove_pointing_invblock_V2(MINUTIAE *minutiae,
Zero - successful completion Zero - successful completion
Negative - system error Negative - system error
**************************************************************************/ **************************************************************************/
int remove_overlaps(MINUTIAE *minutiae, static int remove_overlaps(MINUTIAE *minutiae,
unsigned char *bdata, const int iw, const int ih, unsigned char *bdata, const int iw, const int ih,
const LFSPARMS *lfsparms) const LFSPARMS *lfsparms)
{ {
@ -2160,7 +1996,7 @@ int remove_overlaps(MINUTIAE *minutiae,
Zero - successful completion Zero - successful completion
Negative - system error Negative - system error
**************************************************************************/ **************************************************************************/
int remove_pores(MINUTIAE *minutiae, static int remove_pores(MINUTIAE *minutiae,
unsigned char *bdata, const int iw, const int ih, unsigned char *bdata, const int iw, const int ih,
int *nmap, const int mw, const int mh, int *nmap, const int mw, const int mh,
const LFSPARMS *lfsparms) const LFSPARMS *lfsparms)
@ -2548,7 +2384,7 @@ int remove_pores(MINUTIAE *minutiae,
Zero - successful completion Zero - successful completion
Negative - system error Negative - system error
**************************************************************************/ **************************************************************************/
int remove_pores_V2(MINUTIAE *minutiae, static int remove_pores_V2(MINUTIAE *minutiae,
unsigned char *bdata, const int iw, const int ih, unsigned char *bdata, const int iw, const int ih,
int *direction_map, int *low_flow_map, int *direction_map, int *low_flow_map,
int *high_curve_map, const int mw, const int mh, int *high_curve_map, const int mw, const int mh,
@ -2936,7 +2772,7 @@ int remove_pores_V2(MINUTIAE *minutiae,
Zero - successful completion Zero - successful completion
Negative - system error Negative - system error
**************************************************************************/ **************************************************************************/
int remove_or_adjust_side_minutiae(MINUTIAE *minutiae, static int remove_or_adjust_side_minutiae(MINUTIAE *minutiae,
unsigned char *bdata, const int iw, const int ih, unsigned char *bdata, const int iw, const int ih,
const LFSPARMS *lfsparms) const LFSPARMS *lfsparms)
{ {
@ -3156,7 +2992,7 @@ int remove_or_adjust_side_minutiae(MINUTIAE *minutiae,
Zero - successful completion Zero - successful completion
Negative - system error Negative - system error
**************************************************************************/ **************************************************************************/
int remove_or_adjust_side_minutiae_V2(MINUTIAE *minutiae, static int remove_or_adjust_side_minutiae_V2(MINUTIAE *minutiae,
unsigned char *bdata, const int iw, const int ih, unsigned char *bdata, const int iw, const int ih,
int *direction_map, const int mw, const int mh, int *direction_map, const int mw, const int mh,
const LFSPARMS *lfsparms) const LFSPARMS *lfsparms)
@ -3402,3 +3238,99 @@ int remove_or_adjust_side_minutiae_V2(MINUTIAE *minutiae,
return(0); return(0);
} }
/*************************************************************************
**************************************************************************
#cat: remove_false_minutia_V2 - Takes a list of true and false minutiae and
#cat: attempts to detect and remove the false minutiae based
#cat: on a series of tests.
Input:
minutiae - list of true and false minutiae
bdata - binary image data (0==while & 1==black)
iw - width (in pixels) of image
ih - height (in pixels) of image
direction_map - map of image blocks containing directional ridge flow
low_flow_map - map of image blocks flagged as LOW RIDGE FLOW
high_curve_map - map of image blocks flagged as HIGH CURVATURE
mw - width in blocks of the maps
mh - height in blocks of the maps
lfsparms - parameters and thresholds for controlling LFS
Output:
minutiae - list of pruned minutiae
Return Code:
Zero - successful completion
Negative - system error
**************************************************************************/
int remove_false_minutia_V2(MINUTIAE *minutiae,
unsigned char *bdata, const int iw, const int ih,
int *direction_map, int *low_flow_map, int *high_curve_map,
const int mw, const int mh, const LFSPARMS *lfsparms)
{
int ret;
/* 1. Sort minutiae points top-to-bottom and left-to-right. */
if((ret = sort_minutiae_y_x(minutiae, iw, ih))){
return(ret);
}
/* 2. Remove minutiae on lakes (filled with white pixels) and */
/* islands (filled with black pixels), both defined by a pair of */
/* minutia points. */
if((ret = remove_islands_and_lakes(minutiae, bdata, iw, ih, lfsparms))){
return(ret);
}
/* 3. Remove minutiae on holes in the binary image defined by a */
/* single point. */
if((ret = remove_holes(minutiae, bdata, iw, ih, lfsparms))){
return(ret);
}
/* 4. Remove minutiae that point sufficiently close to a block with */
/* INVALID direction. */
if((ret = remove_pointing_invblock_V2(minutiae, direction_map, mw, mh,
lfsparms))){
return(ret);
}
/* 5. Remove minutiae that are sufficiently close to a block with */
/* INVALID direction. */
if((ret = remove_near_invblock_V2(minutiae, direction_map, mw, mh,
lfsparms))){
return(ret);
}
/* 6. Remove or adjust minutiae that reside on the side of a ridge */
/* or valley. */
if((ret = remove_or_adjust_side_minutiae_V2(minutiae, bdata, iw, ih,
direction_map, mw, mh, lfsparms))){
return(ret);
}
/* 7. Remove minutiae that form a hook on the side of a ridge or valley. */
if((ret = remove_hooks(minutiae, bdata, iw, ih, lfsparms))){
return(ret);
}
/* 8. Remove minutiae that are on opposite sides of an overlap. */
if((ret = remove_overlaps(minutiae, bdata, iw, ih, lfsparms))){
return(ret);
}
/* 9. Remove minutiae that are "irregularly" shaped. */
if((ret = remove_malformations(minutiae, bdata, iw, ih,
low_flow_map, mw, mh, lfsparms))){
return(ret);
}
/* 10. Remove minutiae that form long, narrow, loops in the */
/* "unreliable" regions in the binary image. */
if((ret = remove_pores_V2(minutiae, bdata, iw, ih,
direction_map, low_flow_map, high_curve_map,
mw, mh, lfsparms))){
return(ret);
}
return(0);
}

View file

@ -1,682 +0,0 @@
/*******************************************************************************
License:
This software 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. NIST assumes no responsibility whatsoever for
its use by other parties, and makes no guarantees, expressed or implied,
about its quality, reliability, or any other characteristic.
Disclaimer:
This software 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.
*******************************************************************************/
/***********************************************************************
LIBRARY: LFS - NIST Latent Fingerprint System
FILE: RESULTS.C
AUTHOR: Michael D. Garris
DATE: 03/16/1999
UPDATED: 10/04/1999 Version 2 by MDG
09/14/2004
UPDATED: 03/16/2005 by MDG
Contains routines useful in visualizing intermediate and final
results when exercising the NIST Latent Fingerprint System (LFS).
***********************************************************************
ROUTINES:
write_text_results()
write_minutiae_XYTQ()
dump_map()
drawmap()
drawmap2()
drawblocks()
drawrotgrid()
dump_link_table()
***********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
#include <lfs.h>
#include <sunrast.h>
#include <defs.h>
/*************************************************************************
**************************************************************************
#cat: write_text_results - Takes LFS results including minutiae and image
#cat: maps and writes them to separate formatted text files.
Input:
oroot - root pathname for output files
m1flag - if flag set, write (X,Y,T)'s out to "*.xyt" file according
to M1 (ANSI INCITS 378-2004) minutiae representation
M1 Rep:
1. pixel origin top left
2. direction pointing up the ridge ending or
bifurcaiton valley
NIST Internal Rep:
1. pixel origin bottom left
2. direction pointing out and away from the
ridge ending or bifurcation valley
iw - image pixel width
ih - image pixel height
minutiae - structure containing the detected minutiae
quality_map - integrated image quality map
direction_map - direction map
low_contrast_map - low contrast map
low_flow_map - low ridge flow map
high_curve_map - high curvature map
map_w - width (in blocks) of image maps
map_h - height (in blocks) of image maps
Return Code:
Zero - successful completion
Negative - system error
**************************************************************************/
int write_text_results(char *oroot, const int m1flag,
const int iw, const int ih,
const MINUTIAE *minutiae, int *quality_map,
int *direction_map, int *low_contrast_map,
int *low_flow_map, int *high_curve_map,
const int map_w, const int map_h)
{
FILE *fp;
int ret;
char ofile[MAXPATHLEN];
/* 1. Write Minutiae results to text file "<oroot>.min". */
/* XYT's written in LFS native representation: */
/* 1. pixel coordinates with origin top-left */
/* 2. 11.25 degrees quantized integer orientation */
/* on range [0..31] */
/* 3. minutiae reliability on range [0.0 .. 1.0] */
/* with 0.0 lowest and 1.0 highest reliability */
sprintf(ofile, "%s.%s", oroot, MIN_TXT_EXT);
if((fp = fopen(ofile, "wb")) == (FILE *)NULL){
fprintf(stderr, "ERROR : write_text_results : fopen : %s\n", ofile);
return(-2);
}
/* Print out Image Dimensions Header */
/* !!!! Image dimension header added 09-13-04 !!!! */
fprintf(fp, "Image (w,h) %d %d\n", iw, ih);
/* Print text report from the structure containing detected minutiae. */
dump_minutiae(fp, minutiae);
if(fclose(fp)){
fprintf(stderr, "ERROR : write_text_results : fclose : %s\n", ofile);
return(-3);
}
/* 2. Write just minutiae XYT's & Qualities to text */
/* file "<oroot>.xyt". */
/* */
/* A. If M1 flag set: */
/* XYTQ's written according to M1 (ANSI INCITS */
/* 378-2004) representation: */
/* 1. pixel coordinates with origin top-left */
/* 2. orientation in degrees on range [0..360] */
/* with 0 pointing east and increasing counter */
/* clockwise */
/* 3. direction pointing up the ridge ending or */
/* bifurcaiton valley */
/* 4. minutiae qualities on integer range [0..100] */
/* (non-standard) */
/* */
/* B. If M1 flag NOT set: */
/* XYTQ's written according to NIST internal rep. */
/* 1. pixel coordinates with origin bottom-left */
/* 2. orientation in degrees on range [0..360] */
/* with 0 pointing east and increasing counter */
/* clockwise (same as M1) */
/* 3. direction pointing out and away from the */
/* ridge ending or bifurcation valley */
/* (opposite direction from M1) */
/* 4. minutiae qualities on integer range [0..100] */
/* (non-standard) */
sprintf(ofile, "%s.%s", oroot, XYT_EXT);
if(m1flag){
if((ret = write_minutiae_XYTQ(ofile, M1_XYT_REP, minutiae, iw, ih))){
return(ret);
}
}
else{
if((ret = write_minutiae_XYTQ(ofile, NIST_INTERNAL_XYT_REP,
minutiae, iw, ih))){
return(ret);
}
}
/* 3. Write Integrated Quality Map results to text file. */
sprintf(ofile, "%s.%s", oroot, QUALITY_MAP_EXT);
if((fp = fopen(ofile, "wb")) == (FILE *)NULL){
fprintf(stderr, "ERROR : write_text_results : fopen : %s\n", ofile);
return(-4);
}
/* Print a text report from the map. */
dump_map(fp, quality_map, map_w, map_h);
if(fclose(fp)){
fprintf(stderr, "ERROR : write_text_results : fclose : %s\n", ofile);
return(-5);
}
/* 4. Write Direction Map results to text file. */
sprintf(ofile, "%s.%s", oroot, DIRECTION_MAP_EXT);
if((fp = fopen(ofile, "wb")) == (FILE *)NULL){
fprintf(stderr, "ERROR : write_text_results : fopen : %s\n", ofile);
return(-6);
}
/* Print a text report from the map. */
dump_map(fp, direction_map, map_w, map_h);
if(fclose(fp)){
fprintf(stderr, "ERROR : write_text_results : fclose : %s\n", ofile);
return(-7);
}
/* 5. Write Low Contrast Map results to text file. */
sprintf(ofile, "%s.%s", oroot, LOW_CONTRAST_MAP_EXT);
if((fp = fopen(ofile, "wb")) == (FILE *)NULL){
fprintf(stderr, "ERROR : write_text_results : fopen : %s\n", ofile);
return(-8);
}
/* Print a text report from the map. */
dump_map(fp, low_contrast_map, map_w, map_h);
if(fclose(fp)){
fprintf(stderr, "ERROR : write_text_results : fclose : %s\n", ofile);
return(-9);
}
/* 6. Write Low Flow Map results to text file. */
sprintf(ofile, "%s.%s", oroot, LOW_FLOW_MAP_EXT);
if((fp = fopen(ofile, "wb")) == (FILE *)NULL){
fprintf(stderr, "ERROR : write_text_results : fopen : %s\n", ofile);
return(-10);
}
/* Print a text report from the map. */
dump_map(fp, low_flow_map, map_w, map_h);
if(fclose(fp)){
fprintf(stderr, "ERROR : write_text_results : fclose : %s\n", ofile);
return(-11);
}
/* 7. Write High Curvature Map results to text file. */
sprintf(ofile, "%s.%s", oroot, HIGH_CURVE_MAP_EXT);
if((fp = fopen(ofile, "wb")) == (FILE *)NULL){
fprintf(stderr, "ERROR : write_text_results : fopen : %s\n", ofile);
return(-12);
}
/* Print a text report from the map. */
dump_map(fp, high_curve_map, map_w, map_h);
if(fclose(fp)){
fprintf(stderr, "ERROR : write_text_results : fclose : %s\n", ofile);
return(-13);
}
/* Return normally. */
return(0);
}
/*************************************************************************
**************************************************************************
#cat: write_minutiae_XYTQ - Write just minutiae XYT's & Qualities to text
#cat: file according to the specified mintuiae represenation
Input:
ofile - output file name
reptype - specifies XYT output representation
minutiae - structure containing a list of LFS detected minutiae
iw - width (in pixels) of the input image
ih - height (in pixels) of the input image
Return Code:
Zero - successful completion
Negative - system error
**************************************************************************/
int write_minutiae_XYTQ(char *ofile, const int reptype,
const MINUTIAE *minutiae, const int iw, const int ih)
{
FILE *fp;
int i, ox, oy, ot, oq;
MINUTIA *minutia;
/* A. If M1 flag set: */
/* XYTQ's written according to M1 (ANSI INCITS */
/* 378-2004) representation: */
/* 1. pixel coordinates with origin top-left */
/* 2. orientation in degrees on range [0..360] */
/* with 0 pointing east and increasing counter */
/* clockwise */
/* 3. direction pointing up the ridge ending or */
/* bifurcaiton valley */
/* 4. minutiae qualities on integer range [0..100] */
/* (non-standard) */
/* */
/* B. If M1 flag NOT set: */
/* XYTQ's written according to NIST internal rep. */
/* 1. pixel coordinates with origin bottom-left */
/* 2. orientation in degrees on range [0..360] */
/* with 0 pointing east and increasing counter */
/* clockwise (same as M1) */
/* 3. direction pointing out and away from the */
/* ridge ending or bifurcation valley */
/* (opposite direction from M1) */
/* 4. minutiae qualities on integer range [0..100] */
/* (non-standard) */
if((fp = fopen(ofile, "wb")) == (FILE *)NULL){
fprintf(stderr, "ERROR : write_minutiae_XYTQ : fopen : %s\n", ofile);
return(-2);
}
for(i = 0; i < minutiae->num; i++){
minutia = minutiae->list[i];
switch(reptype){
case M1_XYT_REP:
lfs2m1_minutia_XYT(&ox, &oy, &ot, minutia);
break;
case NIST_INTERNAL_XYT_REP:
lfs2nist_minutia_XYT(&ox, &oy, &ot, minutia, iw, ih);
break;
default:
fprintf(stderr, "ERROR : write_minutiae_XYTQ : ");
fprintf(stderr, "Invalid XYT representation type = %d\n", reptype);
fclose(fp);
return(-4);
}
oq = sround(minutia->reliability * 100.0);
fprintf(fp, "%d %d %d %d\n", ox, oy, ot, oq);
}
if(fclose(fp)){
fprintf(stderr, "ERROR : write_minutiae_XYTQ : fopen : %s\n", ofile);
return(-5);
}
return(0);
}
/*************************************************************************
**************************************************************************
#cat: dump_map - Prints a text report to the specified open file pointer
#cat: of the integer values in a 2D integer vector.
Input:
fpout - open file pointer
map - vector of integer directions (-1 ==> invalid direction)
mw - width (number of blocks) of map vector
mh - height (number of blocks) of map vector
**************************************************************************/
void dump_map(FILE *fpout, int *map, const int mw, const int mh)
{
int mx, my;
int *iptr;
/* Simply print the map matrix out to the specified file pointer. */
iptr = map;
for(my = 0; my < mh; my++){
for(mx = 0; mx < mw; mx++){
fprintf(fpout, "%2d ", *iptr++);
}
fprintf(fpout, "\n");
}
}
/*************************************************************************
**************************************************************************
#cat: drawmap - Draws integer direction vectors over their respective blocks
#cat: of an input image. Note that the input image is modified
#cat: upon return form this routine.
Input:
imap - computed vector of integer directions. (-1 ==> invalid)
mw - width (in blocks) of the map
mh - height (in blocks) of the map
idata - input image data to be annotated
iw - width (in pixels) of the input image
ih - height (in pixels) of the input image
rotgrids - structure containing the rotated pixel grid offsets
draw_pixel - pixel intensity to be used when drawing on the image
Output:
idata - input image contains the results of the annoatation
Return Code:
Zero - successful completion
Negative - system error
**************************************************************************/
int drawmap(int *imap, const int mw, const int mh,
unsigned char *idata, const int iw, const int ih,
const ROTGRIDS *dftgrids, const int draw_pixel)
{
int bi, *iptr;
double dy, dx, xincr, yincr;
int cbxy;
int i, xyoffset;
unsigned char *cptr, *lptr, *rptr, *eptr;
double theta, pi_incr;
int *blkoffs, bw, bh;
int ret; /* return code */
/* Compute block offsets into the input image. */
/* Block_offsets() assumes square block (grid), so ERROR otherwise. */
if(dftgrids->grid_w != dftgrids->grid_h){
fprintf(stderr, "ERROR : drawmap : DFT grids must be square\n");
return(-130);
}
if((ret = block_offsets(&blkoffs, &bw, &bh, iw, ih,
dftgrids->pad, dftgrids->grid_w))){
return(ret);
}
if((bw != mw) || (bh != mh)){
/* Free memory allocated to this point. */
free(blkoffs);
fprintf(stderr,
"ERROR : drawmap : block dimensions between map and image do not match\n");
return(-131);
}
cbxy = dftgrids->grid_w>>1;
pi_incr = M_PI/(double)dftgrids->ngrids;
eptr = idata + (ih*iw);
iptr = imap;
/* Foreach block in image ... */
for(bi = 0; bi < mw*mh; bi++){
/* If valid direction for block ... */
if(*iptr != INVALID_DIR){
/* Get slope components of direction angle */
theta = dftgrids->start_angle + (*iptr * pi_incr);
dx = cos(theta);
dy = sin(theta);
/* Draw line rotated by the direction angle and centered */
/* on the block. */
/* Check if line is perfectly vertical ... */
if(dx == 0){
/* Draw vertical line starting at top of block shifted */
/* over to horizontal center of the block. */
lptr = idata + blkoffs[bi] + cbxy;
for(i = 0; i < dftgrids->grid_w; i++){
if((lptr > idata) && (lptr < eptr)){
*lptr = draw_pixel;
}
lptr += iw;
}
}
else{
cptr = idata + blkoffs[bi] + (cbxy*iw) + cbxy;
/* Draw center pixel */
*cptr = draw_pixel;
/* Draw left and right half of line */
xincr = dx;
yincr = dy;
for(i = 0; i < cbxy; i++){
xyoffset = (sround(yincr)*iw) + sround(xincr);
rptr = cptr + xyoffset;
if((rptr > idata) && (rptr < eptr)){
*rptr = draw_pixel;
}
lptr = cptr - xyoffset;
if((lptr > idata) && (lptr < eptr)){
*lptr = draw_pixel;
}
xincr += dx;
yincr += dy;
}
}
}
iptr++;
}
/* Deallocate working memory */
free(blkoffs);
return(0);
}
/*************************************************************************
**************************************************************************
#cat: drawmap2 - Draws integer direction vectors over their respective blocks
#cat: of an input image. Note that the input image is modified
#cat: upon return form this routine. In this version of the
#cat: routine, offsets to the origin of each block in the image
#cat: must be precomputed and passed in.
Input:
imap - computed vector of integer directions. (-1 ==> invalid)
blkoffs - list of pixel offsets to the origin of each block in the
image from which the map was computed
mw - width (in blocks) of the map
mh - height (in blocks) of the map
pdata - input image data to be annotated
pw - width (in pixels) of the input image
ph - height (in pixels) of the input image
start_angle - the angle (in radians) that the direction 0 points in
ndirs - number of directions within a half circle
blocksize - the dimensions (in pixels) of each block
Output:
pdata - input image contains the results of the annoatation
**************************************************************************/
void drawmap2(int *imap, const int *blkoffs, const int mw, const int mh,
unsigned char *pdata, const int pw, const int ph,
const double start_angle, const int ndirs, const int blocksize)
{
int bi, *iptr;
double dy, dx, xincr, yincr;
int cbxy;
int i, xyoffset;
unsigned char *cptr, *lptr, *rptr, *eptr;
double theta, pi_incr;
cbxy = blocksize>>1;
pi_incr = M_PI/(double)ndirs;
eptr = pdata + (pw*ph);
iptr = imap;
/* Foreach block in image ... */
for(bi = 0; bi < mw*mh; bi++){
/* If valid direction for block ... */
if(*iptr != INVALID_DIR){
/* Get slope components of direction angle */
theta = start_angle + (*iptr * pi_incr);
dx = cos((double)theta);
dy = sin((double)theta);
/* Draw line rotated by the direction angle and centered */
/* on the block. */
/* Check if line is perfectly vertical ... */
if(dx == 0){
/* Draw vertical line starting at top of block shifted */
/* over to horizontal center of the block. */
lptr = pdata + blkoffs[bi] + cbxy;
for(i = 0; i < blocksize; i++){
if((lptr > pdata) && (lptr < eptr))
*lptr = 255;
lptr += pw;
}
}
else{
cptr = pdata + blkoffs[bi] + (cbxy*pw) + cbxy;
/* Draw center pixel */
*cptr = 255;
/* Draw left and right half of line */
xincr = dx;
yincr = dy;
for(i = 0; i < cbxy; i++){
xyoffset = (sround(yincr)*pw) + sround(xincr);
rptr = cptr + xyoffset;
if((rptr > pdata) && (rptr < eptr))
*rptr = 255;
lptr = cptr - xyoffset;
if((lptr > pdata) && (lptr < eptr))
*lptr = 255;
xincr += dx;
yincr += dy;
}
}
}
iptr++;
}
}
/*************************************************************************
**************************************************************************
#cat: drawblocks - Annotates an input image with the location of each block's
#cat: origin. This routine is useful to see how blocks are
#cat: assigned to arbitrarily-sized images that are not an even
#cat: width or height of the block size. In these cases the last
#cat: column pair and row pair of blocks overlap each other.
#cat: Note that the input image is modified upon return form
#cat: this routine.
Input:
blkoffs - offsets to the pixel origin of each block in the image
mw - number of blocks horizontally in the input image
mh - number of blocks vertically in the input image
pdata - input image data to be annotated that has pixel dimensions
compatible with the offsets in blkoffs
pw - width (in pixels) of the input image
ph - height (in pixels) of the input image
draw_pixel - pixel intensity to be used when drawing on the image
Output:
pdata - input image contains the results of the annoatation
**************************************************************************/
void drawblocks(const int *blkoffs, const int mw, const int mh,
unsigned char *pdata, const int pw, const int ph,
const int draw_pixel)
{
int bi;
unsigned char *bptr;
for(bi = 0; bi < mw*mh; bi++){
bptr = pdata + blkoffs[bi];
*bptr = draw_pixel;
}
}
/*************************************************************************
**************************************************************************
#cat: drawrotgrid - Annotates an input image with a specified rotated grid.
#cat: This routine is useful to see the location and orientation
#cat: of a specific rotated grid within a specific block in the
#cat: image. Note that the input image is modified upon return
#cat: form this routine.
Input:
rotgrids - structure containing the rotated pixel grid offsets
dir - integer direction of the rotated grid to be annontated
idata - input image data to be annotated.
blkoffset - the pixel offset from the origin of the input image to
the origin of the specific block to be annoted
iw - width (in pixels) of the input image
ih - height (in pixels) of the input image
draw_pixel - pixel intensity to be used when drawing on the image
Return Code:
Zero - successful completion
Negative - system error
**************************************************************************/
int drawrotgrid(const ROTGRIDS *rotgrids, const int dir,
unsigned char *idata, const int blkoffset,
const int iw, const int ih, const int draw_pixel)
{
int i, j, gi;
/* Check if specified rotation direction is within range of */
/* rotated grids. */
if(dir >= rotgrids->ngrids){
fprintf(stderr,
"ERROR : drawrotgrid : input direction exceeds range of rotated grids\n");
return(-140);
}
/* Intialize grid offset index */
gi = 0;
/* Foreach row in rotated grid ... */
for(i = 0; i < rotgrids->grid_h; i++){
/* Foreach column in rotated grid ... */
for(j = 0; j < rotgrids->grid_w; j++){
/* Draw pixels from every other rotated row to represent direction */
/* of line sums used in DFT processing. */
if(i%2)
*(idata+blkoffset+rotgrids->grids[dir][gi]) = draw_pixel;
/* Bump grid offset index */
gi++;
}
}
return(0);
}
/*************************************************************************
**************************************************************************
#cat: dump_link_table - takes a link table and vectors of minutia IDs
#cat: assigned to its axes and prints the table's contents out
#cat: as formatted text to the specified open file pointer.
Input:
fpout - open file pointer
link_table - sparse 2D table containing scores of potentially linked
minutia pairs
x_axis - minutia IDs registered along x-axis
y_axis - minutia IDs registered along y-axis
nx_axis - number of minutia registered along x-axis
ny_axis - number of minutia registered along y-axis
tbldim - dimension of each axes of the link table
minutiae - list of minutia points
**************************************************************************/
void dump_link_table(FILE *fpout, const int *link_table,
const int *x_axis, const int *y_axis,
const int nx_axis, const int ny_axis, const int tbldim,
const MINUTIAE *minutiae)
{
int i, tx, ty, sentry, entry;
fprintf(fpout, "DUMP LINK TABLE:\n");
fprintf(fpout, "X-AXIS:\n");
for(i = 0; i < nx_axis; i++){
fprintf(fpout, "%d: %d,%d\n", i, minutiae->list[x_axis[i]]->x,
minutiae->list[x_axis[i]]->y);
}
fprintf(fpout, "Y-AXIS:\n");
for(i = 0; i < ny_axis; i++){
fprintf(fpout, "%d: %d,%d\n", i, minutiae->list[y_axis[i]]->x,
minutiae->list[y_axis[i]]->y);
}
fprintf(fpout, "TABLE:\n");
sentry = 0;
for(ty = 0; ty < ny_axis; ty++){
entry = sentry;
for(tx = 0; tx < nx_axis; tx++){
fprintf(fpout, "%7d ", link_table[entry++]);
}
fprintf(fpout, "\n");
sentry += tbldim;
}
}

View file

@ -36,7 +36,6 @@ identified are necessarily the best available for the purpose.
ROUTINES: ROUTINES:
alloc_shape() alloc_shape()
free_shape() free_shape()
dump_shape()
shape_from_contour() shape_from_contour()
sort_row_on_x() sort_row_on_x()
***********************************************************************/ ***********************************************************************/
@ -61,7 +60,7 @@ identified are necessarily the best available for the purpose.
Zero - Shape successfully allocated and initialized Zero - Shape successfully allocated and initialized
Negative - System error Negative - System error
**************************************************************************/ **************************************************************************/
int alloc_shape(SHAPE **oshape, const int xmin, const int ymin, static int alloc_shape(SHAPE **oshape, const int xmin, const int ymin,
const int xmax, const int ymax) const int xmax, const int ymax)
{ {
SHAPE *shape; SHAPE *shape;
@ -181,33 +180,20 @@ void free_shape(SHAPE *shape)
/************************************************************************* /*************************************************************************
************************************************************************** **************************************************************************
#cat: dump_shape - Takes an initialized shape structure and dumps its contents #cat: sort_row_on_x - Takes a row structure and sorts its points left-to-
#cat: as formatted text to the specified open file pointer. #cat: right on X.
Input: Input:
shape - shape structure to be dumped row - row structure to be sorted
Output: Output:
fpout - open file pointer to be written to row - row structure with points in sorted order
**************************************************************************/ **************************************************************************/
void dump_shape(FILE *fpout, const SHAPE *shape) static void sort_row_on_x(ROW *row)
{ {
int i, j; /* Conduct a simple increasing bubble sort on the x-coords */
/* in the given row. A bubble sort is satisfactory as the */
/* Print the shape's y-limits and number of scanlines. */ /* number of points will be relatively small. */
fprintf(fpout, "shape: ymin=%d, ymax=%d, nrows=%d\n", bubble_sort_int_inc(row->xs, row->npts);
shape->ymin, shape->ymax, shape->nrows);
/* Foreach row in the shape... */
for(i = 0; i < shape->nrows; i++){
/* Print the current row's y-coord and number of points on the row. */
fprintf(fpout, "row %d : y=%d, npts=%d\n", i, shape->rows[i]->y,
shape->rows[i]->npts);
/* Print each successive point on the current row. */
for(j = 0; j < shape->rows[i]->npts; j++){
fprintf(fpout, "pt %d : %d %d\n", j, shape->rows[i]->xs[j],
shape->rows[i]->y);
}
}
} }
/************************************************************************* /*************************************************************************
@ -284,21 +270,3 @@ int shape_from_contour(SHAPE **oshape, const int *contour_x,
return(0); return(0);
} }
/*************************************************************************
**************************************************************************
#cat: sort_row_on_x - Takes a row structure and sorts its points left-to-
#cat: right on X.
Input:
row - row structure to be sorted
Output:
row - row structure with points in sorted order
**************************************************************************/
void sort_row_on_x(ROW *row)
{
/* Conduct a simple increasing bubble sort on the x-coords */
/* in the given row. A bubble sort is satisfactory as the */
/* number of points will be relatively small. */
bubble_sort_int_inc(row->xs, row->npts);
}