Add bozorth3 from NBIS; implement verify for image devices

uru4000 works splendiferously (YAY!)
aes4000 is going to need some work though :(
This commit is contained in:
Daniel Drake 2007-10-28 00:21:49 +01:00
parent 41b25f28a4
commit 6b8d17ef26
14 changed files with 3260 additions and 27 deletions

6
README
View file

@ -6,6 +6,12 @@ VERSION INCLUDES GPL CODE FROM LIBTHINKFINGER, therefore distribution is
subject to both the terms of the LGPL (see COPYING) *and* the GPL
(see COPYING.GPL).
libfprint includes code from NIST's NBIS software distribution:
http://fingerprint.nist.gov/NBIS/index.html
We include bozorth3 from the US export controlled distribution. We have
determined that it is fine to ship bozorth3 in an open source project,
see http://reactivated.net/fprint/US_export_control
At release time, I will contact libthinkfinger authors and see if they will
be happy to relicense. I expect they will.

2
THANKS
View file

@ -2,3 +2,5 @@ Tony Vroon - hardware donations
Gerrie Mansur from Security Database BV (http://www.securitydatabase.net/) - hardware donations
Joaquin Custodio - hardware donations
TimeTrex (http://www.timetrex.com/) - hardware donations
Craig Watson (NIST)
James Vasile (SFLC)

5
TODO
View file

@ -13,6 +13,11 @@ ID Mouse driver
Support for 2nd generation MS devices
Support for 2nd generation UPEK devices
IMAGING
=======
aes4000 doesn't work very well, maybe due to small minutia count?
PPMM parameter to get_minutiae seems to have no effect
MISC
====
upekts/thinkfinger relicensing (GPL --> LGPL)

View file

@ -7,6 +7,12 @@ AES4000_SRC = drivers/aes4000.c
DRIVER_SRC = $(UPEKTS_SRC) $(URU4000_SRC) $(AES4000_SRC)
NBIS_SRC = \
nbis/bozorth3/bozorth3.c \
nbis/bozorth3/bz_alloc.c \
nbis/bozorth3/bz_drvrs.c \
nbis/bozorth3/bz_gbls.c \
nbis/bozorth3/bz_io.c \
nbis/bozorth3/bz_sort.c \
nbis/mindtct/binar.c \
nbis/mindtct/block.c \
nbis/mindtct/chaincod.c \

View file

@ -180,6 +180,8 @@ struct fp_img *fpi_img_resize(struct fp_img *img, size_t newsize);
gboolean fpi_img_is_sane(struct fp_img *img);
int fpi_img_detect_minutiae(struct fp_img_dev *imgdev, struct fp_img *img,
struct fp_print_data **ret);
int fpi_img_compare_print_data(struct fp_print_data *enrolled_print,
struct fp_print_data *new_print);
#define bswap16(x) (((x & 0xff) << 8) | (x >> 8))
#if __BYTE_ORDER == __LITTLE_ENDIAN

View file

@ -175,24 +175,6 @@ API_EXPORTED void fp_img_standardize(struct fp_img *img)
}
}
static int sort_x_y(const void *a, const void *b)
{
struct minutiae_struct *af = (struct minutiae_struct *) a;
struct minutiae_struct *bf = (struct minutiae_struct *) b;
if (af->col[0] < bf->col[0])
return -1;
if (af->col[0] > bf->col[0])
return 1;
if (af->col[1] < bf->col[1])
return -1;
if (af->col[1] > bf->col[1])
return 1;
return 0;
}
/* Based on write_minutiae_XYTQ and bz_load */
static void minutiae_to_xyt(MINUTIAE *minutiae, int bwidth,
int bheight, unsigned char *buf)
@ -277,3 +259,21 @@ int fpi_img_detect_minutiae(struct fp_img_dev *imgdev, struct fp_img *img,
return r;
}
int fpi_img_compare_print_data(struct fp_print_data *enrolled_print,
struct fp_print_data *new_print)
{
struct xyt_struct *gstruct = (struct xyt_struct *) enrolled_print->buffer;
struct xyt_struct *pstruct = (struct xyt_struct *) new_print->buffer;
GTimer *timer;
int r;
timer = g_timer_new();
r = bozorth_main(pstruct, gstruct);
g_timer_stop(timer);
fp_dbg("bozorth processing took %f seconds, score=%d",
g_timer_elapsed(timer, NULL), r);
g_timer_destroy(timer);
return r;
}

View file

@ -138,7 +138,7 @@ API_EXPORTED int fp_imgdev_capture(struct fp_img_dev *imgdev,
return r;
}
#define MIN_ACCEPTABLE_MINUTIAE 5
#define MIN_ACCEPTABLE_MINUTIAE 10
int img_dev_enroll(struct fp_dev *dev, gboolean initial, int stage,
struct fp_print_data **ret)
@ -170,11 +170,43 @@ int img_dev_enroll(struct fp_dev *dev, gboolean initial, int stage,
return FP_ENROLL_COMPLETE;
}
static int img_dev_verify(struct fp_dev *dev,
struct fp_print_data *enrolled_print)
{
struct fp_img_dev *imgdev = dev->priv;
struct fp_img *img;
struct fp_print_data *print;
int r;
r = fp_imgdev_capture(imgdev, 0, &img);
if (r)
return r;
fp_img_standardize(img);
r = fpi_img_detect_minutiae(imgdev, img, &print);
fp_img_free(img);
if (r < 0)
return r;
if (r < MIN_ACCEPTABLE_MINUTIAE) {
fp_dbg("not enough minutiae, %d/%d", r, MIN_ACCEPTABLE_MINUTIAE);
fp_print_data_free(print);
return FP_VERIFY_RETRY;
}
r = fpi_img_compare_print_data(enrolled_print, print);
fp_print_data_free(print);
if (r >= 40)
return FP_VERIFY_MATCH;
else
return FP_VERIFY_NO_MATCH;
}
void fpi_img_driver_setup(struct fp_img_driver *idriver)
{
idriver->driver.type = DRIVER_IMAGING;
idriver->driver.init = img_dev_init;
idriver->driver.exit = img_dev_exit;
idriver->driver.enroll = img_dev_enroll;
idriver->driver.verify = img_dev_verify;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,119 @@
/******************************************************************************
This file is part of the Export Control subset of the United States NIST
Biometric Image Software (NBIS) distribution:
http://fingerprint.nist.gov/NBIS/index.html
It is our understanding that this falls within ECCN 3D980, which covers
software associated with the development, production or use of certain
equipment controlled in accordance with U.S. concerns about crime control
practices in specific countries.
Therefore, this file should not be exported, or made available on fileservers,
except as allowed by U.S. export control laws.
Do not remove this notice.
******************************************************************************/
/* NOTE: Despite the above notice (which I have not removed), this file is
* being legally distributed within libfprint; the U.S. Export Administration
* Regulations do not place export restrictions upon distribution of
* "publicly available technology and software", as stated in EAR section
* 734.3(b)(3)(i). libfprint qualifies as publicly available technology as per
* the definition in section 734.7(a)(1).
*
* For further information, see http://reactivated.net/fprint/US_export_control
*/
/*******************************************************************************
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: FING - NIST Fingerprint Systems Utilities
FILE: BZ_ALLOC.C
ALGORITHM: Allan S. Bozorth (FBI)
MODIFICATIONS: Michael D. Garris (NIST)
Stan Janet (NIST)
DATE: 09/21/2004
Contains routines responsible for supporting the
Bozorth3 fingerprint matching algorithm.
***********************************************************************
ROUTINES:
#cat: malloc_or_exit - allocates a buffer of bytes from the heap of
#cat: specified length exiting directly upon system error
#cat: malloc_or_return_error - allocates a buffer of bytes from the heap
#cat: of specified length returning an error code upon system error
***********************************************************************/
#include <stdio.h>
#include <string.h>
#include <bozorth.h>
/***********************************************************************/
char * malloc_or_exit( int nbytes, const char * what )
{
char * p;
/* These are now externally defined in bozorth.h */
/* extern FILE * stderr; */
/* extern char * get_progname( void ); */
p = malloc( (size_t) nbytes );
if ( p == CNULL ) {
fprintf( stderr, "%s: ERROR: malloc() of %d bytes for %s failed: %s\n",
get_progname(),
nbytes,
what,
strerror( errno )
);
exit(1);
}
return p;
}
/***********************************************************************/
/* returns CNULL on error */
char * malloc_or_return_error( int nbytes, const char * what )
{
char * p;
p = malloc( (size_t) nbytes );
if ( p == CNULL ) {
fprintf( stderr, "%s: ERROR: malloc() of %d bytes for %s failed: %s\n",
get_progname(),
nbytes,
what,
strerror( errno )
);
return(CNULL);
}
return p;
}

View file

@ -0,0 +1,223 @@
/******************************************************************************
This file is part of the Export Control subset of the United States NIST
Biometric Image Software (NBIS) distribution:
http://fingerprint.nist.gov/NBIS/index.html
It is our understanding that this falls within ECCN 3D980, which covers
software associated with the development, production or use of certain
equipment controlled in accordance with U.S. concerns about crime control
practices in specific countries.
Therefore, this file should not be exported, or made available on fileservers,
except as allowed by U.S. export control laws.
Do not remove this notice.
******************************************************************************/
/* NOTE: Despite the above notice (which I have not removed), this file is
* being legally distributed within libfprint; the U.S. Export Administration
* Regulations do not place export restrictions upon distribution of
* "publicly available technology and software", as stated in EAR section
* 734.3(b)(3)(i). libfprint qualifies as publicly available technology as per
* the definition in section 734.7(a)(1).
*
* For further information, see http://reactivated.net/fprint/US_export_control
*/
/*******************************************************************************
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: FING - NIST Fingerprint Systems Utilities
FILE: BZ_DRVRS.C
ALGORITHM: Allan S. Bozorth (FBI)
MODIFICATIONS: Michael D. Garris (NIST)
Stan Janet (NIST)
DATE: 09/21/2004
Contains driver routines responsible for kicking off matches
using the Bozorth3 fingerprint matching algorithm.
***********************************************************************
ROUTINES:
#cat: bozorth_probe_init - creates the pairwise minutia comparison
#cat: table for the probe fingerprint
#cat: bozorth_gallery_init - creates the pairwise minutia comparison
#cat: table for the gallery fingerprint
#cat: bozorth_to_gallery - supports the matching scenario where the
#cat: same probe fingerprint is matches repeatedly
#cat: to multiple gallery fingerprints as in
#cat: identification mode
#cat: bozorth_main - supports the matching scenario where a
#cat: single probe fingerprint is to be matched
#cat: to a single gallery fingerprint as in
#cat: verificaiton mode
***********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <bozorth.h>
/**************************************************************************/
int bozorth_probe_init( struct xyt_struct * pstruct )
{
int sim; /* number of pointwise comparisons for Subject's record*/
int msim; /* Pruned length of Subject's comparison pointer list */
/* Take Subject's points and compute pointwise comparison statistics table and sorted row-pointer list. */
/* This builds a "Web" of relative edge statistics between points. */
bz_comp(
pstruct->nrows,
pstruct->xcol,
pstruct->ycol,
pstruct->thetacol,
&sim,
scols,
scolpt );
msim = sim; /* Init search to end of Subject's pointwise comparison table (last edge in Web) */
bz_find( &msim, scolpt );
if ( msim < FDD ) /* Makes sure there are a reasonable number of edges (at least 500, if possible) to analyze in the Web */
msim = ( sim > FDD ) ? FDD : sim;
return msim;
}
/**************************************************************************/
int bozorth_gallery_init( struct xyt_struct * gstruct )
{
int fim; /* number of pointwise comparisons for On-File record*/
int mfim; /* Pruned length of On-File Record's pointer list */
/* Take On-File Record's points and compute pointwise comparison statistics table and sorted row-pointer list. */
/* This builds a "Web" of relative edge statistics between points. */
bz_comp(
gstruct->nrows,
gstruct->xcol,
gstruct->ycol,
gstruct->thetacol,
&fim,
fcols,
fcolpt );
mfim = fim; /* Init search to end of On-File Record's pointwise comparison table (last edge in Web) */
bz_find( &mfim, fcolpt );
if ( mfim < FDD ) /* Makes sure there are a reasonable number of edges (at least 500, if possible) to analyze in the Web */
mfim = ( fim > FDD ) ? FDD : fim;
return mfim;
}
/**************************************************************************/
int bozorth_to_gallery(
int probe_len,
struct xyt_struct * pstruct,
struct xyt_struct * gstruct
)
{
int np;
int gallery_len;
gallery_len = bozorth_gallery_init( gstruct );
np = bz_match( probe_len, gallery_len );
return bz_match_score( np, pstruct, gstruct );
}
/**************************************************************************/
int bozorth_main(
struct xyt_struct * pstruct,
struct xyt_struct * gstruct
)
{
int ms;
int np;
int probe_len;
int gallery_len;
#ifdef DEBUG
printf( "PROBE_INIT() called\n" );
#endif
probe_len = bozorth_probe_init( pstruct );
#ifdef DEBUG
printf( "GALLERY_INIT() called\n" );
#endif
gallery_len = bozorth_gallery_init( gstruct );
#ifdef DEBUG
printf( "BZ_MATCH() called\n" );
#endif
np = bz_match( probe_len, gallery_len );
#ifdef DEBUG
printf( "BZ_MATCH() returned %d edge pairs\n", np );
printf( "COMPUTE() called\n" );
#endif
ms = bz_match_score( np, pstruct, gstruct );
#ifdef DEBUG
printf( "COMPUTE() returned %d\n", ms );
#endif
return ms;
}

View file

@ -0,0 +1,113 @@
/******************************************************************************
This file is part of the Export Control subset of the United States NIST
Biometric Image Software (NBIS) distribution:
http://fingerprint.nist.gov/NBIS/index.html
It is our understanding that this falls within ECCN 3D980, which covers
software associated with the development, production or use of certain
equipment controlled in accordance with U.S. concerns about crime control
practices in specific countries.
Therefore, this file should not be exported, or made available on fileservers,
except as allowed by U.S. export control laws.
Do not remove this notice.
******************************************************************************/
/* NOTE: Despite the above notice (which I have not removed), this file is
* being legally distributed within libfprint; the U.S. Export Administration
* Regulations do not place export restrictions upon distribution of
* "publicly available technology and software", as stated in EAR section
* 734.3(b)(3)(i). libfprint qualifies as publicly available technology as per
* the definition in section 734.7(a)(1).
*
* For further information, see http://reactivated.net/fprint/US_export_control
*/
/*******************************************************************************
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: FING - NIST Fingerprint Systems Utilities
FILE: BZ_GBLS.C
ALGORITHM: Allan S. Bozorth (FBI)
MODIFICATIONS: Michael D. Garris (NIST)
Stan Janet (NIST)
DATE: 09/21/2004
Contains global variables responsible for supporting the
Bozorth3 fingerprint matching "core" algorithm.
***********************************************************************
***********************************************************************/
#include <bozorth.h>
/**************************************************************************/
/* General supporting global variables */
/**************************************************************************/
int colp[ COLP_SIZE_1 ][ COLP_SIZE_2 ]; /* Output from match(), this is a sorted table of compatible edge pairs containing: */
/* DeltaThetaKJs, Subject's K, J, then On-File's {K,J} or {J,K} depending */
/* Sorted first on Subject's point index K, */
/* then On-File's K or J point index (depending), */
/* lastly on Subject's J point index */
int scols[ SCOLS_SIZE_1 ][ COLS_SIZE_2 ]; /* Subject's pointwise comparison table containing: */
/* Distance,min(BetaK,BetaJ),max(BetaK,BbetaJ), K,J,ThetaKJ */
int fcols[ FCOLS_SIZE_1 ][ COLS_SIZE_2 ]; /* On-File Record's pointwise comparison table with: */
/* Distance,min(BetaK,BetaJ),max(BetaK,BbetaJ),K,J, ThetaKJ */
int * scolpt[ SCOLPT_SIZE ]; /* Subject's list of pointers to pointwise comparison rows, sorted on: */
/* Distance, min(BetaK,BetaJ), then max(BetaK,BetaJ) */
int * fcolpt[ FCOLPT_SIZE ]; /* On-File Record's list of pointers to pointwise comparison rows sorted on: */
/* Distance, min(BetaK,BetaJ), then max(BetaK,BetaJ) */
int sc[ SC_SIZE ]; /* Flags all compatible edges in the Subject's Web */
int yl[ YL_SIZE_1 ][ YL_SIZE_2 ];
/**************************************************************************/
/* Globals used significantly by sift() */
/**************************************************************************/
int rq[ RQ_SIZE ] = {};
int tq[ TQ_SIZE ] = {};
int zz[ ZZ_SIZE ] = {};
int rx[ RX_SIZE ] = {};
int mm[ MM_SIZE ] = {};
int nn[ NN_SIZE ] = {};
int qq[ QQ_SIZE ] = {};
int rk[ RK_SIZE ] = {};
int cp[ CP_SIZE ] = {};
int rp[ RP_SIZE ] = {};
int rf[RF_SIZE_1][RF_SIZE_2] = {};
int cf[CF_SIZE_1][CF_SIZE_2] = {};
int y[20000] = {};

View file

@ -0,0 +1,632 @@
/******************************************************************************
This file is part of the Export Control subset of the United States NIST
Biometric Image Software (NBIS) distribution:
http://fingerprint.nist.gov/NBIS/index.html
It is our understanding that this falls within ECCN 3D980, which covers
software associated with the development, production or use of certain
equipment controlled in accordance with U.S. concerns about crime control
practices in specific countries.
Therefore, this file should not be exported, or made available on fileservers,
except as allowed by U.S. export control laws.
Do not remove this notice.
******************************************************************************/
/* NOTE: Despite the above notice (which I have not removed), this file is
* being legally distributed within libfprint; the U.S. Export Administration
* Regulations do not place export restrictions upon distribution of
* "publicly available technology and software", as stated in EAR section
* 734.3(b)(3)(i). libfprint qualifies as publicly available technology as per
* the definition in section 734.7(a)(1).
*
* For further information, see http://reactivated.net/fprint/US_export_control
*/
/*******************************************************************************
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: FING - NIST Fingerprint Systems Utilities
FILE: BZ_IO.C
ALGORITHM: Allan S. Bozorth (FBI)
MODIFICATIONS: Michael D. Garris (NIST)
Stan Janet (NIST)
DATE: 09/21/2004
Contains routines responsible for supporting command line
processing, file and data input to, and output from the
Bozorth3 fingerprint matching algorithm.
***********************************************************************
ROUTINES:
#cat: parse_line_range - parses strings of the form #-# into the upper
#cat: and lower bounds of a range corresponding to lines in
#cat: an input file list
#cat: set_progname - stores the program name for the current invocation
#cat: set_probe_filename - stores the name of the current probe file
#cat: being processed
#cat: set_gallery_filename - stores the name of the current gallery file
#cat: being processed
#cat: get_progname - retrieves the program name for the current invocation
#cat: get_probe_filename - retrieves the name of the current probe file
#cat: being processed
#cat: get_gallery_filename - retrieves the name of the current gallery
#cat: file being processed
#cat: get_next_file - gets the next probe (or gallery) filename to be
#cat: processed, either from the command line or from a
#cat: file list
#cat: get_score_filename - returns the filename to which the output line
#cat: should be written
#cat: get_score_line - formats output lines based on command line options
#cat: specified
#cat: bz_load - loads the contents of the specified XYT file into
#cat: structured memory
#cat: fd_readable - when multiple bozorth processes are being run
#cat: concurrently and one of the processes determines a
#cat: has been found, the other processes poll a file
#cat: descriptor using this function to see if they
#cat: should exit as well
***********************************************************************/
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#include <bozorth.h>
static const int verbose_load = 0;
static const int verbose_main = 0;
/***********************************************************************/
int parse_line_range( const char * sb, int * begin, int * end )
{
int ib, ie;
char * se;
if ( ! isdigit(*sb) )
return -1;
ib = atoi( sb );
se = strchr( sb, '-' );
if ( se != (char *) NULL ) {
se++;
if ( ! isdigit(*se) )
return -2;
ie = atoi( se );
} else {
ie = ib;
}
if ( ib <= 0 ) {
if ( ie <= 0 ) {
return -3;
} else {
return -4;
}
}
if ( ie <= 0 ) {
return -5;
}
if ( ib > ie )
return -6;
*begin = ib;
*end = ie;
return 0;
}
/***********************************************************************/
/* Used by the following set* and get* routines */
static char program_buffer[ 1024 ];
static char * pfile;
static char * gfile;
/***********************************************************************/
void set_progname( int use_pid, char * basename, pid_t pid )
{
if ( use_pid )
sprintf( program_buffer, "%s pid %ld", basename, (long) pid );
else
sprintf( program_buffer, "%s", basename );
}
/***********************************************************************/
void set_probe_filename( char * filename )
{
pfile = filename;
}
/***********************************************************************/
void set_gallery_filename( char * filename )
{
gfile = filename;
}
/***********************************************************************/
char * get_progname( void )
{
return program_buffer;
}
/***********************************************************************/
char * get_probe_filename( void )
{
return pfile;
}
/***********************************************************************/
char * get_gallery_filename( void )
{
return gfile;
}
/***********************************************************************/
char * get_next_file(
char * fixed_file,
FILE * list_fp,
FILE * mates_fp,
int * done_now,
int * done_afterwards,
char * line,
int argc,
char ** argv,
int * optind,
int * lineno,
int begin,
int end
)
{
char * p;
FILE * fp;
if ( fixed_file != (char *) NULL ) {
if ( verbose_main )
fprintf( stderr, "returning fixed filename: %s\n", fixed_file );
return fixed_file;
}
fp = list_fp;
if ( fp == (FILE *) NULL )
fp = mates_fp;
if ( fp != (FILE *) NULL ) {
while (1) {
if ( fgets( line, MAX_LINE_LENGTH, fp ) == (char *) NULL ) {
*done_now = 1;
if ( verbose_main )
fprintf( stderr, "returning NULL -- reached EOF\n" );
return (char *) NULL;
}
++*lineno;
if ( begin <= 0 ) /* no line number range was specified */
break;
if ( *lineno > end ) {
*done_now = 1;
if ( verbose_main )
fprintf( stderr, "returning NULL -- current line (%d) > end line (%d)\n",
*lineno, end );
return (char *) NULL;
}
if ( *lineno >= begin ) {
break;
}
/* Otherwise ( *lineno < begin ) so read another line */
}
p = strchr( line, '\n' );
if ( p == (char *) NULL ) {
*done_now = 1;
if ( verbose_main )
fprintf( stderr, "returning NULL -- missing newline character\n" );
return (char *) NULL;
}
*p = '\0';
p = line;
if ( verbose_main )
fprintf( stderr, "returning filename from next line: %s\n", p );
return p;
}
p = argv[*optind];
++*optind;
if ( *optind >= argc )
*done_afterwards = 1;
if ( verbose_main )
fprintf( stderr, "returning next argv: %s [done_afterwards=%d]\n", p, *done_afterwards );
return p;
}
/***********************************************************************/
/* returns CNULL on error */
char * get_score_filename( const char * outdir, const char * listfile )
{
const char * basename;
int baselen;
int dirlen;
int extlen;
char * outfile;
/* These are now exteranlly defined in bozorth.h */
/* extern FILE * stderr; */
/* extern char * get_progname( void ); */
basename = strrchr( listfile, '/' );
if ( basename == CNULL ) {
basename = listfile;
} else {
++basename;
}
baselen = strlen( basename );
if ( baselen == 0 ) {
fprintf( stderr, "%s: ERROR: couldn't find basename of %s\n", get_progname(), listfile );
return(CNULL);
}
dirlen = strlen( outdir );
if ( dirlen == 0 ) {
fprintf( stderr, "%s: ERROR: illegal output directory %s\n", get_progname(), outdir );
return(CNULL);
}
extlen = strlen( SCOREFILE_EXTENSION );
outfile = malloc_or_return_error( dirlen + baselen + extlen + 2, "output filename" );
if ( outfile == CNULL)
return(CNULL);
sprintf( outfile, "%s/%s%s", outdir, basename, SCOREFILE_EXTENSION );
return outfile;
}
/***********************************************************************/
char * get_score_line(
const char * probe_file,
const char * gallery_file,
int n,
int static_flag,
const char * fmt
)
{
int nchars;
char * bufptr;
static char linebuf[1024];
nchars = 0;
bufptr = &linebuf[0];
while ( *fmt ) {
if ( nchars++ > 0 )
*bufptr++ = ' ';
switch ( *fmt++ ) {
case 's':
sprintf( bufptr, "%d", n );
break;
case 'p':
sprintf( bufptr, "%s", probe_file );
break;
case 'g':
sprintf( bufptr, "%s", gallery_file );
break;
default:
return (char *) NULL;
}
bufptr = strchr( bufptr, '\0' );
}
*bufptr++ = '\n';
*bufptr = '\0';
return static_flag ? &linebuf[0] : strdup( linebuf );
}
/************************************************************************
Load a 3-4 column (X,Y,T[,Q]) set of minutiae from the specified file.
Row 3's value is an angle which is normalized to the interval (-180,180].
A maximum of MAX_BOZORTH_MINUTIAE minutiae can be returned -- fewer if
"DEFAULT_BOZORTH_MINUTIAE" is smaller. If the file contains more minutiae than are
to be returned, the highest-quality minutiae are returned.
*************************************************************************/
/***********************************************************************/
struct xyt_struct * bz_load( const char * xyt_file )
{
int nminutiae;
int j;
int m;
int nargs_expected;
FILE * fp;
struct xyt_struct * s;
int * xptr;
int * yptr;
int * tptr;
int * qptr;
struct minutiae_struct c[MAX_FILE_MINUTIAE];
int xvals_lng[MAX_FILE_MINUTIAE], /* Temporary lists to store all the minutaie from a file */
yvals_lng[MAX_FILE_MINUTIAE],
tvals_lng[MAX_FILE_MINUTIAE],
qvals_lng[MAX_FILE_MINUTIAE];
int order[MAX_FILE_MINUTIAE]; /* The ranked order, after sort, for each index */
int xvals[MAX_BOZORTH_MINUTIAE], /* Temporary lists to hold input coordinates */
yvals[MAX_BOZORTH_MINUTIAE],
tvals[MAX_BOZORTH_MINUTIAE],
qvals[MAX_BOZORTH_MINUTIAE];
char xyt_line[ MAX_LINE_LENGTH ];
/* This is now externally defined in bozorth.h */
/* extern FILE * stderr; */
#define C1 0
#define C2 1
fp = fopen( xyt_file, "r" );
if ( fp == (FILE *) NULL ) {
fprintf( stderr, "%s: ERROR: fopen() of minutiae file \"%s\" failed: %s\n",
get_progname(), xyt_file, strerror(errno) );
return XYT_NULL;
}
nminutiae = 0;
nargs_expected = 0;
while ( fgets( xyt_line, sizeof xyt_line, fp ) != CNULL ) {
m = sscanf( xyt_line, "%d %d %d %d",
&xvals_lng[nminutiae],
&yvals_lng[nminutiae],
&tvals_lng[nminutiae],
&qvals_lng[nminutiae] );
if ( nminutiae == 0 ) {
if ( m != 3 && m != 4 ) {
fprintf( stderr, "%s: ERROR: sscanf() failed on line %u in minutiae file \"%s\"\n",
get_progname(), nminutiae+1, xyt_file );
return XYT_NULL;
}
nargs_expected = m;
} else {
if ( m != nargs_expected ) {
fprintf( stderr, "%s: ERROR: inconsistent argument count on line %u of minutiae file \"%s\"\n",
get_progname(), nminutiae+1, xyt_file );
return XYT_NULL;
}
}
if ( m == 3 )
qvals_lng[nminutiae] = 1;
if ( tvals_lng[nminutiae] > 180 )
tvals_lng[nminutiae] -= 360;
/*
if ( C1 ) {
c[nminutiae].col[0] = xvals_lng[nminutiae];
c[nminutiae].col[1] = yvals_lng[nminutiae];
c[nminutiae].col[2] = tvals_lng[nminutiae];
c[nminutiae].col[3] = qvals_lng[nminutiae];
}
*/
++nminutiae;
if ( nminutiae == MAX_FILE_MINUTIAE )
break;
}
if ( fclose(fp) != 0 ) {
fprintf( stderr, "%s: ERROR: fclose() of minutiae file \"%s\" failed: %s\n",
get_progname(), xyt_file, strerror(errno) );
return XYT_NULL;
}
if ( nminutiae > DEFAULT_BOZORTH_MINUTIAE ) {
if ( verbose_load )
fprintf( stderr, "%s: WARNING: bz_load(): trimming minutiae to the %d of highest quality\n",
get_progname(), DEFAULT_BOZORTH_MINUTIAE );
if ( verbose_load )
fprintf( stderr, "Before quality sort:\n" );
if ( sort_order_decreasing( qvals_lng, nminutiae, order )) {
fprintf( stderr, "%s: ERROR: sort failed and returned on error\n", get_progname());
return XYT_NULL;
}
for ( j = 0; j < nminutiae; j++ ) {
if ( verbose_load )
fprintf( stderr, " %3d: %3d %3d %3d ---> order = %3d\n",
j, xvals_lng[j], yvals_lng[j], qvals_lng[j], order[j] );
if ( j == 0 )
continue;
if ( qvals_lng[order[j]] > qvals_lng[order[j-1]] ) {
fprintf( stderr, "%s: ERROR: sort failed: j=%d; qvals_lng[%d] > qvals_lng[%d]\n",
get_progname(), j, order[j], order[j-1] );
return XYT_NULL;
}
}
if ( verbose_load )
fprintf( stderr, "\nAfter quality sort:\n" );
for ( j = 0; j < DEFAULT_BOZORTH_MINUTIAE; j++ ) {
xvals[j] = xvals_lng[order[j]];
yvals[j] = yvals_lng[order[j]];
tvals[j] = tvals_lng[order[j]];
qvals[j] = qvals_lng[order[j]];
if ( verbose_load )
fprintf( stderr, " %3d: %3d %3d %3d\n", j, xvals[j], yvals[j], qvals[j] );
}
if ( C1 ) {
if ( verbose_load )
fprintf( stderr, "\nAfter qsort():\n" );
qsort( (void *) &c, (size_t) nminutiae, sizeof(struct minutiae_struct), sort_quality_decreasing );
for ( j = 0; j < nminutiae; j++ ) {
if ( verbose_load )
fprintf( stderr, "Q %3d: %3d %3d %3d\n",
j, c[j].col[0], c[j].col[1], c[j].col[3] );
if ( j > 0 && c[j].col[3] > c[j-1].col[3] ) {
fprintf( stderr, "%s: ERROR: sort failed: c[%d].col[3] > c[%d].col[3]\n",
get_progname(), j, j-1 );
return XYT_NULL;
}
}
}
if ( verbose_load )
fprintf( stderr, "\n" );
xptr = xvals;
yptr = yvals;
tptr = tvals;
qptr = qvals;
nminutiae = DEFAULT_BOZORTH_MINUTIAE;
} else{
xptr = xvals_lng;
yptr = yvals_lng;
tptr = tvals_lng;
qptr = qvals_lng;
}
for ( j=0; j < nminutiae; j++ ) {
c[j].col[0] = xptr[j];
c[j].col[1] = yptr[j];
c[j].col[2] = tptr[j];
c[j].col[3] = qptr[j];
}
qsort( (void *) &c, (size_t) nminutiae, sizeof(struct minutiae_struct), sort_x_y );
if ( verbose_load ) {
fprintf( stderr, "\nSorted on increasing x, then increasing y\n" );
for ( j = 0; j < nminutiae; j++ ) {
fprintf( stderr, "%d : %3d, %3d, %3d, %3d\n", j, c[j].col[0], c[j].col[1], c[j].col[2], c[j].col[3] );
if ( j > 0 ) {
if ( c[j].col[0] < c[j-1].col[0] ) {
fprintf( stderr, "%s: ERROR: sort failed: c[%d].col[0]=%d > c[%d].col[0]=%d\n",
get_progname(),
j, c[j].col[0], j-1, c[j-1].col[0]
);
return XYT_NULL;
}
if ( c[j].col[0] == c[j-1].col[0] && c[j].col[1] < c[j-1].col[1] ) {
fprintf( stderr, "%s: ERROR: sort failed: c[%d].col[0]=%d == c[%d].col[0]=%d; c[%d].col[0]=%d == c[%d].col[0]=%d\n",
get_progname(),
j, c[j].col[0], j-1, c[j-1].col[0],
j, c[j].col[1], j-1, c[j-1].col[1]
);
return XYT_NULL;
}
}
}
}
s = (struct xyt_struct *) malloc( sizeof( struct xyt_struct ) );
if ( s == XYT_NULL ) {
fprintf( stderr, "%s: ERROR: malloc() failure while loading minutiae file \"%s\" failed: %s\n",
get_progname(),
xyt_file,
strerror(errno)
);
return XYT_NULL;
}
for ( j = 0; j < nminutiae; j++ ) {
s->xcol[j] = c[j].col[0];
s->ycol[j] = c[j].col[1];
s->thetacol[j] = c[j].col[2];
}
s->nrows = nminutiae;
if ( verbose_load )
fprintf( stderr, "Loaded %s\n", xyt_file );
return s;
}
/***********************************************************************/
#ifdef PARALLEL_SEARCH
int fd_readable( int fd )
{
int retval;
fd_set rfds;
struct timeval tv;
FD_ZERO( &rfds );
FD_SET( fd, &rfds );
tv.tv_sec = 0;
tv.tv_usec = 0;
retval = select( fd+1, &rfds, NULL, NULL, &tv );
if ( retval < 0 ) {
perror( "select() failed" );
return 0;
}
if ( FD_ISSET( fd, &rfds ) ) {
/*fprintf( stderr, "data is available now.\n" );*/
return 1;
}
/* fprintf( stderr, "no data is available\n" ); */
return 0;
}
#endif

View file

@ -0,0 +1,315 @@
/******************************************************************************
This file is part of the Export Control subset of the United States NIST
Biometric Image Software (NBIS) distribution:
http://fingerprint.nist.gov/NBIS/index.html
It is our understanding that this falls within ECCN 3D980, which covers
software associated with the development, production or use of certain
equipment controlled in accordance with U.S. concerns about crime control
practices in specific countries.
Therefore, this file should not be exported, or made available on fileservers,
except as allowed by U.S. export control laws.
Do not remove this notice.
******************************************************************************/
/* NOTE: Despite the above notice (which I have not removed), this file is
* being legally distributed within libfprint; the U.S. Export Administration
* Regulations do not place export restrictions upon distribution of
* "publicly available technology and software", as stated in EAR section
* 734.3(b)(3)(i). libfprint qualifies as publicly available technology as per
* the definition in section 734.7(a)(1).
*
* For further information, see http://reactivated.net/fprint/US_export_control
*/
/*******************************************************************************
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: FING - NIST Fingerprint Systems Utilities
FILE: BZ_SORT.C
ALGORITHM: Allan S. Bozorth (FBI)
MODIFICATIONS: Michael D. Garris (NIST)
Stan Janet (NIST)
DATE: 09/21/2004
Contains sorting routines responsible for supporting the
Bozorth3 fingerprint matching algorithm.
***********************************************************************
ROUTINES:
#cat: sort_quality_decreasing - comparison function passed to stdlib
#cat: qsort() used to sort minutia qualities
#cat: sort_x_y - comparison function passed to stdlib qsort() used
#cat: to sort minutia coordinates increasing first on x
#cat: then on y
#cat: sort_order_decreasing - calls a custom quicksort that sorts
#cat: a list of integers in decreasing order
***********************************************************************/
#include <stdio.h>
#include <bozorth.h>
/* These are now externally defined in bozorth.h */
/* extern char * get_progname( void ); */
/***********************************************************************/
int sort_quality_decreasing( const void * a, const void * b )
{
struct minutiae_struct * af;
struct minutiae_struct * bf;
af = (struct minutiae_struct *) a;
bf = (struct minutiae_struct *) b;
if ( af->col[3] > bf->col[3] )
return -1;
if ( af->col[3] < bf->col[3] )
return 1;
return 0;
}
/***********************************************************************/
int sort_x_y( const void * a, const void * b )
{
struct minutiae_struct * af;
struct minutiae_struct * bf;
af = (struct minutiae_struct *) a;
bf = (struct minutiae_struct *) b;
if ( af->col[0] < bf->col[0] )
return -1;
if ( af->col[0] > bf->col[0] )
return 1;
if ( af->col[1] < bf->col[1] )
return -1;
if ( af->col[1] > bf->col[1] )
return 1;
return 0;
}
/********************************************************
qsort_decreasing() - quicksort an array of integers in decreasing
order [based on multisort.c, by Michael Garris
and Ted Zwiesler, 1986]
********************************************************/
/* Used by custom quicksort code below */
static int stack[BZ_STACKSIZE];
static int * stack_pointer = stack;
/***********************************************************************/
/* return values: 0 == successful, 1 == error */
static int popstack( int *popval )
{
if ( --stack_pointer < stack ) {
fprintf( stderr, "%s: ERROR: popstack(): stack underflow\n", get_progname() );
return 1;
}
*popval = *stack_pointer;
return 0;
}
/***********************************************************************/
/* return values: 0 == successful, 1 == error */
static int pushstack( int position )
{
*stack_pointer++ = position;
if ( stack_pointer > ( stack + BZ_STACKSIZE ) ) {
fprintf( stderr, "%s: ERROR: pushstack(): stack overflow\n", get_progname() );
return 1;
}
return 0;
}
/***********************************************************************/
/*******************************************************************
select_pivot()
selects a pivot from a list being sorted using the Singleton Method.
*******************************************************************/
static int select_pivot( struct cell v[], int left, int right )
{
int midpoint;
midpoint = ( left + right ) / 2;
if ( v[left].index <= v[midpoint].index ) {
if ( v[midpoint].index <= v[right].index ) {
return midpoint;
} else {
if ( v[right].index > v[left].index ) {
return right;
} else {
return left;
}
}
} else {
if ( v[left].index < v[right].index ) {
return left;
} else {
if ( v[right].index < v[midpoint].index ) {
return midpoint;
} else {
return right;
}
}
}
}
/***********************************************************************/
/********************************************************
partition_dec()
Inputs a pivot element making comparisons and swaps with other elements in a list,
until pivot resides at its correct position in the list.
********************************************************/
static void partition_dec( struct cell v[], int *llen, int *rlen, int *ll, int *lr, int *rl, int *rr, int p, int l, int r )
{
#define iswap(a,b) { int itmp = (a); a = (b); b = itmp; }
*ll = l;
*rr = r;
while ( 1 ) {
if ( l < p ) {
if ( v[l].index < v[p].index ) {
iswap( v[l].index, v[p].index )
iswap( v[l].item, v[p].item )
p = l;
} else {
l++;
}
} else {
if ( r > p ) {
if ( v[r].index > v[p].index ) {
iswap( v[r].index, v[p].index )
iswap( v[r].item, v[p].item )
p = r;
l++;
} else {
r--;
}
} else {
*lr = p - 1;
*rl = p + 1;
*llen = *lr - *ll + 1;
*rlen = *rr - *rl + 1;
break;
}
}
}
}
/***********************************************************************/
/********************************************************
qsort_decreasing()
This procedure inputs a pointer to an index_struct, the subscript of an index array to be
sorted, a left subscript pointing to where the sort is to begin in the index array, and a right
subscript where to end. This module invokes a decreasing quick-sort sorting the index array from l to r.
********************************************************/
/* return values: 0 == successful, 1 == error */
static int qsort_decreasing( struct cell v[], int left, int right )
{
int pivot;
int llen, rlen;
int lleft, lright, rleft, rright;
if ( pushstack( left ))
return 1;
if ( pushstack( right ))
return 2;
while ( stack_pointer != stack ) {
if (popstack(&right))
return 3;
if (popstack(&left ))
return 4;
if ( right - left > 0 ) {
pivot = select_pivot( v, left, right );
partition_dec( v, &llen, &rlen, &lleft, &lright, &rleft, &rright, pivot, left, right );
if ( llen > rlen ) {
if ( pushstack( lleft ))
return 5;
if ( pushstack( lright ))
return 6;
if ( pushstack( rleft ))
return 7;
if ( pushstack( rright ))
return 8;
} else{
if ( pushstack( rleft ))
return 9;
if ( pushstack( rright ))
return 10;
if ( pushstack( lleft ))
return 11;
if ( pushstack( lright ))
return 12;
}
}
}
return 0;
}
/***********************************************************************/
/* return values: 0 == successful, 1 == error */
int sort_order_decreasing(
int values[], /* INPUT: the unsorted values themselves */
int num, /* INPUT: the number of values */
int order[] /* OUTPUT: the order for each of the values if sorted */
)
{
int i;
struct cell * cells;
cells = (struct cell *) malloc( num * sizeof(struct cell) );
if ( cells == (struct cell *) NULL ){
fprintf( stderr, "%s: ERROR: malloc(): struct cell\n", get_progname() );
return 1;
}
for( i = 0; i < num; i++ ) {
cells[i].index = values[i];
cells[i].item = i;
}
if ( qsort_decreasing( cells, 0, num-1 ) < 0)
return 2;
for( i = 0; i < num; i++ ) {
order[i] = cells[i].item;
}
free( (void *) cells );
return 0;
}

View file

@ -186,15 +186,7 @@ struct xyt_struct {
/* In: SRC/BIN/BOZORTH3/BOZORTH3.C */
/**************************************************************************/
/* Globals supporting command line options */
extern int m1_xyt;
extern int max_minutiae;
extern int min_computable_minutiae;
extern int verbose_main;
extern int verbose_load;
extern int verbose_bozorth;
extern int verbose_threshold;
/* Global supporting error reporting */
extern FILE *errorfp;
/**************************************************************************/
/* In: BZ_GBLS.C */
@ -258,6 +250,7 @@ extern struct xyt_struct *bz_load(const char *);
extern int fd_readable(int);
/* In: BZ_SORT.C */
extern int sort_quality_decreasing(const void *, const void *);
extern int sort_x_y(const void *, const void *);
extern int sort_order_decreasing(int [], int, int []);
#endif /* !_BOZORTH_H */