NBIS cleanup
Part 1 of many. Remove some unused/pointless code, and made some code static.
This commit is contained in:
parent
6b8d17ef26
commit
4e5cfdf92a
15 changed files with 405 additions and 2442 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -20,3 +20,4 @@ depcomp
|
|||
install-sh
|
||||
.deps
|
||||
.libs
|
||||
compile
|
||||
|
|
|
@ -33,10 +33,8 @@ NBIS_SRC = \
|
|||
nbis/mindtct/matchpat.c \
|
||||
nbis/mindtct/minutia.c \
|
||||
nbis/mindtct/morph.c \
|
||||
nbis/mindtct/mytime.c \
|
||||
nbis/mindtct/quality.c \
|
||||
nbis/mindtct/remove.c \
|
||||
nbis/mindtct/results.c \
|
||||
nbis/mindtct/ridges.c \
|
||||
nbis/mindtct/shape.c \
|
||||
nbis/mindtct/sort.c \
|
||||
|
|
|
@ -701,24 +701,15 @@ typedef struct lfsparms{
|
|||
/*************************************************************************/
|
||||
|
||||
/* 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 *,
|
||||
unsigned char *, const int, const int,
|
||||
int *, const int, const int,
|
||||
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 *,
|
||||
unsigned char *, const int, const int,
|
||||
const int *, const int, const int,
|
||||
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 */
|
||||
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);
|
||||
|
||||
/* 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 **,
|
||||
int **, int **, int **, int **, 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,
|
||||
const int, const int, const DFTWAVES *,
|
||||
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 **,
|
||||
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 */
|
||||
extern void free_dir2rad(DIR2RAD *);
|
||||
|
@ -818,7 +798,6 @@ extern int search_in_direction(int *, int *, int *, int *, const int,
|
|||
/* init.c */
|
||||
extern int init_dir2rad(DIR2RAD **, 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 init_rotgrids(ROTGRIDS **, 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 */
|
||||
extern int line_points(int **, int **, 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 */
|
||||
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,
|
||||
unsigned char *, const int, const int,
|
||||
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,
|
||||
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 */
|
||||
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 *);
|
||||
extern int gen_high_curve_map(int **, int *, const int, const int,
|
||||
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,
|
||||
unsigned char *, const int, const int,
|
||||
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 void smooth_imap(int *, const int, const int, const DIR2RAD *,
|
||||
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,
|
||||
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 */
|
||||
extern int alloc_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 *,
|
||||
unsigned char *, 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,
|
||||
int *, int *, int *, const int, const int,
|
||||
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 */
|
||||
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);
|
||||
|
||||
/* shape.c */
|
||||
extern int alloc_shape(SHAPE **, const int, const int, const int, const int);
|
||||
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 void sort_row_on_x(ROW *);
|
||||
|
||||
/* sort.c */
|
||||
extern int sort_indices_int_inc(int **, int *, const int);
|
||||
|
|
|
@ -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
|
||||
|
|
@ -36,12 +36,9 @@ identified are necessarily the best available for the purpose.
|
|||
|
||||
***********************************************************************
|
||||
ROUTINES:
|
||||
binarize()
|
||||
binarize_V2()
|
||||
binarize_image()
|
||||
binarize_image_V2()
|
||||
dirbinarize()
|
||||
isobinarize()
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
|
@ -49,58 +46,6 @@ identified are necessarily the best available for the purpose.
|
|||
#include <stdlib.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
|
||||
|
@ -156,89 +101,6 @@ int binarize_V2(unsigned char **odata, int *ow, int *oh,
|
|||
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
|
||||
|
@ -385,71 +247,3 @@ int dirbinarize(const unsigned char *pptr, const int idir,
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ identified are necessarily the best available for the purpose.
|
|||
|
||||
***********************************************************************
|
||||
ROUTINES:
|
||||
lfs_detect_minutiae()
|
||||
lfs_detect_minutiae_V2()
|
||||
|
||||
***********************************************************************/
|
||||
|
@ -43,330 +42,8 @@ identified are necessarily the best available for the purpose.
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <lfs.h>
|
||||
#include <mytime.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: arbitrary size), and returns a set of image block maps,
|
||||
|
@ -421,8 +98,6 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
|
|||
int ret, maxpad;
|
||||
MINUTIAE *minutiae;
|
||||
|
||||
set_timer(total_timer);
|
||||
|
||||
/******************/
|
||||
/* INITIALIZATION */
|
||||
/******************/
|
||||
|
@ -505,7 +180,6 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
|
|||
/******************/
|
||||
/* MAPS */
|
||||
/******************/
|
||||
set_timer(imap_timer);
|
||||
|
||||
/* Generate block maps from the input image. */
|
||||
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");
|
||||
|
||||
time_accum(imap_timer, imap_time);
|
||||
|
||||
/******************/
|
||||
/* BINARIZARION */
|
||||
/******************/
|
||||
set_timer(bin_timer);
|
||||
|
||||
/* Initialize lookup table for pixel offsets to rotated grids */
|
||||
/* used for directional binarization. */
|
||||
|
@ -582,12 +253,9 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
|
|||
|
||||
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]. */
|
||||
|
@ -612,10 +280,6 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
|
|||
return(ret);
|
||||
}
|
||||
|
||||
time_accum(minutia_timer, minutia_time);
|
||||
|
||||
set_timer(rm_minutia_timer);
|
||||
|
||||
if((ret = remove_false_minutia_V2(minutiae, bdata, iw, ih,
|
||||
direction_map, low_flow_map, high_curve_map, mw, mh,
|
||||
lfsparms))){
|
||||
|
@ -632,13 +296,9 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
|
|||
|
||||
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);
|
||||
|
@ -653,8 +313,6 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
|
|||
|
||||
print2log("\nNEIGHBOR RIDGE COUNT DONE\n");
|
||||
|
||||
time_accum(ridge_count_timer, ridge_count_time);
|
||||
|
||||
/******************/
|
||||
/* WRAP-UP */
|
||||
/******************/
|
||||
|
@ -678,28 +336,6 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
|
|||
*obh = bh;
|
||||
*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((ret = close_logfile()))
|
||||
return(ret);
|
||||
|
|
|
@ -47,6 +47,84 @@ identified are necessarily the best available for the purpose.
|
|||
#include <stdlib.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.
|
||||
|
@ -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: 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.
|
||||
#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:
|
||||
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
|
||||
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:
|
||||
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,
|
||||
const int *grid_offsets, const int blocksize)
|
||||
static void get_max_norm(double *powmax, int *powmax_dir,
|
||||
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. */
|
||||
gi = 0;
|
||||
/* Find max power value and store corresponding direction */
|
||||
max_v = power_vector[0];
|
||||
max_i = 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++;
|
||||
/* 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: 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
|
||||
#cat: sort_dft_waves - Creates a ranked list of DFT wave form statistics
|
||||
#cat: by sorting on the normalized squared maximum power.
|
||||
|
||||
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)
|
||||
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:
|
||||
power - the computed DFT power for the given wave form at the
|
||||
given orientation within the image block
|
||||
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
|
||||
**************************************************************************/
|
||||
void dft_power(double *power, const int *rowsums,
|
||||
const DFTWAVE *wave, const int wavelen)
|
||||
static int sort_dft_waves(int *wis, const double *powmaxs, const double *pownorms,
|
||||
const int nstats)
|
||||
{
|
||||
int i;
|
||||
double cospart, sinpart;
|
||||
double *pownorms2;
|
||||
|
||||
/* 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]);
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Power is the sum of the squared cos and sin components */
|
||||
*power = (cospart * cospart) + (sinpart * sinpart);
|
||||
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);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
|
@ -253,106 +356,3 @@ int dft_power_stats(int *wis, double *powmaxs, int *powmax_dirs,
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ identified are necessarily the best available for the purpose.
|
|||
ROUTINES:
|
||||
init_dir2rad()
|
||||
init_dftwaves()
|
||||
get_max_padding()
|
||||
get_max_padding_V2()
|
||||
init_rotgrids()
|
||||
alloc_dir_powers()
|
||||
|
@ -243,80 +242,6 @@ int init_dftwaves(DFTWAVES **optr, const double *dft_coefs,
|
|||
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
|
||||
|
|
|
@ -46,8 +46,6 @@ identified are necessarily the best available for the purpose.
|
|||
get_loop_aspect()
|
||||
fill_loop()
|
||||
fill_partial_row()
|
||||
flood_loop()
|
||||
flood_fill4()
|
||||
***********************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -499,6 +497,107 @@ int is_loop_clockwise(const int *contour_x, const int *contour_y,
|
|||
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
|
||||
|
@ -845,103 +944,39 @@ int process_loop_V2(MINUTIAE *minutiae,
|
|||
|
||||
/*************************************************************************
|
||||
**************************************************************************
|
||||
#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.
|
||||
#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:
|
||||
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
|
||||
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:
|
||||
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
|
||||
bdata - 8-bit image data with partial row filled.
|
||||
**************************************************************************/
|
||||
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)
|
||||
static 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 halfway, limit;
|
||||
int i, j;
|
||||
double dist;
|
||||
double min_dist, max_dist;
|
||||
int min_i, max_i, min_j, max_j;
|
||||
int x;
|
||||
unsigned char *bptr;
|
||||
|
||||
/* Compute half the perimeter of the loop. */
|
||||
halfway = ncontour>>1;
|
||||
/* Set pixel pointer to starting x-coord on current row. */
|
||||
bptr = bdata+(y*iw)+frx;
|
||||
|
||||
/* 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;
|
||||
/* 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++;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
**************************************************************************
|
||||
#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. */
|
||||
}
|
||||
|
|
|
@ -46,7 +46,6 @@ identified are necessarily the best available for the purpose.
|
|||
pixelize_map()
|
||||
smooth_direction_map()
|
||||
gen_high_curve_map()
|
||||
gen_imap()
|
||||
gen_initial_imap()
|
||||
primary_dir_test()
|
||||
secondary_fork_test()
|
||||
|
@ -59,7 +58,6 @@ identified are necessarily the best available for the purpose.
|
|||
average_8nbr_dir()
|
||||
num_valid_8nbrs()
|
||||
smooth_imap()
|
||||
gen_nmap()
|
||||
vorticity()
|
||||
accum_nbr_vorticity()
|
||||
curvature()
|
||||
|
@ -930,75 +928,6 @@ int gen_high_curve_map(int **ohcmap, int *direction_map,
|
|||
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.
|
||||
|
@ -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
|
||||
|
|
|
@ -37,7 +37,6 @@ identified are necessarily the best available for the purpose.
|
|||
ROUTINES:
|
||||
alloc_minutiae()
|
||||
realloc_minutiae()
|
||||
detect_minutiae()
|
||||
detect_minutiae_V2()
|
||||
update_minutiae()
|
||||
update_minutiae_V2()
|
||||
|
@ -144,99 +143,6 @@ int realloc_minutiae(MINUTIAE *minutiae, const int incr_minutiae)
|
|||
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
|
||||
|
|
|
@ -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 */
|
|
@ -35,15 +35,14 @@ identified are necessarily the best available for the purpose.
|
|||
|
||||
***********************************************************************
|
||||
ROUTINES:
|
||||
remove_false_minutia()
|
||||
remove_false_minutia_V2()
|
||||
remove_holes()
|
||||
remove_hooks()
|
||||
remove_hooks_islands_overlaps()
|
||||
remove_hooks_islands_lakes_overlaps()
|
||||
remove_islands_and_lakes()
|
||||
remove_malformations()
|
||||
remove_near_invblocks()
|
||||
remove_near_invblocks_V2()
|
||||
remove_near_invblock()
|
||||
remove_near_invblock_V2()
|
||||
remove_pointing_invblock()
|
||||
remove_pointing_invblock_V2()
|
||||
remove_overlaps()
|
||||
|
@ -58,169 +57,6 @@ identified are necessarily the best available for the purpose.
|
|||
#include <lfs.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.
|
||||
|
@ -237,7 +73,7 @@ int remove_false_minutia_V2(MINUTIAE *minutiae,
|
|||
Zero - successful completion
|
||||
Negative - system error
|
||||
**************************************************************************/
|
||||
int remove_holes(MINUTIAE *minutiae,
|
||||
static int remove_holes(MINUTIAE *minutiae,
|
||||
unsigned char *bdata, const int iw, const int ih,
|
||||
const LFSPARMS *lfsparms)
|
||||
{
|
||||
|
@ -308,7 +144,7 @@ int remove_holes(MINUTIAE *minutiae,
|
|||
Zero - successful completion
|
||||
Negative - system error
|
||||
**************************************************************************/
|
||||
int remove_hooks(MINUTIAE *minutiae,
|
||||
static int remove_hooks(MINUTIAE *minutiae,
|
||||
unsigned char *bdata, const int iw, const int ih,
|
||||
const LFSPARMS *lfsparms)
|
||||
{
|
||||
|
@ -532,7 +368,7 @@ int remove_hooks(MINUTIAE *minutiae,
|
|||
Zero - successful completion
|
||||
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,
|
||||
const LFSPARMS *lfsparms)
|
||||
{
|
||||
|
@ -827,7 +663,7 @@ int remove_hooks_islands_lakes_overlaps(MINUTIAE *minutiae,
|
|||
Zero - successful completion
|
||||
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,
|
||||
const LFSPARMS *lfsparms)
|
||||
{
|
||||
|
@ -1081,7 +917,7 @@ int remove_islands_and_lakes(MINUTIAE *minutiae,
|
|||
Zero - successful completion
|
||||
Negative - system error
|
||||
**************************************************************************/
|
||||
int remove_malformations(MINUTIAE *minutiae,
|
||||
static int remove_malformations(MINUTIAE *minutiae,
|
||||
unsigned char *bdata, const int iw, const int ih,
|
||||
int *low_flow_map, const int mw, const int mh,
|
||||
const LFSPARMS *lfsparms)
|
||||
|
@ -1287,7 +1123,7 @@ int remove_malformations(MINUTIAE *minutiae,
|
|||
Zero - successful completion
|
||||
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)
|
||||
{
|
||||
int i, ret;
|
||||
|
@ -1517,7 +1353,7 @@ int remove_near_invblock(MINUTIAE *minutiae, int *nmap,
|
|||
Zero - successful completion
|
||||
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)
|
||||
{
|
||||
int i, ret;
|
||||
|
@ -1747,7 +1583,7 @@ int remove_near_invblock_V2(MINUTIAE *minutiae, int *direction_map,
|
|||
Zero - successful completion
|
||||
Negative - system error
|
||||
**************************************************************************/
|
||||
int remove_pointing_invblock(MINUTIAE *minutiae,
|
||||
static int remove_pointing_invblock(MINUTIAE *minutiae,
|
||||
int *nmap, const int mw, const int mh,
|
||||
const LFSPARMS *lfsparms)
|
||||
{
|
||||
|
@ -1839,7 +1675,7 @@ int remove_pointing_invblock(MINUTIAE *minutiae,
|
|||
Zero - successful completion
|
||||
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,
|
||||
const LFSPARMS *lfsparms)
|
||||
{
|
||||
|
@ -1929,7 +1765,7 @@ int remove_pointing_invblock_V2(MINUTIAE *minutiae,
|
|||
Zero - successful completion
|
||||
Negative - system error
|
||||
**************************************************************************/
|
||||
int remove_overlaps(MINUTIAE *minutiae,
|
||||
static int remove_overlaps(MINUTIAE *minutiae,
|
||||
unsigned char *bdata, const int iw, const int ih,
|
||||
const LFSPARMS *lfsparms)
|
||||
{
|
||||
|
@ -2160,7 +1996,7 @@ int remove_overlaps(MINUTIAE *minutiae,
|
|||
Zero - successful completion
|
||||
Negative - system error
|
||||
**************************************************************************/
|
||||
int remove_pores(MINUTIAE *minutiae,
|
||||
static int remove_pores(MINUTIAE *minutiae,
|
||||
unsigned char *bdata, const int iw, const int ih,
|
||||
int *nmap, const int mw, const int mh,
|
||||
const LFSPARMS *lfsparms)
|
||||
|
@ -2548,7 +2384,7 @@ int remove_pores(MINUTIAE *minutiae,
|
|||
Zero - successful completion
|
||||
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,
|
||||
int *direction_map, int *low_flow_map,
|
||||
int *high_curve_map, const int mw, const int mh,
|
||||
|
@ -2936,7 +2772,7 @@ int remove_pores_V2(MINUTIAE *minutiae,
|
|||
Zero - successful completion
|
||||
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,
|
||||
const LFSPARMS *lfsparms)
|
||||
{
|
||||
|
@ -3156,7 +2992,7 @@ int remove_or_adjust_side_minutiae(MINUTIAE *minutiae,
|
|||
Zero - successful completion
|
||||
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,
|
||||
int *direction_map, const int mw, const int mh,
|
||||
const LFSPARMS *lfsparms)
|
||||
|
@ -3402,3 +3238,99 @@ int remove_or_adjust_side_minutiae_V2(MINUTIAE *minutiae,
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -36,7 +36,6 @@ identified are necessarily the best available for the purpose.
|
|||
ROUTINES:
|
||||
alloc_shape()
|
||||
free_shape()
|
||||
dump_shape()
|
||||
shape_from_contour()
|
||||
sort_row_on_x()
|
||||
***********************************************************************/
|
||||
|
@ -61,7 +60,7 @@ identified are necessarily the best available for the purpose.
|
|||
Zero - Shape successfully allocated and initialized
|
||||
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)
|
||||
{
|
||||
SHAPE *shape;
|
||||
|
@ -181,33 +180,20 @@ void free_shape(SHAPE *shape)
|
|||
|
||||
/*************************************************************************
|
||||
**************************************************************************
|
||||
#cat: dump_shape - Takes an initialized shape structure and dumps its contents
|
||||
#cat: as formatted text to the specified open file pointer.
|
||||
#cat: sort_row_on_x - Takes a row structure and sorts its points left-to-
|
||||
#cat: right on X.
|
||||
|
||||
Input:
|
||||
shape - shape structure to be dumped
|
||||
row - row structure to be sorted
|
||||
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;
|
||||
|
||||
/* Print the shape's y-limits and number of scanlines. */
|
||||
fprintf(fpout, "shape: ymin=%d, ymax=%d, nrows=%d\n",
|
||||
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);
|
||||
}
|
||||
}
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
|
@ -284,21 +270,3 @@ int shape_from_contour(SHAPE **oshape, const int *contour_x,
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue