Add mindtct from NBIS; implement enroll for image devices
mindtct is mostly as-is for now, with just a couple of bits ripped out.
This commit is contained in:
parent
be67f85caa
commit
41b25f28a4
41 changed files with 23503 additions and 3 deletions
|
@ -6,14 +6,46 @@ AES4000_SRC = drivers/aes4000.c
|
||||||
|
|
||||||
DRIVER_SRC = $(UPEKTS_SRC) $(URU4000_SRC) $(AES4000_SRC)
|
DRIVER_SRC = $(UPEKTS_SRC) $(URU4000_SRC) $(AES4000_SRC)
|
||||||
|
|
||||||
libfprint_la_CFLAGS = -fvisibility=hidden $(LIBUSB_CFLAGS) $(GLIB_CFLAGS) $(AM_CFLAGS)
|
NBIS_SRC = \
|
||||||
|
nbis/mindtct/binar.c \
|
||||||
|
nbis/mindtct/block.c \
|
||||||
|
nbis/mindtct/chaincod.c \
|
||||||
|
nbis/mindtct/contour.c \
|
||||||
|
nbis/mindtct/detect.c \
|
||||||
|
nbis/mindtct/dft.c \
|
||||||
|
nbis/mindtct/free.c \
|
||||||
|
nbis/mindtct/getmin.c \
|
||||||
|
nbis/mindtct/globals.c \
|
||||||
|
nbis/mindtct/imgutil.c \
|
||||||
|
nbis/mindtct/init.c \
|
||||||
|
nbis/mindtct/isempty.c \
|
||||||
|
nbis/mindtct/line.c \
|
||||||
|
nbis/mindtct/link.c \
|
||||||
|
nbis/mindtct/log.c \
|
||||||
|
nbis/mindtct/loop.c \
|
||||||
|
nbis/mindtct/maps.c \
|
||||||
|
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 \
|
||||||
|
nbis/mindtct/util.c \
|
||||||
|
nbis/mindtct/xytreps.c
|
||||||
|
|
||||||
|
libfprint_la_CFLAGS = -fvisibility=hidden -Inbis/include $(LIBUSB_CFLAGS) $(GLIB_CFLAGS) $(AM_CFLAGS)
|
||||||
libfprint_la_LDFLAGS = -version-info @lt_major@:@lt_revision@:@lt_age@
|
libfprint_la_LDFLAGS = -version-info @lt_major@:@lt_revision@:@lt_age@
|
||||||
libfprint_la_LIBADD = $(LIBUSB_LIBS) $(GLIB_LIBS)
|
libfprint_la_LIBADD = -lm $(LIBUSB_LIBS) $(GLIB_LIBS)
|
||||||
|
|
||||||
libfprint_la_SOURCES = \
|
libfprint_la_SOURCES = \
|
||||||
core.c \
|
core.c \
|
||||||
data.c \
|
data.c \
|
||||||
img.c \
|
img.c \
|
||||||
imgdev.c \
|
imgdev.c \
|
||||||
$(DRIVER_SRC)
|
$(DRIVER_SRC) \
|
||||||
|
$(NBIS_SRC)
|
||||||
|
|
||||||
|
|
|
@ -178,6 +178,8 @@ struct fp_img *fpi_img_new(size_t length);
|
||||||
struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *dev);
|
struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *dev);
|
||||||
struct fp_img *fpi_img_resize(struct fp_img *img, size_t newsize);
|
struct fp_img *fpi_img_resize(struct fp_img *img, size_t newsize);
|
||||||
gboolean fpi_img_is_sane(struct fp_img *img);
|
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);
|
||||||
|
|
||||||
#define bswap16(x) (((x & 0xff) << 8) | (x >> 8))
|
#define bswap16(x) (((x & 0xff) << 8) | (x >> 8))
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
|
105
libfprint/img.c
105
libfprint/img.c
|
@ -25,6 +25,8 @@
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
#include "fp_internal.h"
|
#include "fp_internal.h"
|
||||||
|
#include "nbis/include/bozorth.h"
|
||||||
|
#include "nbis/include/lfs.h"
|
||||||
|
|
||||||
struct fp_img *fpi_img_new(size_t length)
|
struct fp_img *fpi_img_new(size_t length)
|
||||||
{
|
{
|
||||||
|
@ -172,3 +174,106 @@ API_EXPORTED void fp_img_standardize(struct fp_img *img)
|
||||||
img->flags &= ~FP_IMG_COLORS_INVERTED;
|
img->flags &= ~FP_IMG_COLORS_INVERTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
MINUTIA *minutia;
|
||||||
|
struct minutiae_struct c[MAX_FILE_MINUTIAE];
|
||||||
|
struct xyt_struct *xyt = (struct xyt_struct *) buf;
|
||||||
|
|
||||||
|
/* FIXME: only considers first 150 minutiae (MAX_FILE_MINUTIAE) */
|
||||||
|
/* nist does weird stuff with 150 vs 1000 limits */
|
||||||
|
int nmin = min(minutiae->num, MAX_FILE_MINUTIAE);
|
||||||
|
|
||||||
|
for (i = 0; i < nmin; i++){
|
||||||
|
minutia = minutiae->list[i];
|
||||||
|
|
||||||
|
lfs2nist_minutia_XYT(&c[i].col[0], &c[i].col[1], &c[i].col[2],
|
||||||
|
minutia, bwidth, bheight);
|
||||||
|
c[i].col[3] = sround(minutia->reliability * 100.0);
|
||||||
|
|
||||||
|
if (c[i].col[2] > 180)
|
||||||
|
c[i].col[2] -= 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort((void *) &c, (size_t) nmin, sizeof(struct minutiae_struct),
|
||||||
|
sort_x_y);
|
||||||
|
|
||||||
|
for (i = 0; i < nmin; i++) {
|
||||||
|
xyt->xcol[i] = c[i].col[0];
|
||||||
|
xyt->ycol[i] = c[i].col[1];
|
||||||
|
xyt->thetacol[i] = c[i].col[2];
|
||||||
|
}
|
||||||
|
xyt->nrows = nmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fpi_img_detect_minutiae(struct fp_img_dev *imgdev, struct fp_img *img,
|
||||||
|
struct fp_print_data **ret)
|
||||||
|
{
|
||||||
|
MINUTIAE *minutiae;
|
||||||
|
int r;
|
||||||
|
int *direction_map, *low_contrast_map, *low_flow_map;
|
||||||
|
int *high_curve_map, *quality_map;
|
||||||
|
int map_w, map_h;
|
||||||
|
unsigned char *bdata;
|
||||||
|
int bw, bh, bd;
|
||||||
|
struct fp_print_data *print;
|
||||||
|
GTimer *timer;
|
||||||
|
|
||||||
|
/* 25.4 mm per inch */
|
||||||
|
timer = g_timer_new();
|
||||||
|
r = get_minutiae(&minutiae, &quality_map, &direction_map,
|
||||||
|
&low_contrast_map, &low_flow_map, &high_curve_map,
|
||||||
|
&map_w, &map_h, &bdata, &bw, &bh, &bd,
|
||||||
|
img->data, img->width, img->height, 8,
|
||||||
|
DEFAULT_PPI / (double)25.4, &lfsparms_V2);
|
||||||
|
g_timer_stop(timer);
|
||||||
|
fp_dbg("minutiae scan completed in %f secs", g_timer_elapsed(timer, NULL));
|
||||||
|
g_timer_destroy(timer);
|
||||||
|
if (r) {
|
||||||
|
fp_err("get minutiae failed, code %d", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
fp_dbg("detected %d minutiae", minutiae->num);
|
||||||
|
r = minutiae->num;
|
||||||
|
|
||||||
|
/* FIXME: space is wasted if we dont hit the max minutiae count. would
|
||||||
|
* be good to make this dynamic. */
|
||||||
|
print = fpi_print_data_new(imgdev->dev, sizeof(struct xyt_struct));
|
||||||
|
minutiae_to_xyt(minutiae, bw, bh, print->buffer);
|
||||||
|
/* FIXME: the print buffer at this point is endian-specific, and will
|
||||||
|
* only work when loaded onto machines with identical endianness. not good!
|
||||||
|
* data format should be platform-independant. */
|
||||||
|
*ret = print;
|
||||||
|
|
||||||
|
free_minutiae(minutiae);
|
||||||
|
free(quality_map);
|
||||||
|
free(direction_map);
|
||||||
|
free(low_contrast_map);
|
||||||
|
free(low_flow_map);
|
||||||
|
free(high_curve_map);
|
||||||
|
free(bdata);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
|
@ -138,10 +138,43 @@ API_EXPORTED int fp_imgdev_capture(struct fp_img_dev *imgdev,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MIN_ACCEPTABLE_MINUTIAE 5
|
||||||
|
|
||||||
|
int img_dev_enroll(struct fp_dev *dev, gboolean initial, int stage,
|
||||||
|
struct fp_print_data **ret)
|
||||||
|
{
|
||||||
|
struct fp_img *img;
|
||||||
|
struct fp_img_dev *imgdev = dev->priv;
|
||||||
|
struct fp_print_data *print;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* FIXME: convert to 3-stage enroll mechanism, where we scan 3 prints,
|
||||||
|
* use NFIQ to pick the best one, and discard the others */
|
||||||
|
|
||||||
|
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_ENROLL_RETRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ret = print;
|
||||||
|
return FP_ENROLL_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
void fpi_img_driver_setup(struct fp_img_driver *idriver)
|
void fpi_img_driver_setup(struct fp_img_driver *idriver)
|
||||||
{
|
{
|
||||||
idriver->driver.type = DRIVER_IMAGING;
|
idriver->driver.type = DRIVER_IMAGING;
|
||||||
idriver->driver.init = img_dev_init;
|
idriver->driver.init = img_dev_init;
|
||||||
idriver->driver.exit = img_dev_exit;
|
idriver->driver.exit = img_dev_exit;
|
||||||
|
idriver->driver.enroll = img_dev_enroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
263
libfprint/nbis/include/bozorth.h
Normal file
263
libfprint/nbis/include/bozorth.h
Normal file
|
@ -0,0 +1,263 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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 _BOZORTH_H
|
||||||
|
#define _BOZORTH_H
|
||||||
|
|
||||||
|
/* The max number of points in any Probe or Gallery XYT is set to 200; */
|
||||||
|
/* a pointwise comparison table therefore has a maximum number of: */
|
||||||
|
/* (200^2)/2 = 20000 comparisons. */
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h> /* Needed for type pid_t */
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/* If not defined in sys/param.h */
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Math-Related Macros, Definitions & Prototypes */
|
||||||
|
/**************************************************************************/
|
||||||
|
#include <math.h>
|
||||||
|
/* This macro adjusts angles to the range (-180,180] */
|
||||||
|
#define IANGLE180(deg) ( ( (deg) > 180 ) ? ( (deg) - 360 ) : ( (deg) <= -180 ? ( (deg) + 360 ) : (deg) ) )
|
||||||
|
|
||||||
|
#define SENSE(a,b) ( (a) < (b) ? (-1) : ( ( (a) == (b) ) ? 0 : 1 ) )
|
||||||
|
#define SENSE_NEG_POS(a,b) ( (a) < (b) ? (-1) : 1 )
|
||||||
|
|
||||||
|
#define SQUARED(n) ( (n) * (n) )
|
||||||
|
|
||||||
|
#ifdef ROUND_USING_LIBRARY
|
||||||
|
/* These functions should be declared in math.h:
|
||||||
|
extern float roundf( float );
|
||||||
|
extern double round( double );
|
||||||
|
*/
|
||||||
|
#define ROUND(f) (roundf(f))
|
||||||
|
#else
|
||||||
|
#define ROUND(f) ( ( (f) < 0.0F ) ? ( (int) ( (f) - 0.5F ) ) : ( (int) ( (f) + 0.5F ) ) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* PI is used in: bozorth3.c, comp.c */
|
||||||
|
#ifdef M_PI
|
||||||
|
#define PI M_PI
|
||||||
|
#define PI_SINGLE ( (float) PI )
|
||||||
|
#else
|
||||||
|
#define PI 3.14159
|
||||||
|
#define PI_SINGLE 3.14159F
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Provide prototype for atanf() */
|
||||||
|
extern float atanf( float );
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Array Length Definitions */
|
||||||
|
/**************************************************************************/
|
||||||
|
#include <bz_array.h>
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/**************************************************************************/
|
||||||
|
/* GENERAL DEFINITIONS */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#define FPNULL ((FILE *) NULL)
|
||||||
|
#define CNULL ((char *) NULL)
|
||||||
|
|
||||||
|
#define PROGRAM "bozorth3"
|
||||||
|
|
||||||
|
#define MAX_LINE_LENGTH 1024
|
||||||
|
|
||||||
|
#define SCOREFILE_EXTENSION ".scr"
|
||||||
|
|
||||||
|
#define MAX_FILELIST_LENGTH 10000
|
||||||
|
|
||||||
|
#define DEFAULT_BOZORTH_MINUTIAE 150
|
||||||
|
#define MAX_BOZORTH_MINUTIAE 200
|
||||||
|
#define MIN_BOZORTH_MINUTIAE 0
|
||||||
|
#define MIN_COMPUTABLE_BOZORTH_MINUTIAE 10
|
||||||
|
|
||||||
|
#define DEFAULT_MAX_MATCH_SCORE 400
|
||||||
|
#define ZERO_MATCH_SCORE 0
|
||||||
|
|
||||||
|
#define DEFAULT_SCORE_LINE_FORMAT "s"
|
||||||
|
|
||||||
|
#define DM 125
|
||||||
|
#define FD 5625
|
||||||
|
#define FDD 500
|
||||||
|
#define TK 0.05F
|
||||||
|
#define TXS 121
|
||||||
|
#define CTXS 121801
|
||||||
|
#define MSTR 3
|
||||||
|
#define MMSTR 8
|
||||||
|
#define WWIM 10
|
||||||
|
|
||||||
|
#define QQ_SIZE 4000
|
||||||
|
|
||||||
|
#define QQ_OVERFLOW_SCORE QQ_SIZE
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/**************************************************************************/
|
||||||
|
/* MACROS DEFINITIONS */
|
||||||
|
/**************************************************************************/
|
||||||
|
#define INT_SET(dst,count,value) { \
|
||||||
|
int * int_set_dst = (dst); \
|
||||||
|
int int_set_count = (count); \
|
||||||
|
int int_set_value = (value); \
|
||||||
|
while ( int_set_count-- > 0 ) \
|
||||||
|
*int_set_dst++ = int_set_value; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The code that calls it assumed dst gets bumped, so don't assign to a local variable */
|
||||||
|
#define INT_COPY(dst,src,count) { \
|
||||||
|
int * int_copy_src = (src); \
|
||||||
|
int int_copy_count = (count); \
|
||||||
|
while ( int_copy_count-- > 0 ) \
|
||||||
|
*dst++ = *int_copy_src++; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/**************************************************************************/
|
||||||
|
/* STRUCTURES & TYPEDEFS */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/* In BZ_SORT.C - supports stdlib qsort() and customized quicksort */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
/* Used by call to stdlib qsort() */
|
||||||
|
struct minutiae_struct {
|
||||||
|
int col[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Used by custom quicksort */
|
||||||
|
#define BZ_STACKSIZE 1000
|
||||||
|
struct cell {
|
||||||
|
int index; /* pointer to an array of pointers to index arrays */
|
||||||
|
int item; /* pointer to an item array */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/* In BZ_IO : Supports the loading and manipulation of XYT data */
|
||||||
|
/**************************************************************************/
|
||||||
|
#define MAX_FILE_MINUTIAE 1000 /* bz_load() */
|
||||||
|
|
||||||
|
struct xyt_struct {
|
||||||
|
int nrows;
|
||||||
|
int xcol[ MAX_BOZORTH_MINUTIAE ];
|
||||||
|
int ycol[ MAX_BOZORTH_MINUTIAE ];
|
||||||
|
int thetacol[ MAX_BOZORTH_MINUTIAE ];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define XYT_NULL ( (struct xyt_struct *) NULL ) /* bz_load() */
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/**************************************************************************/
|
||||||
|
/* GLOBAL VARIABLES */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/* 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 */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Global arrays supporting "core" bozorth algorithm */
|
||||||
|
extern int colp[ COLP_SIZE_1 ][ COLP_SIZE_2 ];
|
||||||
|
extern int scols[ SCOLS_SIZE_1 ][ COLS_SIZE_2 ];
|
||||||
|
extern int fcols[ FCOLS_SIZE_1 ][ COLS_SIZE_2 ];
|
||||||
|
extern int * scolpt[ SCOLPT_SIZE ];
|
||||||
|
extern int * fcolpt[ FCOLPT_SIZE ];
|
||||||
|
extern int sc[ SC_SIZE ];
|
||||||
|
extern int yl[ YL_SIZE_1 ][ YL_SIZE_2 ];
|
||||||
|
/* Global arrays supporting "core" bozorth algorithm continued: */
|
||||||
|
/* Globals used significantly by sift() */
|
||||||
|
extern int rq[ RQ_SIZE ];
|
||||||
|
extern int tq[ TQ_SIZE ];
|
||||||
|
extern int zz[ ZZ_SIZE ];
|
||||||
|
extern int rx[ RX_SIZE ];
|
||||||
|
extern int mm[ MM_SIZE ];
|
||||||
|
extern int nn[ NN_SIZE ];
|
||||||
|
extern int qq[ QQ_SIZE ];
|
||||||
|
extern int rk[ RK_SIZE ];
|
||||||
|
extern int cp[ CP_SIZE ];
|
||||||
|
extern int rp[ RP_SIZE ];
|
||||||
|
extern int rf[RF_SIZE_1][RF_SIZE_2];
|
||||||
|
extern int cf[CF_SIZE_1][CF_SIZE_2];
|
||||||
|
extern int y[20000];
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/**************************************************************************/
|
||||||
|
/* ROUTINE PROTOTYPES */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* In: BZ_DRVRS.C */
|
||||||
|
extern int bozorth_probe_init( struct xyt_struct *);
|
||||||
|
extern int bozorth_gallery_init( struct xyt_struct *);
|
||||||
|
extern int bozorth_to_gallery(int, struct xyt_struct *, struct xyt_struct *);
|
||||||
|
extern int bozorth_main(struct xyt_struct *, struct xyt_struct *);
|
||||||
|
/* In: BOZORTH3.C */
|
||||||
|
extern void bz_comp(int, int [], int [], int [], int *, int [][COLS_SIZE_2],
|
||||||
|
int *[]);
|
||||||
|
extern void bz_find(int *, int *[]);
|
||||||
|
extern int bz_match(int, int);
|
||||||
|
extern int bz_match_score(int, struct xyt_struct *, struct xyt_struct *);
|
||||||
|
extern void bz_sift(int *, int, int *, int, int, int, int *, int *);
|
||||||
|
/* In: BZ_ALLOC.C */
|
||||||
|
extern char *malloc_or_exit(int, const char *);
|
||||||
|
extern char *malloc_or_return_error(int, const char *);
|
||||||
|
/* In: BZ_IO.C */
|
||||||
|
extern int parse_line_range(const char *, int *, int *);
|
||||||
|
extern void set_progname(int, char *, pid_t);
|
||||||
|
extern void set_probe_filename(char *);
|
||||||
|
extern void set_gallery_filename(char *);
|
||||||
|
extern char *get_progname(void);
|
||||||
|
extern char *get_probe_filename(void);
|
||||||
|
extern char *get_gallery_filename(void);
|
||||||
|
extern char *get_next_file(char *, FILE *, FILE *, int *, int *, char *,
|
||||||
|
int, char **, int *, int *, int, int);
|
||||||
|
extern char *get_score_filename(const char *, const char *);
|
||||||
|
extern char *get_score_line(const char *, const char *, int, int, const char *);
|
||||||
|
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_order_decreasing(int [], int, int []);
|
||||||
|
|
||||||
|
#endif /* !_BOZORTH_H */
|
121
libfprint/nbis/include/bz_array.h
Normal file
121
libfprint/nbis/include/bz_array.h
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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 _BZ_ARRAY_H
|
||||||
|
#define _BZ_ARRAY_H
|
||||||
|
|
||||||
|
#define STATIC static
|
||||||
|
/* #define BAD_BOUNDS 1 */
|
||||||
|
|
||||||
|
#define COLP_SIZE_1 20000
|
||||||
|
#define COLP_SIZE_2 5
|
||||||
|
|
||||||
|
#define COLS_SIZE_2 6
|
||||||
|
#define SCOLS_SIZE_1 20000
|
||||||
|
#define FCOLS_SIZE_1 20000
|
||||||
|
|
||||||
|
#define SCOLPT_SIZE 20000
|
||||||
|
#define FCOLPT_SIZE 20000
|
||||||
|
|
||||||
|
#define SC_SIZE 20000
|
||||||
|
|
||||||
|
|
||||||
|
#define RQ_SIZE 20000
|
||||||
|
#define TQ_SIZE 20000
|
||||||
|
#define ZZ_SIZE 20000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define RX_SIZE 100
|
||||||
|
#define MM_SIZE 100
|
||||||
|
#define NN_SIZE 20
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define RK_SIZE 20000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define RR_SIZE 100
|
||||||
|
#define AVN_SIZE 5
|
||||||
|
#define AVV_SIZE_1 2000
|
||||||
|
#define AVV_SIZE_2 5
|
||||||
|
#define CT_SIZE 2000
|
||||||
|
#define GCT_SIZE 2000
|
||||||
|
#define CTT_SIZE 2000
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef BAD_BOUNDS
|
||||||
|
#define CTP_SIZE_1 2000
|
||||||
|
#define CTP_SIZE_2 1000
|
||||||
|
#else
|
||||||
|
#define CTP_SIZE_1 2000
|
||||||
|
#define CTP_SIZE_2 2500
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
rp[x] == ctp[][x] :: sct[x][]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define RF_SIZE_1 100
|
||||||
|
#define RF_SIZE_2 10
|
||||||
|
|
||||||
|
#define CF_SIZE_1 100
|
||||||
|
#define CF_SIZE_2 10
|
||||||
|
|
||||||
|
#define Y_SIZE 20000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define YL_SIZE_1 2
|
||||||
|
#define YL_SIZE_2 2000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define YY_SIZE_1 1000
|
||||||
|
#define YY_SIZE_2 2
|
||||||
|
#define YY_SIZE_3 2000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef BAD_BOUNDS
|
||||||
|
#define SCT_SIZE_1 1000
|
||||||
|
#define SCT_SIZE_2 1000
|
||||||
|
#else
|
||||||
|
#define SCT_SIZE_1 2500
|
||||||
|
#define SCT_SIZE_2 1000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CP_SIZE 20000
|
||||||
|
#define RP_SIZE 20000
|
||||||
|
|
||||||
|
#endif /* !_BZ_ARRAY_H */
|
63
libfprint/nbis/include/defs.h
Normal file
63
libfprint/nbis/include/defs.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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 _DEFS_H
|
||||||
|
#define _DEFS_H
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
/* General Purpose Defines */
|
||||||
|
/*********************************************************************/
|
||||||
|
#ifndef True
|
||||||
|
#define True 1
|
||||||
|
#define False 0
|
||||||
|
#endif
|
||||||
|
#ifndef TRUE
|
||||||
|
#define TRUE True
|
||||||
|
#define FALSE False
|
||||||
|
#endif
|
||||||
|
#define Yes True
|
||||||
|
#define No False
|
||||||
|
#define Empty NULL
|
||||||
|
#ifndef None
|
||||||
|
#define None -1
|
||||||
|
#endif
|
||||||
|
#ifndef FOUND
|
||||||
|
#define FOUND 1
|
||||||
|
#endif
|
||||||
|
#define NOT_FOUND_NEG -1
|
||||||
|
#define EOL EOF
|
||||||
|
#ifndef DEG2RAD
|
||||||
|
#define DEG2RAD (double)(57.29578)
|
||||||
|
#endif
|
||||||
|
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#define sround(x) ((int) (((x)<0) ? (x)-0.5 : (x)+0.5))
|
||||||
|
#define sround_uint(x) ((unsigned int) (((x)<0) ? (x)-0.5 : (x)+0.5))
|
||||||
|
#define xor(a, b) (!(a && b) && (a || b))
|
||||||
|
#define align_to_16(_v_) ((((_v_)+15)>>4)<<4)
|
||||||
|
#define align_to_32(_v_) ((((_v_)+31)>>5)<<5)
|
||||||
|
#ifndef CHUNKS
|
||||||
|
#define CHUNKS 100
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !_DEFS_H */
|
1208
libfprint/nbis/include/lfs.h
Normal file
1208
libfprint/nbis/include/lfs.h
Normal file
File diff suppressed because it is too large
Load diff
48
libfprint/nbis/include/log.h
Normal file
48
libfprint/nbis/include/log.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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 _LOG_H
|
||||||
|
#define _LOG_H
|
||||||
|
|
||||||
|
/* Definitions and references to support log report files. */
|
||||||
|
/* UPDATED: 03/16/2005 by MDG */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#ifdef LOG_REPORT
|
||||||
|
/* Uncomment the following line to enable logging. */
|
||||||
|
#define LOG_FILE "log.txt"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern FILE *logfp;
|
||||||
|
extern int avrdir;
|
||||||
|
extern float dir_strength;
|
||||||
|
extern int nvalid;
|
||||||
|
|
||||||
|
extern int open_logfile(void);
|
||||||
|
extern int close_logfile(void);
|
||||||
|
extern void print2log(char *, ...);
|
||||||
|
|
||||||
|
#endif
|
39
libfprint/nbis/include/morph.h
Normal file
39
libfprint/nbis/include/morph.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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 __MORPH_H__
|
||||||
|
#define __MORPH_H__
|
||||||
|
|
||||||
|
/* Modified 10/26/1999 by MDG to avoid indisciminate erosion of pixels */
|
||||||
|
/* along the edge of the binary image. */
|
||||||
|
|
||||||
|
extern void erode_charimage_2(unsigned char *, unsigned char *,
|
||||||
|
const int, const int);
|
||||||
|
extern void dilate_charimage_2(unsigned char *, unsigned char *,
|
||||||
|
const int, const int);
|
||||||
|
extern char get_south8_2(char *, const int, const int, const int, const int);
|
||||||
|
extern char get_north8_2(char *, const int, const int, const int);
|
||||||
|
extern char get_east8_2(char *, const int, const int, const int);
|
||||||
|
extern char get_west8_2(char *, const int, const int);
|
||||||
|
|
||||||
|
#endif /* !__MORPH_H__ */
|
80
libfprint/nbis/include/mytime.h
Normal file
80
libfprint/nbis/include/mytime.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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
|
||||||
|
|
76
libfprint/nbis/include/sunrast.h
Normal file
76
libfprint/nbis/include/sunrast.h
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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 _SUNRAST_H
|
||||||
|
#define _SUNRAST_H
|
||||||
|
|
||||||
|
/************************************************************/
|
||||||
|
/* File Name: Sunrast.h */
|
||||||
|
/* Package: Sun Rasterfile I/O */
|
||||||
|
/* Author: Michael D. Garris */
|
||||||
|
/* Date: 8/19/99 */
|
||||||
|
/* Updated: 03/16/2005 by MDG */
|
||||||
|
/* */
|
||||||
|
/************************************************************/
|
||||||
|
|
||||||
|
/* Contains header information related to Sun Rasterfile images. */
|
||||||
|
|
||||||
|
typedef struct sunrasterhdr {
|
||||||
|
int magic; /* magic number */
|
||||||
|
int width; /* width (in pixels) of image */
|
||||||
|
int height; /* height (in pixels) of image */
|
||||||
|
int depth; /* depth (1, 8, or 24 bits) of pixel */
|
||||||
|
int raslength; /* length (in bytes) of image */
|
||||||
|
int rastype; /* type of file; see SUN_* below */
|
||||||
|
int maptype; /* type of colormap; see MAP_* below */
|
||||||
|
int maplength; /* length (bytes) of following map */
|
||||||
|
/* color map follows for maplength bytes, followed by image */
|
||||||
|
} SUNHEAD;
|
||||||
|
|
||||||
|
#define SUN_MAGIC 0x59a66a95
|
||||||
|
|
||||||
|
/* Sun supported ras_type's */
|
||||||
|
#define SUN_STANDARD 1 /* Raw pixrect image in 68000 byte order */
|
||||||
|
#define SUN_RUN_LENGTH 2 /* Run-length compression of bytes */
|
||||||
|
#define SUN_FORMAT_RGB 3 /* XRGB or RGB instead of XBGR or BGR */
|
||||||
|
#define SUN_FORMAT_TIFF 4 /* tiff <-> standard rasterfile */
|
||||||
|
#define SUN_FORMAT_IFF 5 /* iff (TAAC format) <-> standard rasterfile */
|
||||||
|
|
||||||
|
/* Sun supported maptype's */
|
||||||
|
#define MAP_RAW 2
|
||||||
|
#define MAP_NONE 0 /* maplength is expected to be 0 */
|
||||||
|
#define MAP_EQUAL_RGB 1 /* red[maplength/3],green[],blue[] */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTES:
|
||||||
|
* Each line of a bitmap image should be rounded out to a multiple
|
||||||
|
* of 16 bits.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* sunrast.c */
|
||||||
|
extern int ReadSunRaster(const char *, SUNHEAD **, unsigned char **, int *,
|
||||||
|
unsigned char **, int *, int *, int *, int *);
|
||||||
|
extern int WriteSunRaster(char *, unsigned char *, const int, const int,
|
||||||
|
const int);
|
||||||
|
|
||||||
|
#endif
|
455
libfprint/nbis/mindtct/binar.c
Normal file
455
libfprint/nbis/mindtct/binar.c
Normal file
|
@ -0,0 +1,455 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: BINAR.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 03/16/1999
|
||||||
|
UPDATED: 10/04/1999 Version 2 by MDG
|
||||||
|
UPDATED: 03/16/2005 by MDG
|
||||||
|
|
||||||
|
Contains routines responsible for binarizing a grayscale image based
|
||||||
|
on an arbitrarily-sized image and its precomputed direcitonal ridge
|
||||||
|
flow (IMAP) as part of the NIST Latent Fingerprint System (LFS).
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
binarize()
|
||||||
|
binarize_V2()
|
||||||
|
binarize_image()
|
||||||
|
binarize_image_V2()
|
||||||
|
dirbinarize()
|
||||||
|
isobinarize()
|
||||||
|
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#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
|
||||||
|
#cat: Direction Map and produces a binarized version of the
|
||||||
|
#cat: image. It then fills horizontal and vertical "holes" in
|
||||||
|
#cat: the binary image results. Note that the input image must
|
||||||
|
#cat: be padded sufficiently to contain in memory rotated
|
||||||
|
#cat: directional binarization grids applied to pixels along the
|
||||||
|
#cat: perimeter of the input image.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
pdata - padded input grayscale image
|
||||||
|
pw - padded width (in pixels) of input image
|
||||||
|
ph - padded height (in pixels) of input image
|
||||||
|
direction_map - 2-D vector of discrete ridge flow directions
|
||||||
|
mw - width (in blocks) of the map
|
||||||
|
mh - height (in blocks) of the map
|
||||||
|
dirbingrids - set of rotated grid offsets used for directional
|
||||||
|
binarization
|
||||||
|
lfsparms - parameters and thresholds for controlling LFS
|
||||||
|
Output:
|
||||||
|
odata - 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_V2(unsigned char **odata, int *ow, int *oh,
|
||||||
|
unsigned char *pdata, const int pw, const int ph,
|
||||||
|
int *direction_map, 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 directional block info. */
|
||||||
|
if((ret = binarize_image_V2(&bdata, &bw, &bh, pdata, pw, ph,
|
||||||
|
direction_map, mw, mh,
|
||||||
|
lfsparms->blocksize, dirbingrids))){
|
||||||
|
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. */
|
||||||
|
*odata = bdata;
|
||||||
|
*ow = bw;
|
||||||
|
*oh = bh;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: binarize_image - Takes a grayscale input image and its associated
|
||||||
|
#cat: NMAP and generates a binarized version of the image.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
pdata - padded input grayscale image
|
||||||
|
pw - padded width (in pixels) of input image
|
||||||
|
ph - padded height (in pixels) of input image
|
||||||
|
nmap - 2-D vector of IMAP directions and other codes
|
||||||
|
mw - width (in blocks) of the NMAP
|
||||||
|
mh - height (in blocks) of the NMAP
|
||||||
|
imap_blocksize - dimension (in pixels) of each NMAP block
|
||||||
|
dirbingrids - set of rotated grid offsets used for directional
|
||||||
|
binarization
|
||||||
|
isobin_grid_dim - dimension (in pixels) of grid used for isotropic
|
||||||
|
binarization
|
||||||
|
Output:
|
||||||
|
optr - points to binary image results
|
||||||
|
ow - points to binary image width
|
||||||
|
oh - points to binary image height
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int binarize_image(unsigned char **optr, int *ow, int *oh,
|
||||||
|
unsigned char *pdata, const int pw, const int ph,
|
||||||
|
const int *nmap, const int mw, const int mh,
|
||||||
|
const int imap_blocksize, const ROTGRIDS *dirbingrids,
|
||||||
|
const int isobin_grid_dim)
|
||||||
|
{
|
||||||
|
int ix, iy, bw, bh, bx, by, nmapval;
|
||||||
|
unsigned char *bdata, *bptr;
|
||||||
|
unsigned char *pptr, *spptr;
|
||||||
|
|
||||||
|
/* Compute dimensions of "unpadded" binary image results. */
|
||||||
|
bw = pw - (dirbingrids->pad<<1);
|
||||||
|
bh = ph - (dirbingrids->pad<<1);
|
||||||
|
|
||||||
|
bdata = (unsigned char *)malloc(bw*bh*sizeof(unsigned char));
|
||||||
|
if(bdata == (unsigned char *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : binarize_image : malloc : bdata\n");
|
||||||
|
return(-110);
|
||||||
|
}
|
||||||
|
|
||||||
|
bptr = bdata;
|
||||||
|
spptr = pdata + (dirbingrids->pad * pw) + dirbingrids->pad;
|
||||||
|
for(iy = 0; iy < bh; iy++){
|
||||||
|
/* Set pixel pointer to start of next row in grid. */
|
||||||
|
pptr = spptr;
|
||||||
|
for(ix = 0; ix < bw; ix++){
|
||||||
|
/* Compute which block the current pixel is in. */
|
||||||
|
bx = (int)(ix/imap_blocksize);
|
||||||
|
by = (int)(iy/imap_blocksize);
|
||||||
|
/* Get corresponding value in NMAP */
|
||||||
|
nmapval = *(nmap + (by*mw) + bx);
|
||||||
|
/* If current block has no neighboring blocks with */
|
||||||
|
/* VALID directions ... */
|
||||||
|
if(nmapval == NO_VALID_NBRS)
|
||||||
|
/* Set binary pixel to white (255). */
|
||||||
|
*bptr = WHITE_PIXEL;
|
||||||
|
/* Otherwise, if block's NMAP has a valid direction ... */
|
||||||
|
else if(nmapval >= 0)
|
||||||
|
/* Use directional binarization based on NMAP direction. */
|
||||||
|
*bptr = dirbinarize(pptr, nmapval, dirbingrids);
|
||||||
|
else
|
||||||
|
/* Otherwise, the block's NMAP is either INVALID or */
|
||||||
|
/* HIGH-CURVATURE, so use isotropic binarization. */
|
||||||
|
*bptr = isobinarize(pptr, pw, ph, isobin_grid_dim);
|
||||||
|
/* Bump input and output pixel pointers. */
|
||||||
|
pptr++;
|
||||||
|
bptr++;
|
||||||
|
}
|
||||||
|
/* Bump pointer to the next row in padded input image. */
|
||||||
|
spptr += pw;
|
||||||
|
}
|
||||||
|
|
||||||
|
*optr = bdata;
|
||||||
|
*ow = bw;
|
||||||
|
*oh = bh;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: binarize_image_V2 - Takes a grayscale input image and its associated
|
||||||
|
#cat: Direction Map and generates a binarized version of the
|
||||||
|
#cat: image. Note that there is no "Isotropic" binarization
|
||||||
|
#cat: used in this version.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
pdata - padded input grayscale image
|
||||||
|
pw - padded width (in pixels) of input image
|
||||||
|
ph - padded height (in pixels) of input image
|
||||||
|
direction_map - 2-D vector of discrete ridge flow directions
|
||||||
|
mw - width (in blocks) of the map
|
||||||
|
mh - height (in blocks) of the map
|
||||||
|
blocksize - dimension (in pixels) of each NMAP block
|
||||||
|
dirbingrids - set of rotated grid offsets used for directional
|
||||||
|
binarization
|
||||||
|
Output:
|
||||||
|
odata - 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_V2(unsigned char **odata, int *ow, int *oh,
|
||||||
|
unsigned char *pdata, const int pw, const int ph,
|
||||||
|
const int *direction_map, const int mw, const int mh,
|
||||||
|
const int blocksize, const ROTGRIDS *dirbingrids)
|
||||||
|
{
|
||||||
|
int ix, iy, bw, bh, bx, by, mapval;
|
||||||
|
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_V2 : malloc : bdata\n");
|
||||||
|
return(-600);
|
||||||
|
}
|
||||||
|
|
||||||
|
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/blocksize);
|
||||||
|
by = (int)(iy/blocksize);
|
||||||
|
/* Get corresponding value in Direction Map. */
|
||||||
|
mapval = *(direction_map + (by*mw) + bx);
|
||||||
|
/* If current block has has INVALID direction ... */
|
||||||
|
if(mapval == INVALID_DIR)
|
||||||
|
/* Set binary pixel to white (255). */
|
||||||
|
*bptr = WHITE_PIXEL;
|
||||||
|
/* Otherwise, if block has a valid direction ... */
|
||||||
|
else /*if(mapval >= 0)*/
|
||||||
|
/* Use directional binarization based on block's direction. */
|
||||||
|
*bptr = dirbinarize(pptr, mapval, dirbingrids);
|
||||||
|
|
||||||
|
/* Bump input and output pixel pointers. */
|
||||||
|
pptr++;
|
||||||
|
bptr++;
|
||||||
|
}
|
||||||
|
/* Bump pointer to the next row in padded input image. */
|
||||||
|
spptr += pw;
|
||||||
|
}
|
||||||
|
|
||||||
|
*odata = bdata;
|
||||||
|
*ow = bw;
|
||||||
|
*oh = bh;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: dirbinarize - Determines the binary value of a grayscale pixel based
|
||||||
|
#cat: on a VALID IMAP ridge flow direction.
|
||||||
|
|
||||||
|
CAUTION: The image to which the input pixel points must be appropriately
|
||||||
|
padded to account for the radius of the rotated grid. Otherwise,
|
||||||
|
this routine may access "unkown" memory.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
pptr - pointer to current grayscale pixel
|
||||||
|
idir - IMAP integer direction associated with the block the
|
||||||
|
current is in
|
||||||
|
dirbingrids - set of precomputed rotated grid offsets
|
||||||
|
Return Code:
|
||||||
|
BLACK_PIXEL - pixel intensity for BLACK
|
||||||
|
WHITE_PIXEL - pixel intensity of WHITE
|
||||||
|
**************************************************************************/
|
||||||
|
int dirbinarize(const unsigned char *pptr, const int idir,
|
||||||
|
const ROTGRIDS *dirbingrids)
|
||||||
|
{
|
||||||
|
int gx, gy, gi, cy;
|
||||||
|
int rsum, gsum, csum = 0;
|
||||||
|
int *grid;
|
||||||
|
double dcy;
|
||||||
|
|
||||||
|
/* Assign nickname pointer. */
|
||||||
|
grid = dirbingrids->grids[idir];
|
||||||
|
/* Calculate center (0-oriented) row in grid. */
|
||||||
|
dcy = (dirbingrids->grid_h-1)/(double)2.0;
|
||||||
|
/* Need to truncate precision so that answers are consistent */
|
||||||
|
/* on different computer architectures when rounding doubles. */
|
||||||
|
dcy = trunc_dbl_precision(dcy, TRUNC_SCALE);
|
||||||
|
cy = sround(dcy);
|
||||||
|
/* Initialize grid's pixel offset index to zero. */
|
||||||
|
gi = 0;
|
||||||
|
/* Initialize grid's pixel accumulator to zero */
|
||||||
|
gsum = 0;
|
||||||
|
|
||||||
|
/* Foreach row in grid ... */
|
||||||
|
for(gy = 0; gy < dirbingrids->grid_h; gy++){
|
||||||
|
/* Initialize row pixel sum to zero. */
|
||||||
|
rsum = 0;
|
||||||
|
/* Foreach column in grid ... */
|
||||||
|
for(gx = 0; gx < dirbingrids->grid_w; gx++){
|
||||||
|
/* Accumulate next pixel along rotated row in grid. */
|
||||||
|
rsum += *(pptr+grid[gi]);
|
||||||
|
/* Bump grid's pixel offset index. */
|
||||||
|
gi++;
|
||||||
|
}
|
||||||
|
/* Accumulate row sum into grid pixel sum. */
|
||||||
|
gsum += rsum;
|
||||||
|
/* If current row is center row, then save row sum separately. */
|
||||||
|
if(gy == cy)
|
||||||
|
csum = rsum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the center row sum treated as an average is less than the */
|
||||||
|
/* total pixel sum in the rotated grid ... */
|
||||||
|
if((csum * dirbingrids->grid_h) < gsum)
|
||||||
|
/* Set the binary pixel to BLACK. */
|
||||||
|
return(BLACK_PIXEL);
|
||||||
|
else
|
||||||
|
/* Otherwise set the binary pixel to WHITE. */
|
||||||
|
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);
|
||||||
|
}
|
377
libfprint/nbis/mindtct/block.c
Normal file
377
libfprint/nbis/mindtct/block.c
Normal file
|
@ -0,0 +1,377 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: BLOCK.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 03/16/1999
|
||||||
|
UPDATED: 10/04/1999 Version 2 by MDG
|
||||||
|
UPDATED: 03/16/2005 by MDG
|
||||||
|
|
||||||
|
Contains routines responsible for partitioning arbitrarily-
|
||||||
|
sized images into equally-sized blocks as part of the NIST
|
||||||
|
Latent Fingerprint System (LFS).
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
block_offsets()
|
||||||
|
low_contrast_block()
|
||||||
|
find_valid_block()
|
||||||
|
set_margin_blocks()
|
||||||
|
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: block_offsets - Divides an image into mw X mh equally sized blocks,
|
||||||
|
#cat: returning a list of offsets to the top left corner of each block.
|
||||||
|
#cat: For images that are even multiples of BLOCKSIZE, blocks do not
|
||||||
|
#cat: not overlap and are immediately adjacent to each other. For image
|
||||||
|
#cat: that are NOT even multiples of BLOCKSIZE, blocks continue to be
|
||||||
|
#cat: non-overlapping up to the last column and/or last row of blocks.
|
||||||
|
#cat: In these cases the blocks are adjacent to the edge of the image and
|
||||||
|
#cat: extend inwards BLOCKSIZE units, overlapping the neighboring column
|
||||||
|
#cat: or row of blocks. This routine also accounts for image padding
|
||||||
|
#cat: which makes things a little more "messy". This routine is primarily
|
||||||
|
#cat: responsible providing the ability to processs arbitrarily-sized
|
||||||
|
#cat: images. The strategy used here is simple, but others are possible.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
iw - width (in pixels) of the orginal input image
|
||||||
|
ih - height (in pixels) of the orginal input image
|
||||||
|
pad - the padding (in pixels) required to support the desired
|
||||||
|
range of block orientations for DFT analysis. This padding
|
||||||
|
is required along the entire perimeter of the input image.
|
||||||
|
For certain applications, the pad may be zero.
|
||||||
|
blocksize - the width and height (in pixels) of each image block
|
||||||
|
Output:
|
||||||
|
optr - points to the list of pixel offsets to the origin of
|
||||||
|
each block in the "padded" input image
|
||||||
|
ow - the number of horizontal blocks in the input image
|
||||||
|
oh - the number of vertical blocks in the input image
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int block_offsets(int **optr, int *ow, int *oh,
|
||||||
|
const int iw, const int ih, const int pad, const int blocksize)
|
||||||
|
{
|
||||||
|
int *blkoffs, bx, by, bw, bh, bi, bsize;
|
||||||
|
int blkrow_start, blkrow_size, offset;
|
||||||
|
int lastbw, lastbh;
|
||||||
|
int pad2, pw, ph;
|
||||||
|
|
||||||
|
/* Test if unpadded image is smaller than a single block */
|
||||||
|
if((iw < blocksize) || (ih < blocksize)){
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR : block_offsets : image must be at least %d by %d in size\n",
|
||||||
|
blocksize, blocksize);
|
||||||
|
return(-80);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute padded width and height of image */
|
||||||
|
pad2 = pad<<1;
|
||||||
|
pw = iw + pad2;
|
||||||
|
ph = ih + pad2;
|
||||||
|
|
||||||
|
/* Compute the number of columns and rows of blocks in the image. */
|
||||||
|
/* Take the ceiling to account for "leftovers" at the right and */
|
||||||
|
/* bottom of the unpadded image */
|
||||||
|
bw = (int)ceil(iw / (double)blocksize);
|
||||||
|
bh = (int)ceil(ih / (double)blocksize);
|
||||||
|
|
||||||
|
/* Total number of blocks in the image */
|
||||||
|
bsize = bw*bh;
|
||||||
|
|
||||||
|
/* The index of the last column */
|
||||||
|
lastbw = bw - 1;
|
||||||
|
/* The index of the last row */
|
||||||
|
lastbh = bh - 1;
|
||||||
|
|
||||||
|
/* Allocate list of block offsets */
|
||||||
|
blkoffs = (int *)malloc(bsize * sizeof(int));
|
||||||
|
if(blkoffs == (int *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : block_offsets : malloc : blkoffs\n");
|
||||||
|
return(-81);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Current block index */
|
||||||
|
bi = 0;
|
||||||
|
|
||||||
|
/* Current offset from top of padded image to start of new row of */
|
||||||
|
/* unpadded image blocks. It is initialize to account for the */
|
||||||
|
/* padding and will always be indented the size of the padding */
|
||||||
|
/* from the left edge of the padded image. */
|
||||||
|
blkrow_start = (pad * pw) + pad;
|
||||||
|
|
||||||
|
/* Number of pixels in a row of blocks in the padded image */
|
||||||
|
blkrow_size = pw * blocksize; /* row width X block height */
|
||||||
|
|
||||||
|
/* Foreach non-overlapping row of blocks in the image */
|
||||||
|
for(by = 0; by < lastbh; by++){
|
||||||
|
/* Current offset from top of padded image to beginning of */
|
||||||
|
/* the next block */
|
||||||
|
offset = blkrow_start;
|
||||||
|
/* Foreach non-overlapping column of blocks in the image */
|
||||||
|
for(bx = 0; bx < lastbw; bx++){
|
||||||
|
/* Store current block offset */
|
||||||
|
blkoffs[bi++] = offset;
|
||||||
|
/* Bump to the beginning of the next block */
|
||||||
|
offset += blocksize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute and store "left-over" block in row. */
|
||||||
|
/* This is the block in the last column of row. */
|
||||||
|
/* Start at far right edge of unpadded image data */
|
||||||
|
/* and come in BLOCKSIZE pixels. */
|
||||||
|
blkoffs[bi++] = blkrow_start + iw - blocksize;
|
||||||
|
/* Bump to beginning of next row of blocks */
|
||||||
|
blkrow_start += blkrow_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute and store "left-over" row of blocks at bottom of image */
|
||||||
|
/* Start at bottom edge of unpadded image data and come up */
|
||||||
|
/* BLOCKSIZE pixels. This too must account for padding. */
|
||||||
|
blkrow_start = ((pad + ih - blocksize) * pw) + pad;
|
||||||
|
/* Start the block offset for the last row at this point */
|
||||||
|
offset = blkrow_start;
|
||||||
|
/* Foreach non-overlapping column of blocks in last row of the image */
|
||||||
|
for(bx = 0; bx < lastbw; bx++){
|
||||||
|
/* Store current block offset */
|
||||||
|
blkoffs[bi++] = offset;
|
||||||
|
/* Bump to the beginning of the next block */
|
||||||
|
offset += blocksize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute and store last "left-over" block in last row. */
|
||||||
|
/* Start at right edge of unpadded image data and come in */
|
||||||
|
/* BLOCKSIZE pixels. */
|
||||||
|
blkoffs[bi++] = blkrow_start + iw - blocksize;
|
||||||
|
|
||||||
|
*optr = blkoffs;
|
||||||
|
*ow = bw;
|
||||||
|
*oh = bh;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
#cat: low_contrast_block - Takes the offset to an image block of specified
|
||||||
|
#cat: dimension, and analyzes the pixel intensities in the block
|
||||||
|
#cat: to determine if there is sufficient contrast for further
|
||||||
|
#cat: processing.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
blkoffset - byte offset into the padded input image to the origin of
|
||||||
|
the block to be analyzed
|
||||||
|
blocksize - dimension (in pixels) of the width and height of the block
|
||||||
|
(passing separate blocksize from LFSPARMS on purpose)
|
||||||
|
pdata - padded input image data (8 bits [0..256) grayscale)
|
||||||
|
pw - width (in pixels) of the padded input image
|
||||||
|
ph - height (in pixels) of the padded input image
|
||||||
|
lfsparms - parameters and thresholds for controlling LFS
|
||||||
|
Return Code:
|
||||||
|
TRUE - block has sufficiently low contrast
|
||||||
|
FALSE - block has sufficiently hight contrast
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************/
|
||||||
|
int low_contrast_block(const int blkoffset, const int blocksize,
|
||||||
|
unsigned char *pdata, const int pw, const int ph,
|
||||||
|
const LFSPARMS *lfsparms)
|
||||||
|
{
|
||||||
|
int pixtable[IMG_6BIT_PIX_LIMIT], numpix;
|
||||||
|
int px, py, pi;
|
||||||
|
unsigned char *sptr, *pptr;
|
||||||
|
int delta;
|
||||||
|
double tdbl;
|
||||||
|
int prctmin = 0, prctmax = 0, prctthresh;
|
||||||
|
int pixsum, found;
|
||||||
|
|
||||||
|
numpix = blocksize*blocksize;
|
||||||
|
memset(pixtable, 0, IMG_6BIT_PIX_LIMIT*sizeof(int));
|
||||||
|
|
||||||
|
tdbl = (lfsparms->percentile_min_max/100.0) * (double)(numpix-1);
|
||||||
|
tdbl = trunc_dbl_precision(tdbl, TRUNC_SCALE);
|
||||||
|
prctthresh = sround(tdbl);
|
||||||
|
|
||||||
|
sptr = pdata+blkoffset;
|
||||||
|
for(py = 0; py < blocksize; py++){
|
||||||
|
pptr = sptr;
|
||||||
|
for(px = 0; px < blocksize; px++){
|
||||||
|
pixtable[*pptr]++;
|
||||||
|
pptr++;
|
||||||
|
}
|
||||||
|
sptr += pw;
|
||||||
|
}
|
||||||
|
|
||||||
|
pi = 0;
|
||||||
|
pixsum = 0;
|
||||||
|
found = FALSE;
|
||||||
|
while(pi < IMG_6BIT_PIX_LIMIT){
|
||||||
|
pixsum += pixtable[pi];
|
||||||
|
if(pixsum >= prctthresh){
|
||||||
|
prctmin = pi;
|
||||||
|
found = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pi++;
|
||||||
|
}
|
||||||
|
if(!found){
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR : low_contrast_block : min percentile pixel not found\n");
|
||||||
|
return(-510);
|
||||||
|
}
|
||||||
|
|
||||||
|
pi = IMG_6BIT_PIX_LIMIT-1;
|
||||||
|
pixsum = 0;
|
||||||
|
found = FALSE;
|
||||||
|
while(pi >= 0){
|
||||||
|
pixsum += pixtable[pi];
|
||||||
|
if(pixsum >= prctthresh){
|
||||||
|
prctmax = pi;
|
||||||
|
found = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pi--;
|
||||||
|
}
|
||||||
|
if(!found){
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR : low_contrast_block : max percentile pixel not found\n");
|
||||||
|
return(-511);
|
||||||
|
}
|
||||||
|
|
||||||
|
delta = prctmax - prctmin;
|
||||||
|
|
||||||
|
if(delta < lfsparms->min_contrast_delta)
|
||||||
|
return(TRUE);
|
||||||
|
else
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: find_valid_block - Take a Direction Map, Low Contrast Map,
|
||||||
|
#cat: Starting block address, a direction and searches the
|
||||||
|
#cat: maps in the specified direction until either a block valid
|
||||||
|
#cat: direction is encountered or a block flagged as LOW CONTRAST
|
||||||
|
#cat: is encountered. If a valid direction is located, it and the
|
||||||
|
#cat: address of the corresponding block are returned with a
|
||||||
|
#cat: code of FOUND. Otherwise, a code of NOT_FOUND is returned.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
direction_map - map of blocks containing directional ridge flows
|
||||||
|
low_contrast_map - map of blocks flagged as LOW CONTRAST
|
||||||
|
sx - X-block coord where search starts in maps
|
||||||
|
sy - Y-block coord where search starts in maps
|
||||||
|
mw - number of blocks horizontally in the maps
|
||||||
|
mh - number of blocks vertically in the maps
|
||||||
|
x_incr - X-block increment to direct search
|
||||||
|
y_incr - Y-block increment to direct search
|
||||||
|
Output:
|
||||||
|
nbr_dir - valid direction found
|
||||||
|
nbr_x - X-block coord where valid direction found
|
||||||
|
nbr_y - Y-block coord where valid direction found
|
||||||
|
Return Code:
|
||||||
|
FOUND - neighboring block with valid direction found
|
||||||
|
NOT_FOUND - neighboring block with valid direction NOT found
|
||||||
|
**************************************************************************/
|
||||||
|
int find_valid_block(int *nbr_dir, int *nbr_x, int *nbr_y,
|
||||||
|
int *direction_map, int *low_contrast_map,
|
||||||
|
const int sx, const int sy,
|
||||||
|
const int mw, const int mh,
|
||||||
|
const int x_incr, const int y_incr)
|
||||||
|
{
|
||||||
|
int x, y, dir;
|
||||||
|
|
||||||
|
/* Initialize starting block coords. */
|
||||||
|
x = sx + x_incr;
|
||||||
|
y = sy + y_incr;
|
||||||
|
|
||||||
|
/* While we are not outside the boundaries of the map ... */
|
||||||
|
while((x >= 0) && (x < mw) && (y >= 0) && (y < mh)){
|
||||||
|
/* Stop unsuccessfully if we encounter a LOW CONTRAST block. */
|
||||||
|
if(*(low_contrast_map+(y*mw)+x))
|
||||||
|
return(NOT_FOUND);
|
||||||
|
|
||||||
|
/* Stop successfully if we encounter a block with valid direction. */
|
||||||
|
if((dir = *(direction_map+(y*mw)+x)) >= 0){
|
||||||
|
*nbr_dir = dir;
|
||||||
|
*nbr_x = x;
|
||||||
|
*nbr_y = y;
|
||||||
|
return(FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, advance to the next block in the map. */
|
||||||
|
x += x_incr;
|
||||||
|
y += y_incr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get here, then we did not find a valid block in the given */
|
||||||
|
/* direction in the map. */
|
||||||
|
return(NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: set_margin_blocks - Take an image map and sets its perimeter values to
|
||||||
|
#cat: the specified value.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
map - map of blocks to be modified
|
||||||
|
mw - number of blocks horizontally in the map
|
||||||
|
mh - number of blocks vertically in the map
|
||||||
|
margin_value - value to be assigned to the perimeter blocks
|
||||||
|
Output:
|
||||||
|
map - resulting map
|
||||||
|
**************************************************************************/
|
||||||
|
void set_margin_blocks(int *map, const int mw, const int mh,
|
||||||
|
const int margin_value)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
int *ptr1, *ptr2;
|
||||||
|
|
||||||
|
ptr1 = map;
|
||||||
|
ptr2 = map+((mh-1)*mw);
|
||||||
|
for(x = 0; x < mw; x++){
|
||||||
|
*ptr1++ = margin_value;
|
||||||
|
*ptr2++ = margin_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr1 = map + mw;
|
||||||
|
ptr2 = map + mw + mw - 1;
|
||||||
|
for(y = 1; y < mh-1; y++){
|
||||||
|
*ptr1 = margin_value;
|
||||||
|
*ptr2 = margin_value;
|
||||||
|
ptr1 += mw;
|
||||||
|
ptr2 += mw;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
191
libfprint/nbis/mindtct/chaincod.c
Normal file
191
libfprint/nbis/mindtct/chaincod.c
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: CHAINCODE.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 05/11/1999
|
||||||
|
|
||||||
|
Contains routines responsible for generating and manipulating
|
||||||
|
chain codes as part of the NIST Latent Fingerprint System (LFS).
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
chain_code_loop()
|
||||||
|
is_chain_clockwise()
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: chain_code_loop - Converts a feature's contour points into an
|
||||||
|
#cat: 8-connected chain code vector. This encoding represents
|
||||||
|
#cat: the direction taken between each adjacent point in the
|
||||||
|
#cat: contour. Chain codes may be used for many purposes, such
|
||||||
|
#cat: as computing the perimeter or area of an object, and they
|
||||||
|
#cat: may be used in object detection and recognition.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
contour_x - x-coord list for feature's contour points
|
||||||
|
contour_y - y-coord list for feature's contour points
|
||||||
|
ncontour - number of points in contour
|
||||||
|
Output:
|
||||||
|
ochain - resulting vector of chain codes
|
||||||
|
onchain - number of codes in chain
|
||||||
|
(same as number of points in contour)
|
||||||
|
Return Code:
|
||||||
|
Zero - chain code successful derived
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int chain_code_loop(int **ochain, int *onchain,
|
||||||
|
const int *contour_x, const int *contour_y, const int ncontour)
|
||||||
|
{
|
||||||
|
int *chain;
|
||||||
|
int i, j, dx, dy;
|
||||||
|
|
||||||
|
/* If we don't have at least 3 points in the contour ... */
|
||||||
|
if(ncontour <= 3){
|
||||||
|
/* Then we don't have a loop, so set chain length to 0 */
|
||||||
|
/* and return without any allocations. */
|
||||||
|
*onchain = 0;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate chain code vector. It will be the same length as the */
|
||||||
|
/* number of points in the contour. There will be one chain code */
|
||||||
|
/* between each point on the contour including a code between the */
|
||||||
|
/* last to the first point on the contour (completing the loop). */
|
||||||
|
chain = (int *)malloc(ncontour * sizeof(int));
|
||||||
|
/* If the allocation fails ... */
|
||||||
|
if(chain == (int *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : chain_code_loop : malloc : chain\n");
|
||||||
|
return(-170);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For each neighboring point in the list (with "i" pointing to the */
|
||||||
|
/* previous neighbor and "j" pointing to the next neighbor... */
|
||||||
|
for(i = 0, j=1; i < ncontour-1; i++, j++){
|
||||||
|
/* Compute delta in X between neighbors. */
|
||||||
|
dx = contour_x[j] - contour_x[i];
|
||||||
|
/* Compute delta in Y between neighbors. */
|
||||||
|
dy = contour_y[j] - contour_y[i];
|
||||||
|
/* Derive chain code index from neighbor deltas. */
|
||||||
|
/* The deltas are on the range [-1..1], so to use them as indices */
|
||||||
|
/* into the code list, they must first be incremented by one. */
|
||||||
|
chain[i] = *(chaincodes_nbr8+((dy+1)*NBR8_DIM)+dx+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now derive chain code between last and first points in the */
|
||||||
|
/* contour list. */
|
||||||
|
dx = contour_x[0] - contour_x[i];
|
||||||
|
dy = contour_y[0] - contour_y[i];
|
||||||
|
chain[i] = *(chaincodes_nbr8+((dy+1)*NBR8_DIM)+dx+1);
|
||||||
|
|
||||||
|
/* Store results to the output pointers. */
|
||||||
|
*ochain = chain;
|
||||||
|
*onchain = ncontour;
|
||||||
|
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: is_chain_clockwise - Takes an 8-connected chain code vector and
|
||||||
|
#cat: determines if the codes are ordered clockwise or
|
||||||
|
#cat: counter-clockwise.
|
||||||
|
#cat: The routine also requires a default return value be
|
||||||
|
#cat: specified in the case the the routine is not able to
|
||||||
|
#cat: definitively determine the chains direction. This allows
|
||||||
|
#cat: the default response to be application-specific.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
chain - chain code vector
|
||||||
|
nchain - number of codes in chain
|
||||||
|
default_ret - default return code (used when we can't tell the order)
|
||||||
|
Return Code:
|
||||||
|
TRUE - chain determined to be ordered clockwise
|
||||||
|
FALSE - chain determined to be ordered counter-clockwise
|
||||||
|
Default - could not determine the order of the chain
|
||||||
|
**************************************************************************/
|
||||||
|
int is_chain_clockwise(const int *chain, const int nchain,
|
||||||
|
const int default_ret)
|
||||||
|
{
|
||||||
|
int i, j, d, sum;
|
||||||
|
|
||||||
|
/* Initialize turn-accumulator to 0. */
|
||||||
|
sum = 0;
|
||||||
|
|
||||||
|
/* Foreach neighboring code in chain, compute the difference in */
|
||||||
|
/* direction and accumulate. Left-hand turns increment, whereas */
|
||||||
|
/* right-hand decrement. */
|
||||||
|
for(i = 0, j =1; i < nchain-1; i++, j++){
|
||||||
|
/* Compute delta in neighbor direction. */
|
||||||
|
d = chain[j] - chain[i];
|
||||||
|
/* Make the delta the "inner" distance. */
|
||||||
|
/* If delta >= 4, for example if chain_i==2 and chain_j==7 (which */
|
||||||
|
/* means the contour went from a step up to step down-to-the-right) */
|
||||||
|
/* then 5=(7-2) which is >=4, so -3=(5-8) which means that the */
|
||||||
|
/* change in direction is a righ-hand turn of 3 units). */
|
||||||
|
if(d >= 4)
|
||||||
|
d -= 8;
|
||||||
|
/* If delta <= -4, for example if chain_i==7 and chain_j==2 (which */
|
||||||
|
/* means the contour went from a step down-to-the-right to step up) */
|
||||||
|
/* then -5=(2-7) which is <=-4, so 3=(-5+8) which means that the */
|
||||||
|
/* change in direction is a left-hand turn of 3 units). */
|
||||||
|
else if (d <= -4)
|
||||||
|
d += 8;
|
||||||
|
|
||||||
|
/* The delta direction is then accumulated. */
|
||||||
|
sum += d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we need to add in the final delta direction between the last */
|
||||||
|
/* and first codes in the chain. */
|
||||||
|
d = chain[0] - chain[i];
|
||||||
|
if(d >= 4)
|
||||||
|
d -= 8;
|
||||||
|
else if (d <= -4)
|
||||||
|
d += 8;
|
||||||
|
sum += d;
|
||||||
|
|
||||||
|
/* If the final turn_accumulator == 0, then we CAN'T TELL the */
|
||||||
|
/* direction of the chain code, so return the default return value. */
|
||||||
|
if(sum == 0)
|
||||||
|
return(default_ret);
|
||||||
|
/* Otherwise, if the final turn-accumulator is positive ... */
|
||||||
|
else if(sum > 0)
|
||||||
|
/* Then we had a greater amount of left-hand turns than right-hand */
|
||||||
|
/* turns, so the chain is in COUNTER-CLOCKWISE order, so return FALSE. */
|
||||||
|
return(FALSE);
|
||||||
|
/* Otherwise, the final turn-accumulator is negative ... */
|
||||||
|
else
|
||||||
|
/* So we had a greater amount of right-hand turns than left-hand */
|
||||||
|
/* turns, so the chain is in CLOCKWISE order, so return TRUE. */
|
||||||
|
return(TRUE);
|
||||||
|
}
|
1274
libfprint/nbis/mindtct/contour.c
Normal file
1274
libfprint/nbis/mindtct/contour.c
Normal file
File diff suppressed because it is too large
Load diff
709
libfprint/nbis/mindtct/detect.c
Normal file
709
libfprint/nbis/mindtct/detect.c
Normal file
|
@ -0,0 +1,709 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: DETECT.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 08/16/1999
|
||||||
|
UPDATED: 10/04/1999 Version 2 by MDG
|
||||||
|
UPDATED: 03/16/2005 by MDG
|
||||||
|
|
||||||
|
Takes an 8-bit grayscale fingerpinrt image and detects minutiae
|
||||||
|
as part of the NIST Latent Fingerprint System (LFS).
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
lfs_detect_minutiae()
|
||||||
|
lfs_detect_minutiae_V2()
|
||||||
|
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#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,
|
||||||
|
#cat: a binarized image designating ridges from valleys,
|
||||||
|
#cat: and a list of minutiae (including position, reliability,
|
||||||
|
#cat: type, direction, neighbors, and ridge counts to neighbors).
|
||||||
|
#cat: The image maps include a ridge flow directional map,
|
||||||
|
#cat: a map of low contrast blocks, a map of low ridge flow blocks.
|
||||||
|
#cat: and a map of high-curvature blocks.
|
||||||
|
|
||||||
|
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
|
||||||
|
odmap - resulting Direction Map
|
||||||
|
{invalid (-1) or valid ridge directions}
|
||||||
|
olcmap - resulting Low Contrast Map
|
||||||
|
{low contrast (TRUE), high contrast (FALSE)}
|
||||||
|
olfmap - resulting Low Ridge Flow Map
|
||||||
|
{low ridge flow (TRUE), high ridge flow (FALSE)}
|
||||||
|
ohcmap - resulting High Curvature Map
|
||||||
|
{high curvature (TRUE), low curvature (FALSE)}
|
||||||
|
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_V2(MINUTIAE **ominutiae,
|
||||||
|
int **odmap, int **olcmap, int **olfmap, int **ohcmap,
|
||||||
|
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 *direction_map, *low_contrast_map, *low_flow_map, *high_curve_map;
|
||||||
|
int 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_V2(lfsparms->windowsize, lfsparms->windowoffset,
|
||||||
|
lfsparms->dirbin_grid_w, lfsparms->dirbin_grid_h);
|
||||||
|
|
||||||
|
/* Initialize lookup table for converting integer 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->windowsize))){
|
||||||
|
/* 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->windowsize, lfsparms->windowsize,
|
||||||
|
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_V2 : malloc : pdata\n");
|
||||||
|
return(-580);
|
||||||
|
}
|
||||||
|
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. Also, if not */
|
||||||
|
/* careful, I think accumulated power magnitudes may overflow */
|
||||||
|
/* doubles. */
|
||||||
|
bits_8to6(pdata, pw, ph);
|
||||||
|
|
||||||
|
print2log("\nINITIALIZATION AND PADDING DONE\n");
|
||||||
|
|
||||||
|
/******************/
|
||||||
|
/* MAPS */
|
||||||
|
/******************/
|
||||||
|
set_timer(imap_timer);
|
||||||
|
|
||||||
|
/* Generate block maps from the input image. */
|
||||||
|
if((ret = gen_image_maps(&direction_map, &low_contrast_map,
|
||||||
|
&low_flow_map, &high_curve_map, &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);
|
||||||
|
}
|
||||||
|
/* Deallocate working memories. */
|
||||||
|
free_dir2rad(dir2rad);
|
||||||
|
free_dftwaves(dftwaves);
|
||||||
|
free_rotgrids(dftgrids);
|
||||||
|
|
||||||
|
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. */
|
||||||
|
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(direction_map);
|
||||||
|
free(low_contrast_map);
|
||||||
|
free(low_flow_map);
|
||||||
|
free(high_curve_map);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Binarize input image based on NMAP information. */
|
||||||
|
if((ret = binarize_V2(&bdata, &bw, &bh,
|
||||||
|
pdata, pw, ph, direction_map, mw, mh,
|
||||||
|
dirbingrids, lfsparms))){
|
||||||
|
/* Free memory allocated to this point. */
|
||||||
|
free(pdata);
|
||||||
|
free(direction_map);
|
||||||
|
free(low_contrast_map);
|
||||||
|
free(low_flow_map);
|
||||||
|
free(high_curve_map);
|
||||||
|
free_rotgrids(dirbingrids);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deallocate working memory. */
|
||||||
|
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(direction_map);
|
||||||
|
free(low_contrast_map);
|
||||||
|
free(low_flow_map);
|
||||||
|
free(high_curve_map);
|
||||||
|
free(bdata);
|
||||||
|
fprintf(stderr, "ERROR : lfs_detect_minutiae_V2 :");
|
||||||
|
fprintf(stderr,"binary image has bad dimensions : %d, %d\n",
|
||||||
|
bw, bh);
|
||||||
|
return(-581);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 initial list of minutia pointers. */
|
||||||
|
if((ret = alloc_minutiae(&minutiae, MAX_MINUTIAE))){
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detect the minutiae in the binarized image. */
|
||||||
|
if((ret = detect_minutiae_V2(minutiae, bdata, iw, ih,
|
||||||
|
direction_map, low_flow_map, high_curve_map,
|
||||||
|
mw, mh, lfsparms))){
|
||||||
|
/* Free memory allocated to this point. */
|
||||||
|
free(pdata);
|
||||||
|
free(direction_map);
|
||||||
|
free(low_contrast_map);
|
||||||
|
free(low_flow_map);
|
||||||
|
free(high_curve_map);
|
||||||
|
free(bdata);
|
||||||
|
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))){
|
||||||
|
/* Free memory allocated to this point. */
|
||||||
|
free(pdata);
|
||||||
|
free(direction_map);
|
||||||
|
free(low_contrast_map);
|
||||||
|
free(low_flow_map);
|
||||||
|
free(high_curve_map);
|
||||||
|
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(direction_map);
|
||||||
|
free(low_contrast_map);
|
||||||
|
free(low_flow_map);
|
||||||
|
free(high_curve_map);
|
||||||
|
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. */
|
||||||
|
*odmap = direction_map;
|
||||||
|
*olcmap = low_contrast_map;
|
||||||
|
*olfmap = low_flow_map;
|
||||||
|
*ohcmap = high_curve_map;
|
||||||
|
*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 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);
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
358
libfprint/nbis/mindtct/dft.c
Normal file
358
libfprint/nbis/mindtct/dft.c
Normal file
|
@ -0,0 +1,358 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: DFT.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 03/16/1999
|
||||||
|
UPDATED: 03/16/2005 by MDG
|
||||||
|
|
||||||
|
Contains routines responsible for conducting Discrete Fourier
|
||||||
|
Transforms (DFT) analysis on a block of image data as part of
|
||||||
|
the NIST Latent Fingerprint System (LFS).
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
dft_dir_powers()
|
||||||
|
sum_rot_block_rows()
|
||||||
|
dft_power()
|
||||||
|
dft_power_stats()
|
||||||
|
get_max_norm()
|
||||||
|
sort_dft_waves()
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: dft_dir_powers - Conducts the DFT analysis on a block of image data.
|
||||||
|
#cat: The image block is sampled across a range of orientations
|
||||||
|
#cat: (directions) and multiple wave forms of varying frequency are
|
||||||
|
#cat: applied at each orientation. At each orentation, pixels are
|
||||||
|
#cat: accumulated along each rotated pixel row, creating a vector
|
||||||
|
#cat: of pixel row sums. Each DFT wave form is then applied
|
||||||
|
#cat: individually to this vector of pixel row sums. A DFT power
|
||||||
|
#cat: value is computed for each wave form (frequency0 at each
|
||||||
|
#cat: orientaion within the image block. Therefore, the resulting DFT
|
||||||
|
#cat: power vectors are of dimension (N Waves X M Directions).
|
||||||
|
#cat: The power signatures derived form this process are used to
|
||||||
|
#cat: determine dominant direction flow within the image block.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
pdata - the padded input image. It is important that the image
|
||||||
|
be properly padded, or else the sampling at various block
|
||||||
|
orientations may result in accessing unkown memory.
|
||||||
|
blkoffset - the pixel offset form the origin of the padded image to
|
||||||
|
the origin of the current block in the image
|
||||||
|
pw - the width (in pixels) of the padded input image
|
||||||
|
ph - the height (in pixels) of the padded input image
|
||||||
|
dftwaves - structure containing the DFT wave forms
|
||||||
|
dftgrids - structure containing the rotated pixel grid offsets
|
||||||
|
Output:
|
||||||
|
powers - DFT power computed from each wave form frequencies at each
|
||||||
|
orientation (direction) in the current image block
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int dft_dir_powers(double **powers, unsigned char *pdata,
|
||||||
|
const int blkoffset, const int pw, const int ph,
|
||||||
|
const DFTWAVES *dftwaves, const ROTGRIDS *dftgrids)
|
||||||
|
{
|
||||||
|
int w, dir;
|
||||||
|
int *rowsums;
|
||||||
|
unsigned char *blkptr;
|
||||||
|
|
||||||
|
/* Allocate line sum vector, and initialize to zeros */
|
||||||
|
/* This routine requires square block (grid), so ERROR otherwise. */
|
||||||
|
if(dftgrids->grid_w != dftgrids->grid_h){
|
||||||
|
fprintf(stderr, "ERROR : dft_dir_powers : DFT grids must be square\n");
|
||||||
|
return(-90);
|
||||||
|
}
|
||||||
|
rowsums = (int *)malloc(dftgrids->grid_w * sizeof(int));
|
||||||
|
if(rowsums == (int *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : dft_dir_powers : malloc : rowsums\n");
|
||||||
|
return(-91);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Foreach direction ... */
|
||||||
|
for(dir = 0; dir < dftgrids->ngrids; dir++){
|
||||||
|
/* Compute vector of line sums from rotated grid */
|
||||||
|
blkptr = pdata + blkoffset;
|
||||||
|
sum_rot_block_rows(rowsums, blkptr,
|
||||||
|
dftgrids->grids[dir], dftgrids->grid_w);
|
||||||
|
|
||||||
|
/* Foreach DFT wave ... */
|
||||||
|
for(w = 0; w < dftwaves->nwaves; w++){
|
||||||
|
dft_power(&(powers[w][dir]), rowsums,
|
||||||
|
dftwaves->waves[w], dftwaves->wavelen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deallocate working memory. */
|
||||||
|
free(rowsums);
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: sum_rot_block_rows - Computes a vector or pixel row sums by sampling
|
||||||
|
#cat: the current image block at a given orientation. The
|
||||||
|
#cat: sampling is conducted using a precomputed set of rotated
|
||||||
|
#cat: pixel offsets (called a grid) relative to the orgin of
|
||||||
|
#cat: the image block.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
blkptr - the pixel address of the origin of the current image block
|
||||||
|
grid_offsets - the rotated pixel offsets for a block-sized grid
|
||||||
|
rotated according to a specific orientation
|
||||||
|
blocksize - the width and height of the image block and thus the size
|
||||||
|
of the rotated grid
|
||||||
|
Output:
|
||||||
|
rowsums - the resulting vector of pixel row sums
|
||||||
|
**************************************************************************/
|
||||||
|
void sum_rot_block_rows(int *rowsums, const unsigned char *blkptr,
|
||||||
|
const int *grid_offsets, const int blocksize)
|
||||||
|
{
|
||||||
|
int ix, iy, gi;
|
||||||
|
|
||||||
|
/* Initialize rotation offset index. */
|
||||||
|
gi = 0;
|
||||||
|
|
||||||
|
/* For each row in block ... */
|
||||||
|
for(iy = 0; iy < blocksize; iy++){
|
||||||
|
/* The sums are accumlated along the rotated rows of the grid, */
|
||||||
|
/* so initialize row sum to 0. */
|
||||||
|
rowsums[iy] = 0;
|
||||||
|
/* Foreach column in block ... */
|
||||||
|
for(ix = 0; ix < blocksize; ix++){
|
||||||
|
/* Accumulate pixel value at rotated grid position in image */
|
||||||
|
rowsums[iy] += *(blkptr + grid_offsets[gi]);
|
||||||
|
gi++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: dft_power - Computes the DFT power by applying a specific wave form
|
||||||
|
#cat: frequency to a vector of pixel row sums computed from a
|
||||||
|
#cat: specific orientation of the block image
|
||||||
|
|
||||||
|
Input:
|
||||||
|
rowsums - accumulated rows of pixels from within a rotated grid
|
||||||
|
overlaying an input image block
|
||||||
|
wave - the wave form (cosine and sine components) at a specific
|
||||||
|
frequency
|
||||||
|
wavelen - the length of the wave form (must match the height of the
|
||||||
|
image block which is the length of the rowsum vector)
|
||||||
|
Output:
|
||||||
|
power - the computed DFT power for the given wave form at the
|
||||||
|
given orientation within the image block
|
||||||
|
**************************************************************************/
|
||||||
|
void dft_power(double *power, const int *rowsums,
|
||||||
|
const DFTWAVE *wave, const int wavelen)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double cospart, sinpart;
|
||||||
|
|
||||||
|
/* Initialize accumulators */
|
||||||
|
cospart = 0.0;
|
||||||
|
sinpart = 0.0;
|
||||||
|
|
||||||
|
/* Accumulate cos and sin components of DFT. */
|
||||||
|
for(i = 0; i < wavelen; i++){
|
||||||
|
/* Multiply each rotated row sum by its */
|
||||||
|
/* corresponding cos or sin point in DFT wave. */
|
||||||
|
cospart += (rowsums[i] * wave->cos[i]);
|
||||||
|
sinpart += (rowsums[i] * wave->sin[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Power is the sum of the squared cos and sin components */
|
||||||
|
*power = (cospart * cospart) + (sinpart * sinpart);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: dft_power_stats - Derives statistics from a set of DFT power vectors.
|
||||||
|
#cat: Statistics are computed for all but the lowest frequency
|
||||||
|
#cat: wave form, including the Maximum power for each wave form,
|
||||||
|
#cat: the direction at which the maximum power occured, and a
|
||||||
|
#cat: normalized value for the maximum power. In addition, the
|
||||||
|
#cat: statistics are ranked in descending order based on normalized
|
||||||
|
#cat: squared maximum power. These statistics are fundamental
|
||||||
|
#cat: to selecting a dominant direction flow for the current
|
||||||
|
#cat: input image block.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
powers - DFT power vectors (N Waves X M Directions) computed for
|
||||||
|
the current image block from which the values in the
|
||||||
|
statistics arrays are derived
|
||||||
|
fw - the beginning of the range of wave form indices from which
|
||||||
|
the statistcs are to derived
|
||||||
|
tw - the ending of the range of wave form indices from which
|
||||||
|
the statistcs are to derived (last index is tw-1)
|
||||||
|
ndirs - number of orientations (directions) at which the DFT
|
||||||
|
analysis was conducted
|
||||||
|
Output:
|
||||||
|
wis - list of ranked wave form indicies of the corresponding
|
||||||
|
statistics based on normalized squared maximum power. These
|
||||||
|
indices will be used as indirect addresses when processing
|
||||||
|
the power statistics in descending order of "dominance"
|
||||||
|
powmaxs - array holding the maximum DFT power for each wave form
|
||||||
|
(other than the lowest frequecy)
|
||||||
|
powmax_dirs - array to holding the direction corresponding to
|
||||||
|
each maximum power value in powmaxs
|
||||||
|
pownorms - array to holding the normalized maximum powers corresponding
|
||||||
|
to each value in powmaxs
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int dft_power_stats(int *wis, double *powmaxs, int *powmax_dirs,
|
||||||
|
double *pownorms, double **powers,
|
||||||
|
const int fw, const int tw, const int ndirs)
|
||||||
|
{
|
||||||
|
int w, i;
|
||||||
|
int ret; /* return code */
|
||||||
|
|
||||||
|
for(w = fw, i = 0; w < tw; w++, i++){
|
||||||
|
get_max_norm(&(powmaxs[i]), &(powmax_dirs[i]),
|
||||||
|
&(pownorms[i]), powers[w], ndirs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get sorted order of applied DFT waves based on normalized power */
|
||||||
|
if((ret = sort_dft_waves(wis, powmaxs, pownorms, tw-fw)))
|
||||||
|
return(ret);
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: get_max_norm - Analyses a DFT power vector for a specific wave form
|
||||||
|
#cat: applied at different orientations (directions) to the
|
||||||
|
#cat: current image block. The routine retuns the maximum
|
||||||
|
#cat: power value in the vector, the direction at which the
|
||||||
|
#cat: maximum occurs, and a normalized power value. The
|
||||||
|
#cat: normalized power is computed as the maximum power divided
|
||||||
|
#cat: by the average power across all the directions. These
|
||||||
|
#cat: simple statistics are fundamental to the selection of
|
||||||
|
#cat: a dominant direction flow for the image block.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
power_vector - the DFT power values derived form a specific wave form
|
||||||
|
applied at different directions
|
||||||
|
ndirs - the number of directions to which the wave form was applied
|
||||||
|
Output:
|
||||||
|
powmax - the maximum power value in the DFT power vector
|
||||||
|
powmax_dir - the direciton at which the maximum power value occured
|
||||||
|
pownorm - the normalized power corresponding to the maximum power
|
||||||
|
**************************************************************************/
|
||||||
|
void get_max_norm(double *powmax, int *powmax_dir,
|
||||||
|
double *pownorm, const double *power_vector, const int ndirs)
|
||||||
|
{
|
||||||
|
int dir;
|
||||||
|
double max_v, powsum;
|
||||||
|
int max_i;
|
||||||
|
double powmean;
|
||||||
|
|
||||||
|
/* Find max power value and store corresponding direction */
|
||||||
|
max_v = power_vector[0];
|
||||||
|
max_i = 0;
|
||||||
|
|
||||||
|
/* Sum the total power in a block at a given direction */
|
||||||
|
powsum = power_vector[0];
|
||||||
|
|
||||||
|
/* For each direction ... */
|
||||||
|
for(dir = 1; dir < ndirs; dir++){
|
||||||
|
powsum += power_vector[dir];
|
||||||
|
if(power_vector[dir] > max_v){
|
||||||
|
max_v = power_vector[dir];
|
||||||
|
max_i = dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*powmax = max_v;
|
||||||
|
*powmax_dir = max_i;
|
||||||
|
|
||||||
|
/* Powmean is used as denominator for pownorm, so setting */
|
||||||
|
/* a non-zero minimum avoids possible division by zero. */
|
||||||
|
powmean = max(powsum, MIN_POWER_SUM)/(double)ndirs;
|
||||||
|
|
||||||
|
*pownorm = *powmax / powmean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: sort_dft_waves - Creates a ranked list of DFT wave form statistics
|
||||||
|
#cat: by sorting on the normalized squared maximum power.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
powmaxs - maximum DFT power for each wave form used to derive
|
||||||
|
statistics
|
||||||
|
pownorms - normalized maximum power corresponding to values in powmaxs
|
||||||
|
nstats - number of wave forms used to derive statistics (N Wave - 1)
|
||||||
|
Output:
|
||||||
|
wis - sorted list of indices corresponding to the ranked set of
|
||||||
|
wave form statistics. These indices will be used as
|
||||||
|
indirect addresses when processing the power statistics
|
||||||
|
in descending order of "dominance"
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int sort_dft_waves(int *wis, const double *powmaxs, const double *pownorms,
|
||||||
|
const int nstats)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double *pownorms2;
|
||||||
|
|
||||||
|
/* Allocate normalized power^2 array */
|
||||||
|
pownorms2 = (double *)malloc(nstats * sizeof(double));
|
||||||
|
if(pownorms2 == (double *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : sort_dft_waves : malloc : pownorms2\n");
|
||||||
|
return(-100);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < nstats; i++){
|
||||||
|
/* Wis will hold the sorted statistic indices when all is done. */
|
||||||
|
wis[i] = i;
|
||||||
|
/* This is normalized squared max power. */
|
||||||
|
pownorms2[i] = powmaxs[i] * pownorms[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sort the statistic indices on the normalized squared power. */
|
||||||
|
bubble_sort_double_dec_2(pownorms2, wis, nstats);
|
||||||
|
|
||||||
|
/* Deallocate the working memory. */
|
||||||
|
free(pownorms2);
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
116
libfprint/nbis/mindtct/free.c
Normal file
116
libfprint/nbis/mindtct/free.c
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: FREE.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 03/16/1999
|
||||||
|
|
||||||
|
Contains routines responsible for deallocating
|
||||||
|
memories required by the NIST Latent Fingerprint System (LFS).
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
free_dir2rad()
|
||||||
|
free_dftwaves()
|
||||||
|
free_rotgrids()
|
||||||
|
free_dir_powers()
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: free_dir2rad - Deallocates memory associated with a DIR2RAD structure
|
||||||
|
|
||||||
|
Input:
|
||||||
|
dir2rad - pointer to memory to be freed
|
||||||
|
*************************************************************************/
|
||||||
|
void free_dir2rad(DIR2RAD *dir2rad)
|
||||||
|
{
|
||||||
|
free(dir2rad->cos);
|
||||||
|
free(dir2rad->sin);
|
||||||
|
free(dir2rad);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: free_dftwaves - Deallocates the memory associated with a DFTWAVES
|
||||||
|
#cat: structure
|
||||||
|
|
||||||
|
Input:
|
||||||
|
dftwaves - pointer to memory to be freed
|
||||||
|
**************************************************************************/
|
||||||
|
void free_dftwaves(DFTWAVES *dftwaves)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < dftwaves->nwaves; i++){
|
||||||
|
free(dftwaves->waves[i]->cos);
|
||||||
|
free(dftwaves->waves[i]->sin);
|
||||||
|
free(dftwaves->waves[i]);
|
||||||
|
}
|
||||||
|
free(dftwaves->waves);
|
||||||
|
free(dftwaves);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: free_rotgrids - Deallocates the memory associated with a ROTGRIDS
|
||||||
|
#cat: structure
|
||||||
|
|
||||||
|
Input:
|
||||||
|
rotgrids - pointer to memory to be freed
|
||||||
|
**************************************************************************/
|
||||||
|
void free_rotgrids(ROTGRIDS *rotgrids)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < rotgrids->ngrids; i++)
|
||||||
|
free(rotgrids->grids[i]);
|
||||||
|
free(rotgrids->grids);
|
||||||
|
free(rotgrids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: free_dir_powers - Deallocate memory associated with DFT power vectors
|
||||||
|
|
||||||
|
Input:
|
||||||
|
powers - vectors of DFT power values (N Waves X M Directions)
|
||||||
|
nwaves - number of DFT wave forms used
|
||||||
|
**************************************************************************/
|
||||||
|
void free_dir_powers(double **powers, const int nwaves)
|
||||||
|
{
|
||||||
|
int w;
|
||||||
|
|
||||||
|
for(w = 0; w < nwaves; w++)
|
||||||
|
free(powers[w]);
|
||||||
|
|
||||||
|
free(powers);
|
||||||
|
}
|
||||||
|
|
155
libfprint/nbis/mindtct/getmin.c
Normal file
155
libfprint/nbis/mindtct/getmin.c
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: GETMIN.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 09/10/2004
|
||||||
|
UPDATED: 03/16/2005 by MDG
|
||||||
|
|
||||||
|
Takes an 8-bit grayscale fingerpinrt image and detects minutiae
|
||||||
|
as part of the NIST Latent Fingerprint System (LFS), returning
|
||||||
|
minutiae with final reliabilities and maps including a merged
|
||||||
|
quality map.
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
get_minutiae()
|
||||||
|
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: get_minutiae - Takes a grayscale fingerprint image, binarizes the input
|
||||||
|
#cat: image, and detects minutiae points using LFS Version 2.
|
||||||
|
#cat: The routine passes back the detected minutiae, the
|
||||||
|
#cat: binarized image, and a set of image quality maps.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
idata - grayscale fingerprint image data
|
||||||
|
iw - width (in pixels) of the grayscale image
|
||||||
|
ih - height (in pixels) of the grayscale image
|
||||||
|
id - pixel depth (in bits) of the grayscale image
|
||||||
|
ppmm - the scan resolution (in pixels/mm) of the grayscale image
|
||||||
|
lfsparms - parameters and thresholds for controlling LFS
|
||||||
|
Output:
|
||||||
|
ominutiae - points to a structure containing the
|
||||||
|
detected minutiae
|
||||||
|
oquality_map - resulting integrated image quality map
|
||||||
|
odirection_map - resulting direction map
|
||||||
|
olow_contrast_map - resulting low contrast map
|
||||||
|
olow_flow_map - resulting low ridge flow map
|
||||||
|
ohigh_curve_map - resulting high curvature map
|
||||||
|
omap_w - width (in blocks) of image maps
|
||||||
|
omap_h - height (in blocks) of image maps
|
||||||
|
obdata - points to binarized image data
|
||||||
|
obw - width (in pixels) of binarized image
|
||||||
|
obh - height (in pixels) of binarized image
|
||||||
|
obd - pixel depth (in bits) of binarized image
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int get_minutiae(MINUTIAE **ominutiae, int **oquality_map,
|
||||||
|
int **odirection_map, int **olow_contrast_map,
|
||||||
|
int **olow_flow_map, int **ohigh_curve_map,
|
||||||
|
int *omap_w, int *omap_h,
|
||||||
|
unsigned char **obdata, int *obw, int *obh, int *obd,
|
||||||
|
unsigned char *idata, const int iw, const int ih,
|
||||||
|
const int id, const double ppmm, const LFSPARMS *lfsparms)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
MINUTIAE *minutiae;
|
||||||
|
int *direction_map, *low_contrast_map, *low_flow_map;
|
||||||
|
int *high_curve_map, *quality_map;
|
||||||
|
int map_w, map_h;
|
||||||
|
unsigned char *bdata;
|
||||||
|
int bw, bh;
|
||||||
|
|
||||||
|
/* If input image is not 8-bit grayscale ... */
|
||||||
|
if(id != 8){
|
||||||
|
fprintf(stderr, "ERROR : get_minutiae : input image pixel ");
|
||||||
|
fprintf(stderr, "depth = %d != 8.\n", id);
|
||||||
|
return(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detect minutiae in grayscale fingerpeint image. */
|
||||||
|
if((ret = lfs_detect_minutiae_V2(&minutiae,
|
||||||
|
&direction_map, &low_contrast_map,
|
||||||
|
&low_flow_map, &high_curve_map,
|
||||||
|
&map_w, &map_h,
|
||||||
|
&bdata, &bw, &bh,
|
||||||
|
idata, iw, ih, lfsparms))){
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build integrated quality map. */
|
||||||
|
if((ret = gen_quality_map(&quality_map,
|
||||||
|
direction_map, low_contrast_map,
|
||||||
|
low_flow_map, high_curve_map, map_w, map_h))){
|
||||||
|
free_minutiae(minutiae);
|
||||||
|
free(direction_map);
|
||||||
|
free(low_contrast_map);
|
||||||
|
free(low_flow_map);
|
||||||
|
free(high_curve_map);
|
||||||
|
free(bdata);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign reliability from quality map. */
|
||||||
|
if((ret = combined_minutia_quality(minutiae, quality_map, map_w, map_h,
|
||||||
|
lfsparms->blocksize,
|
||||||
|
idata, iw, ih, id, ppmm))){
|
||||||
|
free_minutiae(minutiae);
|
||||||
|
free(direction_map);
|
||||||
|
free(low_contrast_map);
|
||||||
|
free(low_flow_map);
|
||||||
|
free(high_curve_map);
|
||||||
|
free(quality_map);
|
||||||
|
free(bdata);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set output pointers. */
|
||||||
|
*ominutiae = minutiae;
|
||||||
|
*oquality_map = quality_map;
|
||||||
|
*odirection_map = direction_map;
|
||||||
|
*olow_contrast_map = low_contrast_map;
|
||||||
|
*olow_flow_map = low_flow_map;
|
||||||
|
*ohigh_curve_map = high_curve_map;
|
||||||
|
*omap_w = map_w;
|
||||||
|
*omap_h = map_h;
|
||||||
|
*obdata = bdata;
|
||||||
|
*obw = bw;
|
||||||
|
*obh = bh;
|
||||||
|
*obd = id;
|
||||||
|
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
293
libfprint/nbis/mindtct/globals.c
Normal file
293
libfprint/nbis/mindtct/globals.c
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: GLOBALS.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 03/16/1999
|
||||||
|
UPDATED: 10/04/1999 Version 2 by MDG
|
||||||
|
|
||||||
|
Contains general global variable definitions required by the
|
||||||
|
NIST Latent Fingerprint System (LFS).
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
/*************************************************************************/
|
||||||
|
/* GOBAL DECLARATIONS */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#ifdef LOG_REPORT
|
||||||
|
FILE *logfp;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Constants (C) for defining 4 DFT frequencies, where */
|
||||||
|
/* frequency is defined as C*(PI_FACTOR). PI_FACTOR */
|
||||||
|
/* regulates the period of the function in x, so: */
|
||||||
|
/* 1 = one period in range X. */
|
||||||
|
/* 2 = twice the frequency in range X. */
|
||||||
|
/* 3 = three times the frequency in reange X. */
|
||||||
|
/* 4 = four times the frequency in ranage X. */
|
||||||
|
double dft_coefs[NUM_DFT_WAVES] = { 1,2,3,4 };
|
||||||
|
|
||||||
|
/* Allocate and initialize a global LFS parameters structure. */
|
||||||
|
LFSPARMS lfsparms = {
|
||||||
|
/* Image Controls */
|
||||||
|
PAD_VALUE,
|
||||||
|
JOIN_LINE_RADIUS,
|
||||||
|
|
||||||
|
/* Map Controls */
|
||||||
|
IMAP_BLOCKSIZE,
|
||||||
|
UNUSED_INT, /* windowsize */
|
||||||
|
UNUSED_INT, /* windowoffset */
|
||||||
|
NUM_DIRECTIONS,
|
||||||
|
START_DIR_ANGLE,
|
||||||
|
RMV_VALID_NBR_MIN,
|
||||||
|
DIR_STRENGTH_MIN,
|
||||||
|
DIR_DISTANCE_MAX,
|
||||||
|
SMTH_VALID_NBR_MIN,
|
||||||
|
VORT_VALID_NBR_MIN,
|
||||||
|
HIGHCURV_VORTICITY_MIN,
|
||||||
|
HIGHCURV_CURVATURE_MIN,
|
||||||
|
UNUSED_INT, /* min_interpolate_nbrs */
|
||||||
|
UNUSED_INT, /* percentile_min_max */
|
||||||
|
UNUSED_INT, /* min_contrast_delta */
|
||||||
|
|
||||||
|
/* DFT Controls */
|
||||||
|
NUM_DFT_WAVES,
|
||||||
|
POWMAX_MIN,
|
||||||
|
POWNORM_MIN,
|
||||||
|
POWMAX_MAX,
|
||||||
|
FORK_INTERVAL,
|
||||||
|
FORK_PCT_POWMAX,
|
||||||
|
FORK_PCT_POWNORM,
|
||||||
|
|
||||||
|
/* Binarization Controls */
|
||||||
|
DIRBIN_GRID_W,
|
||||||
|
DIRBIN_GRID_H,
|
||||||
|
ISOBIN_GRID_DIM,
|
||||||
|
NUM_FILL_HOLES,
|
||||||
|
|
||||||
|
/* Minutiae Detection Controls */
|
||||||
|
MAX_MINUTIA_DELTA,
|
||||||
|
MAX_HIGH_CURVE_THETA,
|
||||||
|
HIGH_CURVE_HALF_CONTOUR,
|
||||||
|
MIN_LOOP_LEN,
|
||||||
|
MIN_LOOP_ASPECT_DIST,
|
||||||
|
MIN_LOOP_ASPECT_RATIO,
|
||||||
|
|
||||||
|
/* Minutiae Link Controls */
|
||||||
|
LINK_TABLE_DIM,
|
||||||
|
MAX_LINK_DIST,
|
||||||
|
MIN_THETA_DIST,
|
||||||
|
MAXTRANS,
|
||||||
|
SCORE_THETA_NORM,
|
||||||
|
SCORE_DIST_NORM,
|
||||||
|
SCORE_DIST_WEIGHT,
|
||||||
|
SCORE_NUMERATOR,
|
||||||
|
|
||||||
|
/* False Minutiae Removal Controls */
|
||||||
|
MAX_RMTEST_DIST,
|
||||||
|
MAX_HOOK_LEN,
|
||||||
|
MAX_HALF_LOOP,
|
||||||
|
TRANS_DIR_PIX,
|
||||||
|
SMALL_LOOP_LEN,
|
||||||
|
SIDE_HALF_CONTOUR,
|
||||||
|
INV_BLOCK_MARGIN,
|
||||||
|
RM_VALID_NBR_MIN,
|
||||||
|
UNUSED_INT, /* max_overlap_dist */
|
||||||
|
UNUSED_INT, /* max_overlap_join_dist */
|
||||||
|
UNUSED_INT, /* malformation_steps_1 */
|
||||||
|
UNUSED_INT, /* malformation_steps_2 */
|
||||||
|
UNUSED_DBL, /* min_malformation_ratio */
|
||||||
|
UNUSED_INT, /* max_malformation_dist */
|
||||||
|
PORES_TRANS_R,
|
||||||
|
PORES_PERP_STEPS,
|
||||||
|
PORES_STEPS_FWD,
|
||||||
|
PORES_STEPS_BWD,
|
||||||
|
PORES_MIN_DIST2,
|
||||||
|
PORES_MAX_RATIO,
|
||||||
|
|
||||||
|
/* Ridge Counting Controls */
|
||||||
|
MAX_NBRS,
|
||||||
|
MAX_RIDGE_STEPS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Allocate and initialize VERSION 2 global LFS parameters structure. */
|
||||||
|
LFSPARMS lfsparms_V2 = {
|
||||||
|
/* Image Controls */
|
||||||
|
PAD_VALUE,
|
||||||
|
JOIN_LINE_RADIUS,
|
||||||
|
|
||||||
|
/* Map Controls */
|
||||||
|
MAP_BLOCKSIZE_V2,
|
||||||
|
MAP_WINDOWSIZE_V2,
|
||||||
|
MAP_WINDOWOFFSET_V2,
|
||||||
|
NUM_DIRECTIONS,
|
||||||
|
START_DIR_ANGLE,
|
||||||
|
RMV_VALID_NBR_MIN,
|
||||||
|
DIR_STRENGTH_MIN,
|
||||||
|
DIR_DISTANCE_MAX,
|
||||||
|
SMTH_VALID_NBR_MIN,
|
||||||
|
VORT_VALID_NBR_MIN,
|
||||||
|
HIGHCURV_VORTICITY_MIN,
|
||||||
|
HIGHCURV_CURVATURE_MIN,
|
||||||
|
MIN_INTERPOLATE_NBRS,
|
||||||
|
PERCENTILE_MIN_MAX,
|
||||||
|
MIN_CONTRAST_DELTA,
|
||||||
|
|
||||||
|
/* DFT Controls */
|
||||||
|
NUM_DFT_WAVES,
|
||||||
|
POWMAX_MIN,
|
||||||
|
POWNORM_MIN,
|
||||||
|
POWMAX_MAX,
|
||||||
|
FORK_INTERVAL,
|
||||||
|
FORK_PCT_POWMAX,
|
||||||
|
FORK_PCT_POWNORM,
|
||||||
|
|
||||||
|
/* Binarization Controls */
|
||||||
|
DIRBIN_GRID_W,
|
||||||
|
DIRBIN_GRID_H,
|
||||||
|
UNUSED_INT, /* isobin_grid_dim */
|
||||||
|
NUM_FILL_HOLES,
|
||||||
|
|
||||||
|
/* Minutiae Detection Controls */
|
||||||
|
MAX_MINUTIA_DELTA,
|
||||||
|
MAX_HIGH_CURVE_THETA,
|
||||||
|
HIGH_CURVE_HALF_CONTOUR,
|
||||||
|
MIN_LOOP_LEN,
|
||||||
|
MIN_LOOP_ASPECT_DIST,
|
||||||
|
MIN_LOOP_ASPECT_RATIO,
|
||||||
|
|
||||||
|
/* Minutiae Link Controls */
|
||||||
|
UNUSED_INT, /* link_table_dim */
|
||||||
|
UNUSED_INT, /* max_link_dist */
|
||||||
|
UNUSED_INT, /* min_theta_dist */
|
||||||
|
MAXTRANS, /* used for removing overlaps as well */
|
||||||
|
UNUSED_DBL, /* score_theta_norm */
|
||||||
|
UNUSED_DBL, /* score_dist_norm */
|
||||||
|
UNUSED_DBL, /* score_dist_weight */
|
||||||
|
UNUSED_DBL, /* score_numerator */
|
||||||
|
|
||||||
|
/* False Minutiae Removal Controls */
|
||||||
|
MAX_RMTEST_DIST_V2,
|
||||||
|
MAX_HOOK_LEN_V2,
|
||||||
|
MAX_HALF_LOOP_V2,
|
||||||
|
TRANS_DIR_PIX_V2,
|
||||||
|
SMALL_LOOP_LEN,
|
||||||
|
SIDE_HALF_CONTOUR,
|
||||||
|
INV_BLOCK_MARGIN_V2,
|
||||||
|
RM_VALID_NBR_MIN,
|
||||||
|
MAX_OVERLAP_DIST,
|
||||||
|
MAX_OVERLAP_JOIN_DIST,
|
||||||
|
MALFORMATION_STEPS_1,
|
||||||
|
MALFORMATION_STEPS_2,
|
||||||
|
MIN_MALFORMATION_RATIO,
|
||||||
|
MAX_MALFORMATION_DIST,
|
||||||
|
PORES_TRANS_R,
|
||||||
|
PORES_PERP_STEPS,
|
||||||
|
PORES_STEPS_FWD,
|
||||||
|
PORES_STEPS_BWD,
|
||||||
|
PORES_MIN_DIST2,
|
||||||
|
PORES_MAX_RATIO,
|
||||||
|
|
||||||
|
/* Ridge Counting Controls */
|
||||||
|
MAX_NBRS,
|
||||||
|
MAX_RIDGE_STEPS
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Variables for conducting 8-connected neighbor analyses. */
|
||||||
|
/* Pixel neighbor offsets: 0 1 2 3 4 5 6 7 */ /* 7 0 1 */
|
||||||
|
int nbr8_dx[] = { 0, 1, 1, 1, 0,-1,-1,-1 }; /* 6 C 2 */
|
||||||
|
int nbr8_dy[] = { -1,-1, 0, 1, 1, 1, 0,-1 }; /* 5 4 3 */
|
||||||
|
|
||||||
|
/* The chain code lookup matrix for 8-connected neighbors. */
|
||||||
|
/* Should put this in globals. */
|
||||||
|
int chaincodes_nbr8[]={ 3, 2, 1,
|
||||||
|
4,-1, 0,
|
||||||
|
5, 6, 7};
|
||||||
|
|
||||||
|
/* Global array of feature pixel pairs. */
|
||||||
|
FEATURE_PATTERN feature_patterns[]=
|
||||||
|
{{RIDGE_ENDING, /* a. Ridge Ending (appearing) */
|
||||||
|
APPEARING,
|
||||||
|
{0,0},
|
||||||
|
{0,1},
|
||||||
|
{0,0}},
|
||||||
|
|
||||||
|
{RIDGE_ENDING, /* b. Ridge Ending (disappearing) */
|
||||||
|
DISAPPEARING,
|
||||||
|
{0,0},
|
||||||
|
{1,0},
|
||||||
|
{0,0}},
|
||||||
|
|
||||||
|
{BIFURCATION, /* c. Bifurcation (disappearing) */
|
||||||
|
DISAPPEARING,
|
||||||
|
{1,1},
|
||||||
|
{0,1},
|
||||||
|
{1,1}},
|
||||||
|
|
||||||
|
{BIFURCATION, /* d. Bifurcation (appearing) */
|
||||||
|
APPEARING,
|
||||||
|
{1,1},
|
||||||
|
{1,0},
|
||||||
|
{1,1}},
|
||||||
|
|
||||||
|
{BIFURCATION, /* e. Bifurcation (disappearing) */
|
||||||
|
DISAPPEARING,
|
||||||
|
{1,0},
|
||||||
|
{0,1},
|
||||||
|
{1,1}},
|
||||||
|
|
||||||
|
{BIFURCATION, /* f. Bifurcation (disappearing) */
|
||||||
|
DISAPPEARING,
|
||||||
|
{1,1},
|
||||||
|
{0,1},
|
||||||
|
{1,0}},
|
||||||
|
|
||||||
|
{BIFURCATION, /* g. Bifurcation (appearing) */
|
||||||
|
APPEARING,
|
||||||
|
{1,1},
|
||||||
|
{1,0},
|
||||||
|
{0,1}},
|
||||||
|
|
||||||
|
{BIFURCATION, /* h. Bifurcation (appearing) */
|
||||||
|
APPEARING,
|
||||||
|
{0,1},
|
||||||
|
{1,0},
|
||||||
|
{1,1}},
|
||||||
|
|
||||||
|
{BIFURCATION, /* i. Bifurcation (disappearing) */
|
||||||
|
DISAPPEARING,
|
||||||
|
{1,0},
|
||||||
|
{0,1},
|
||||||
|
{1,0}},
|
||||||
|
|
||||||
|
{BIFURCATION, /* j. Bifurcation (appearing) */
|
||||||
|
APPEARING,
|
||||||
|
{0,1},
|
||||||
|
{1,0},
|
||||||
|
{0,1}}};
|
469
libfprint/nbis/mindtct/imgutil.c
Normal file
469
libfprint/nbis/mindtct/imgutil.c
Normal file
|
@ -0,0 +1,469 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: IMGUTIL.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 03/16/1999
|
||||||
|
UPDATED: 03/16/2005 by MDG
|
||||||
|
|
||||||
|
Contains general support image routines required by the NIST
|
||||||
|
Latent Fingerprint System (LFS).
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
bits_6to8()
|
||||||
|
bits_8to6()
|
||||||
|
gray2bin()
|
||||||
|
pad_uchar_image()
|
||||||
|
fill_holes()
|
||||||
|
free_path()
|
||||||
|
search_in_direction()
|
||||||
|
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: bits_6to8 - Takes an array of unsigned characters and bitwise shifts
|
||||||
|
#cat: each value 2 postitions to the left. This is equivalent
|
||||||
|
#cat: to multiplying each value by 4. This puts original values
|
||||||
|
#cat: on the range [0..64) now on the range [0..256). Another
|
||||||
|
#cat: way to say this, is the original 6-bit values now fit in
|
||||||
|
#cat: 8 bits. This is to be used to undo the effects of bits_8to6.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
idata - input array of unsigned characters
|
||||||
|
iw - width (in characters) of the input array
|
||||||
|
ih - height (in characters) of the input array
|
||||||
|
Output:
|
||||||
|
idata - contains the bit-shifted results
|
||||||
|
**************************************************************************/
|
||||||
|
void bits_6to8(unsigned char *idata, const int iw, const int ih)
|
||||||
|
{
|
||||||
|
int i, isize;
|
||||||
|
unsigned char *iptr;
|
||||||
|
|
||||||
|
isize = iw * ih;
|
||||||
|
iptr = idata;
|
||||||
|
for(i = 0; i < isize; i++){
|
||||||
|
/* Multiply every pixel value by 4 so that [0..64) -> [0..255) */
|
||||||
|
*iptr++ <<= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: bits_8to6 - Takes an array of unsigned characters and bitwise shifts
|
||||||
|
#cat: each value 2 postitions to the right. This is equivalent
|
||||||
|
#cat: to dividing each value by 4. This puts original values
|
||||||
|
#cat: on the range [0..256) now on the range [0..64). Another
|
||||||
|
#cat: way to say this, is the original 8-bit values now fit in
|
||||||
|
#cat: 6 bits. I would really like to make this dependency
|
||||||
|
#cat: go away.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
idata - input array of unsigned characters
|
||||||
|
iw - width (in characters) of the input array
|
||||||
|
ih - height (in characters) of the input array
|
||||||
|
Output:
|
||||||
|
idata - contains the bit-shifted results
|
||||||
|
**************************************************************************/
|
||||||
|
void bits_8to6(unsigned char *idata, const int iw, const int ih)
|
||||||
|
{
|
||||||
|
int i, isize;
|
||||||
|
unsigned char *iptr;
|
||||||
|
|
||||||
|
isize = iw * ih;
|
||||||
|
iptr = idata;
|
||||||
|
for(i = 0; i < isize; i++){
|
||||||
|
/* Divide every pixel value by 4 so that [0..256) -> [0..64) */
|
||||||
|
*iptr++ >>= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: gray2bin - Takes an 8-bit threshold value and two 8-bit pixel values.
|
||||||
|
#cat: Those pixels in the image less than the threhsold are set
|
||||||
|
#cat: to the first specified pixel value, whereas those pixels
|
||||||
|
#cat: greater than or equal to the threshold are set to the second
|
||||||
|
#cat: specified pixel value. On application for this routine is
|
||||||
|
#cat: to convert binary images from 8-bit pixels valued {0,255} to
|
||||||
|
#cat: {1,0} and vice versa.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
thresh - 8-bit pixel threshold
|
||||||
|
less_pix - pixel value used when image pixel is < threshold
|
||||||
|
greater_pix - pixel value used when image pixel is >= threshold
|
||||||
|
bdata - 8-bit image data
|
||||||
|
iw - width (in pixels) of the image
|
||||||
|
ih - height (in pixels) of the image
|
||||||
|
Output:
|
||||||
|
bdata - altered 8-bit image data
|
||||||
|
**************************************************************************/
|
||||||
|
void gray2bin(const int thresh, const int less_pix, const int greater_pix,
|
||||||
|
unsigned char *bdata, const int iw, const int ih)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < iw*ih; i++){
|
||||||
|
if(bdata[i] >= thresh)
|
||||||
|
bdata[i] = (unsigned char)greater_pix;
|
||||||
|
else
|
||||||
|
bdata[i] = (unsigned char)less_pix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: pad_uchar_image - Copies an 8-bit grayscale images into a larger
|
||||||
|
#cat: output image centering the input image so as to
|
||||||
|
#cat: add a specified amount of pixel padding along the
|
||||||
|
#cat: entire perimeter of the input image. The amount of
|
||||||
|
#cat: pixel padding and the intensity of the pixel padding
|
||||||
|
#cat: are specified. An alternative to padding with a
|
||||||
|
#cat: constant intensity would be to copy the edge pixels
|
||||||
|
#cat: of the centered image into the adjacent pad area.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
idata - input 8-bit grayscale image
|
||||||
|
iw - width (in pixels) of the input image
|
||||||
|
ih - height (in pixels) of the input image
|
||||||
|
pad - size of padding (in pixels) to be added
|
||||||
|
pad_value - intensity of the padded area
|
||||||
|
Output:
|
||||||
|
optr - points to the newly padded image
|
||||||
|
ow - width (in pixels) of the padded image
|
||||||
|
oh - height (in pixels) of the padded image
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int pad_uchar_image(unsigned char **optr, int *ow, int *oh,
|
||||||
|
unsigned char *idata, const int iw, const int ih,
|
||||||
|
const int pad, const int pad_value)
|
||||||
|
{
|
||||||
|
unsigned char *pdata, *pptr, *iptr;
|
||||||
|
int i, pw, ph;
|
||||||
|
int pad2, psize;
|
||||||
|
|
||||||
|
/* Account for pad on both sides of image */
|
||||||
|
pad2 = pad<<1;
|
||||||
|
|
||||||
|
/* Compute new pad sizes */
|
||||||
|
pw = iw + pad2;
|
||||||
|
ph = ih + pad2;
|
||||||
|
psize = pw * ph;
|
||||||
|
|
||||||
|
/* Allocate padded image */
|
||||||
|
pdata = (unsigned char *)malloc(psize * sizeof(unsigned char));
|
||||||
|
if(pdata == (unsigned char *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : pad_uchar_image : malloc : pdata\n");
|
||||||
|
return(-160);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize values to a constant PAD value */
|
||||||
|
memset(pdata, pad_value, psize);
|
||||||
|
|
||||||
|
/* Copy input image into padded image one scanline at a time */
|
||||||
|
iptr = idata;
|
||||||
|
pptr = pdata + (pad * pw) + pad;
|
||||||
|
for(i = 0; i < ih; i++){
|
||||||
|
memcpy(pptr, iptr, iw);
|
||||||
|
iptr += iw;
|
||||||
|
pptr += pw;
|
||||||
|
}
|
||||||
|
|
||||||
|
*optr = pdata;
|
||||||
|
*ow = pw;
|
||||||
|
*oh = ph;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: fill_holes - Takes an input image and analyzes triplets of horizontal
|
||||||
|
#cat: pixels first and then triplets of vertical pixels, filling
|
||||||
|
#cat: in holes of width 1. A hole is defined as the case where
|
||||||
|
#cat: the neighboring 2 pixels are equal, AND the center pixel
|
||||||
|
#cat: is different. Each hole is filled with the value of its
|
||||||
|
#cat: immediate neighbors. This routine modifies the input image.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
bdata - binary image data to be processed
|
||||||
|
iw - width (in pixels) of the binary input image
|
||||||
|
ih - height (in pixels) of the binary input image
|
||||||
|
Output:
|
||||||
|
bdata - points to the results
|
||||||
|
**************************************************************************/
|
||||||
|
void fill_holes(unsigned char *bdata, const int iw, const int ih)
|
||||||
|
{
|
||||||
|
int ix, iy, iw2;
|
||||||
|
unsigned char *lptr, *mptr, *rptr, *tptr, *bptr, *sptr;
|
||||||
|
|
||||||
|
/* 1. Fill 1-pixel wide holes in horizontal runs first ... */
|
||||||
|
sptr = bdata + 1;
|
||||||
|
/* Foreach row in image ... */
|
||||||
|
for(iy = 0; iy < ih; iy++){
|
||||||
|
/* Initialize pointers to start of next line ... */
|
||||||
|
lptr = sptr-1; /* Left pixel */
|
||||||
|
mptr = sptr; /* Middle pixel */
|
||||||
|
rptr = sptr+1; /* Right pixel */
|
||||||
|
/* Foreach column in image (less far left and right pixels) ... */
|
||||||
|
for(ix = 1; ix < iw-1; ix++){
|
||||||
|
/* Do we have a horizontal hole of length 1? */
|
||||||
|
if((*lptr != *mptr) && (*lptr == *rptr)){
|
||||||
|
/* If so, then fill it. */
|
||||||
|
*mptr = *lptr;
|
||||||
|
/* Bump passed right pixel because we know it will not */
|
||||||
|
/* be a hole. */
|
||||||
|
lptr+=2;
|
||||||
|
mptr+=2;
|
||||||
|
rptr+=2;
|
||||||
|
/* We bump ix once here and then the FOR bumps it again. */
|
||||||
|
ix++;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
/* Otherwise, bump to the next pixel to the right. */
|
||||||
|
lptr++;
|
||||||
|
mptr++;
|
||||||
|
rptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Bump to start of next row. */
|
||||||
|
sptr += iw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. Now, fill 1-pixel wide holes in vertical runs ... */
|
||||||
|
iw2 = iw<<1;
|
||||||
|
/* Start processing column one row down from the top of the image. */
|
||||||
|
sptr = bdata + iw;
|
||||||
|
/* Foreach column in image ... */
|
||||||
|
for(ix = 0; ix < iw; ix++){
|
||||||
|
/* Initialize pointers to start of next column ... */
|
||||||
|
tptr = sptr-iw; /* Top pixel */
|
||||||
|
mptr = sptr; /* Middle pixel */
|
||||||
|
bptr = sptr+iw; /* Bottom pixel */
|
||||||
|
/* Foreach row in image (less top and bottom row) ... */
|
||||||
|
for(iy = 1; iy < ih-1; iy++){
|
||||||
|
/* Do we have a vertical hole of length 1? */
|
||||||
|
if((*tptr != *mptr) && (*tptr == *bptr)){
|
||||||
|
/* If so, then fill it. */
|
||||||
|
*mptr = *tptr;
|
||||||
|
/* Bump passed bottom pixel because we know it will not */
|
||||||
|
/* be a hole. */
|
||||||
|
tptr+=iw2;
|
||||||
|
mptr+=iw2;
|
||||||
|
bptr+=iw2;
|
||||||
|
/* We bump iy once here and then the FOR bumps it again. */
|
||||||
|
iy++;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
/* Otherwise, bump to the next pixel below. */
|
||||||
|
tptr+=iw;
|
||||||
|
mptr+=iw;
|
||||||
|
bptr+=iw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Bump to start of next column. */
|
||||||
|
sptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: free_path - Traverses a straight line between 2 pixel points in an
|
||||||
|
#cat: image and determines if a "free path" exists between the
|
||||||
|
#cat: 2 points by counting the number of pixel value transitions
|
||||||
|
#cat: between adjacent pixels along the trajectory.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
x1 - x-pixel coord of first point
|
||||||
|
y1 - y-pixel coord of first point
|
||||||
|
x2 - x-pixel coord of second point
|
||||||
|
y2 - y-pixel coord of second point
|
||||||
|
bdata - binary image data (0==while & 1==black)
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
ih - height (in pixels) of image
|
||||||
|
lfsparms - parameters and threshold for controlling LFS
|
||||||
|
Return Code:
|
||||||
|
TRUE - free path determined to exist
|
||||||
|
FALSE - free path determined not to exist
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int free_path(const int x1, const int y1, const int x2, const int y2,
|
||||||
|
unsigned char *bdata, const int iw, const int ih,
|
||||||
|
const LFSPARMS *lfsparms)
|
||||||
|
{
|
||||||
|
int *x_list, *y_list, num;
|
||||||
|
int ret;
|
||||||
|
int i, trans, preval, nextval;
|
||||||
|
|
||||||
|
/* Compute points along line segment between the two points. */
|
||||||
|
if((ret = line_points(&x_list, &y_list, &num, x1, y1, x2, y2)))
|
||||||
|
return(ret);
|
||||||
|
|
||||||
|
/* Intialize the number of transitions to 0. */
|
||||||
|
trans = 0;
|
||||||
|
/* Get the pixel value of first point along line segment. */
|
||||||
|
preval = *(bdata+(y1*iw)+x1);
|
||||||
|
|
||||||
|
/* Foreach remaining point along line segment ... */
|
||||||
|
for(i = 1; i < num; i++){
|
||||||
|
/* Get pixel value of next point along line segment. */
|
||||||
|
nextval = *(bdata+(y_list[i]*iw)+x_list[i]);
|
||||||
|
|
||||||
|
/* If next pixel value different from previous pixel value ... */
|
||||||
|
if(nextval != preval){
|
||||||
|
/* Then we have detected a transition, so bump counter. */
|
||||||
|
trans++;
|
||||||
|
/* If number of transitions seen > than threshold (ex. 2) ... */
|
||||||
|
if(trans > lfsparms->maxtrans){
|
||||||
|
/* Deallocate the line segment's coordinate lists. */
|
||||||
|
free(x_list);
|
||||||
|
free(y_list);
|
||||||
|
/* Return free path to be FALSE. */
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
/* Otherwise, maximum number of transitions not yet exceeded. */
|
||||||
|
/* Assign the next pixel value to the previous pixel value. */
|
||||||
|
preval = nextval;
|
||||||
|
}
|
||||||
|
/* Otherwise, no transition detected this interation. */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get here we did not exceed the maximum allowable number */
|
||||||
|
/* of transitions. So, deallocate the line segment's coordinate lists. */
|
||||||
|
free(x_list);
|
||||||
|
free(y_list);
|
||||||
|
|
||||||
|
/* Return free path to be TRUE. */
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: search_in_direction - Takes a specified maximum number of steps in a
|
||||||
|
#cat: specified direction looking for the first occurence of
|
||||||
|
#cat: a pixel with specified value. (Once found, adjustments
|
||||||
|
#cat: are potentially made to make sure the resulting pixel
|
||||||
|
#cat: and its associated edge pixel are 4-connected.)
|
||||||
|
|
||||||
|
Input:
|
||||||
|
pix - value of pixel to be searched for
|
||||||
|
strt_x - x-pixel coord to start search
|
||||||
|
strt_y - y-pixel coord to start search
|
||||||
|
delta_x - increment in x for each step
|
||||||
|
delta_y - increment in y for each step
|
||||||
|
maxsteps - maximum number of steps to conduct search
|
||||||
|
bdata - binary image data (0==while & 1==black)
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
ih - height (in pixels) of image
|
||||||
|
Output:
|
||||||
|
ox - x coord of located pixel
|
||||||
|
oy - y coord of located pixel
|
||||||
|
oex - x coord of associated edge pixel
|
||||||
|
oey - y coord of associated edge pixel
|
||||||
|
Return Code:
|
||||||
|
TRUE - pixel of specified value found
|
||||||
|
FALSE - pixel of specified value NOT found
|
||||||
|
**************************************************************************/
|
||||||
|
int search_in_direction(int *ox, int *oy, int *oex, int *oey, const int pix,
|
||||||
|
const int strt_x, const int strt_y,
|
||||||
|
const double delta_x, const double delta_y, const int maxsteps,
|
||||||
|
unsigned char *bdata, const int iw, const int ih)
|
||||||
|
{
|
||||||
|
|
||||||
|
int i, x, y, px, py;
|
||||||
|
double fx, fy;
|
||||||
|
|
||||||
|
/* Set previous point to starting point. */
|
||||||
|
px = strt_x;
|
||||||
|
py = strt_y;
|
||||||
|
/* Set floating point accumulators to starting point. */
|
||||||
|
fx = (double)strt_x;
|
||||||
|
fy = (double)strt_y;
|
||||||
|
|
||||||
|
/* Foreach step up to the specified maximum ... */
|
||||||
|
for(i = 0; i < maxsteps; i++){
|
||||||
|
|
||||||
|
/* Increment accumulators. */
|
||||||
|
fx += delta_x;
|
||||||
|
fy += delta_y;
|
||||||
|
/* Round to get next step. */
|
||||||
|
x = sround(fx);
|
||||||
|
y = sround(fy);
|
||||||
|
|
||||||
|
/* If we stepped outside the image boundaries ... */
|
||||||
|
if((x < 0) || (x >= iw) ||
|
||||||
|
(y < 0) || (y >= ih)){
|
||||||
|
/* Return FALSE (we did not find what we were looking for). */
|
||||||
|
*ox = -1;
|
||||||
|
*oy = -1;
|
||||||
|
*oex = -1;
|
||||||
|
*oey = -1;
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, test to see if we found our pixel with value 'pix'. */
|
||||||
|
if(*(bdata+(y*iw)+x) == pix){
|
||||||
|
/* The previous and current pixels form a feature, edge pixel */
|
||||||
|
/* pair, which we would like to use for edge following. The */
|
||||||
|
/* previous pixel may be a diagonal neighbor however to the */
|
||||||
|
/* current pixel, in which case the pair could not be used by */
|
||||||
|
/* the contour tracing (which requires the edge pixel in the */
|
||||||
|
/* pair neighbor to the N,S,E or W. */
|
||||||
|
/* This routine adjusts the pair so that the results may be */
|
||||||
|
/* used by the contour tracing. */
|
||||||
|
fix_edge_pixel_pair(&x, &y, &px, &py, bdata, iw, ih);
|
||||||
|
|
||||||
|
/* Return TRUE (we found what we were looking for). */
|
||||||
|
*ox = x;
|
||||||
|
*oy = y;
|
||||||
|
*oex = px;
|
||||||
|
*oey = py;
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, still haven't found pixel with desired value, */
|
||||||
|
/* so set current point to previous and take another step. */
|
||||||
|
px = x;
|
||||||
|
py = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return FALSE (we did not find what we were looking for). */
|
||||||
|
*ox = -1;
|
||||||
|
*oy = -1;
|
||||||
|
*oex = -1;
|
||||||
|
*oey = -1;
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
768
libfprint/nbis/mindtct/init.c
Normal file
768
libfprint/nbis/mindtct/init.c
Normal file
|
@ -0,0 +1,768 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: INIT.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 03/16/1999
|
||||||
|
UPDATED: 10/04/1999 Version 2 by MDG
|
||||||
|
UPDATED: 03/16/2005 by MDG
|
||||||
|
|
||||||
|
Contains routines responsible for allocation and/or initialization
|
||||||
|
of memories required by the NIST Latent Fingerprint System.
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
init_dir2rad()
|
||||||
|
init_dftwaves()
|
||||||
|
get_max_padding()
|
||||||
|
get_max_padding_V2()
|
||||||
|
init_rotgrids()
|
||||||
|
alloc_dir_powers()
|
||||||
|
alloc_power_stats()
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: init_dir2rad - Allocates and initializes a lookup table containing
|
||||||
|
#cat: cosine and sine values needed to convert integer IMAP
|
||||||
|
#cat: directions to angles in radians.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
ndirs - the number of integer directions to be defined in a
|
||||||
|
semicircle
|
||||||
|
Output:
|
||||||
|
optr - points to the allocated/initialized DIR2RAD structure
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int init_dir2rad(DIR2RAD **optr, const int ndirs)
|
||||||
|
{
|
||||||
|
DIR2RAD *dir2rad;
|
||||||
|
int i;
|
||||||
|
double theta, pi_factor;
|
||||||
|
double cs, sn;
|
||||||
|
|
||||||
|
/* Allocate structure */
|
||||||
|
dir2rad = (DIR2RAD *)malloc(sizeof(DIR2RAD));
|
||||||
|
if(dir2rad == (DIR2RAD *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : init_dir2rad : malloc : dir2rad\n");
|
||||||
|
return(-10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign number of directions */
|
||||||
|
dir2rad->ndirs = ndirs;
|
||||||
|
|
||||||
|
/* Allocate cosine vector */
|
||||||
|
dir2rad->cos = (double *)malloc(ndirs * sizeof(double));
|
||||||
|
if(dir2rad->cos == (double *)NULL){
|
||||||
|
/* Free memory allocated to this point. */
|
||||||
|
free(dir2rad);
|
||||||
|
fprintf(stderr, "ERROR : init_dir2rad : malloc : dir2rad->cos\n");
|
||||||
|
return(-11);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate sine vector */
|
||||||
|
dir2rad->sin = (double *)malloc(ndirs * sizeof(double));
|
||||||
|
if(dir2rad->sin == (double *)NULL){
|
||||||
|
/* Free memory allocated to this point. */
|
||||||
|
free(dir2rad->cos);
|
||||||
|
free(dir2rad);
|
||||||
|
fprintf(stderr, "ERROR : init_dir2rad : malloc : dir2rad->sin\n");
|
||||||
|
return(-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pi_factor sets the period of the trig functions to NDIRS units in x. */
|
||||||
|
/* For example, if NDIRS==16, then pi_factor = 2(PI/16) = .3926... */
|
||||||
|
pi_factor = 2.0*M_PI/(double)ndirs;
|
||||||
|
|
||||||
|
/* Now compute cos and sin values for each direction. */
|
||||||
|
for (i = 0; i < ndirs; ++i) {
|
||||||
|
theta = (double)(i * pi_factor);
|
||||||
|
cs = cos(theta);
|
||||||
|
sn = sin(theta);
|
||||||
|
/* Need to truncate precision so that answers are consistent */
|
||||||
|
/* on different computer architectures. */
|
||||||
|
cs = trunc_dbl_precision(cs, TRUNC_SCALE);
|
||||||
|
sn = trunc_dbl_precision(sn, TRUNC_SCALE);
|
||||||
|
dir2rad->cos[i] = cs;
|
||||||
|
dir2rad->sin[i] = sn;
|
||||||
|
}
|
||||||
|
|
||||||
|
*optr = dir2rad;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: init_dftwaves - Allocates and initializes a set of wave forms needed
|
||||||
|
#cat: to conduct DFT analysis on blocks of the input image
|
||||||
|
|
||||||
|
Input:
|
||||||
|
dft_coefs - array of multipliers used to define the frequency for
|
||||||
|
each wave form to be computed
|
||||||
|
nwaves - number of wave forms to be computed
|
||||||
|
blocksize - the width and height of each block of image data to
|
||||||
|
be DFT analyzed
|
||||||
|
Output:
|
||||||
|
optr - points to the allocated/initialized DFTWAVES structure
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int init_dftwaves(DFTWAVES **optr, const double *dft_coefs,
|
||||||
|
const int nwaves, const int blocksize)
|
||||||
|
{
|
||||||
|
DFTWAVES *dftwaves;
|
||||||
|
int i, j;
|
||||||
|
double pi_factor, freq, x;
|
||||||
|
double *cptr, *sptr;
|
||||||
|
|
||||||
|
/* Allocate structure */
|
||||||
|
dftwaves = (DFTWAVES *)malloc(sizeof(DFTWAVES));
|
||||||
|
if(dftwaves == (DFTWAVES *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : init_dftwaves : malloc : dftwaves\n");
|
||||||
|
return(-20);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set number of DFT waves */
|
||||||
|
dftwaves->nwaves = nwaves;
|
||||||
|
/* Set wave length of the DFT waves (they all must be the same length) */
|
||||||
|
dftwaves->wavelen = blocksize;
|
||||||
|
|
||||||
|
/* Allocate list of wave pointers */
|
||||||
|
dftwaves->waves = (DFTWAVE **)malloc(nwaves * sizeof(DFTWAVE *));
|
||||||
|
if(dftwaves == (DFTWAVES *)NULL){
|
||||||
|
/* Free memory allocated to this point. */
|
||||||
|
free(dftwaves);
|
||||||
|
fprintf(stderr, "ERROR : init_dftwaves : malloc : dftwaves->waves\n");
|
||||||
|
return(-21);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pi_factor sets the period of the trig functions to BLOCKSIZE units */
|
||||||
|
/* in x. For example, if BLOCKSIZE==24, then */
|
||||||
|
/* pi_factor = 2(PI/24) = .26179... */
|
||||||
|
pi_factor = 2.0*M_PI/(double)blocksize;
|
||||||
|
|
||||||
|
/* Foreach of 4 DFT frequency coef ... */
|
||||||
|
for (i = 0; i < nwaves; ++i) {
|
||||||
|
/* Allocate wave structure */
|
||||||
|
dftwaves->waves[i] = (DFTWAVE *)malloc(sizeof(DFTWAVE));
|
||||||
|
if(dftwaves->waves[i] == (DFTWAVE *)NULL){
|
||||||
|
/* Free memory allocated to this point. */
|
||||||
|
{ int _j; for(_j = 0; _j < i; _j++){
|
||||||
|
free(dftwaves->waves[_j]->cos);
|
||||||
|
free(dftwaves->waves[_j]->sin);
|
||||||
|
free(dftwaves->waves[_j]);
|
||||||
|
}}
|
||||||
|
free(dftwaves->waves);
|
||||||
|
free(dftwaves);
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR : init_dftwaves : malloc : dftwaves->waves[i]\n");
|
||||||
|
return(-22);
|
||||||
|
}
|
||||||
|
/* Allocate cosine vector */
|
||||||
|
dftwaves->waves[i]->cos = (double *)malloc(blocksize * sizeof(double));
|
||||||
|
if(dftwaves->waves[i]->cos == (double *)NULL){
|
||||||
|
/* Free memory allocated to this point. */
|
||||||
|
{ int _j; for(_j = 0; _j < i; _j++){
|
||||||
|
free(dftwaves->waves[_j]->cos);
|
||||||
|
free(dftwaves->waves[_j]->sin);
|
||||||
|
free(dftwaves->waves[_j]);
|
||||||
|
}}
|
||||||
|
free(dftwaves->waves[i]);
|
||||||
|
free(dftwaves->waves);
|
||||||
|
free(dftwaves);
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR : init_dftwaves : malloc : dftwaves->waves[i]->cos\n");
|
||||||
|
return(-23);
|
||||||
|
}
|
||||||
|
/* Allocate sine vector */
|
||||||
|
dftwaves->waves[i]->sin = (double *)malloc(blocksize * sizeof(double));
|
||||||
|
if(dftwaves->waves[i]->sin == (double *)NULL){
|
||||||
|
/* Free memory allocated to this point. */
|
||||||
|
{ int _j; for(_j = 0; _j < i; _j++){
|
||||||
|
free(dftwaves->waves[_j]->cos);
|
||||||
|
free(dftwaves->waves[_j]->sin);
|
||||||
|
free(dftwaves->waves[_j]);
|
||||||
|
}}
|
||||||
|
free(dftwaves->waves[i]->cos);
|
||||||
|
free(dftwaves->waves[i]);
|
||||||
|
free(dftwaves->waves);
|
||||||
|
free(dftwaves);
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR : init_dftwaves : malloc : dftwaves->waves[i]->sin\n");
|
||||||
|
return(-24);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign pointer nicknames */
|
||||||
|
cptr = dftwaves->waves[i]->cos;
|
||||||
|
sptr = dftwaves->waves[i]->sin;
|
||||||
|
|
||||||
|
/* Compute actual frequency */
|
||||||
|
freq = pi_factor * dft_coefs[i];
|
||||||
|
|
||||||
|
/* Used as a 1D DFT on a 24 long vector of pixel sums */
|
||||||
|
for (j = 0; j < blocksize; ++j) {
|
||||||
|
/* Compute sample points from frequency */
|
||||||
|
x = freq * (double)j;
|
||||||
|
/* Store cos and sin components of sample point */
|
||||||
|
*cptr++ = cos(x);
|
||||||
|
*sptr++ = sin(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*optr = dftwaves;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: get_max_padding - Deterines the maximum amount of image pixel padding
|
||||||
|
#cat: required by all LFS processes. Padding is currently
|
||||||
|
#cat: required by the rotated grids used in DFT analyses,
|
||||||
|
#cat: rotated grids used in directional binarization,
|
||||||
|
#cat: and in the grid used for isotropic binarization.
|
||||||
|
#cat: The NIST generalized code enables the parameters
|
||||||
|
#cat: governing these processes to be redefined, so a check
|
||||||
|
#cat: at runtime is required to determine which process
|
||||||
|
#cat: requires the most padding. By using the maximum as
|
||||||
|
#cat: the padding factor, all processes will run safely
|
||||||
|
#cat: with a single padding of the input image avoiding the
|
||||||
|
#cat: need to repad for further processes.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
imap_blocksize - the size (in pixels) of each IMAP block in the image
|
||||||
|
dirbin_grid_w - the width (in pixels) of the rotated grids used in
|
||||||
|
directional binarization
|
||||||
|
dirbin_grid_h - the height (in pixels) of the rotated grids used in
|
||||||
|
directional binarization
|
||||||
|
isobin_grid_dim - the dimension (in pixels) of the square grid used in
|
||||||
|
isotropic binarization
|
||||||
|
Return Code:
|
||||||
|
Non-negative - the maximum padding required for all processes
|
||||||
|
**************************************************************************/
|
||||||
|
int get_max_padding(const int imap_blocksize,
|
||||||
|
const int dirbin_grid_w, const int dirbin_grid_h,
|
||||||
|
const int isobin_grid_dim)
|
||||||
|
{
|
||||||
|
int dft_pad, dirbin_pad, isobin_pad, max_pad;
|
||||||
|
double diag;
|
||||||
|
double pad;
|
||||||
|
|
||||||
|
/* Compute pad required for rotated blocks used in DFT analyses. */
|
||||||
|
diag = sqrt((double)(2.0 * imap_blocksize * imap_blocksize));
|
||||||
|
/* Compute pad as difference between the IMAP blocksize */
|
||||||
|
/* and the diagonal distance of the block. */
|
||||||
|
/* Assumption: all block origins reside in valid/allocated memory. */
|
||||||
|
/* DFT grids are computed with pixel offsets RELATIVE2ORIGIN. */
|
||||||
|
pad = (diag-imap_blocksize)/(double)2.0;
|
||||||
|
/* Need to truncate precision so that answers are consistent */
|
||||||
|
/* on different computer architectures when rounding doubles. */
|
||||||
|
pad = trunc_dbl_precision(pad, TRUNC_SCALE);
|
||||||
|
dft_pad = sround(pad);
|
||||||
|
|
||||||
|
/* Compute pad required for rotated blocks used in directional */
|
||||||
|
/* binarization. */
|
||||||
|
diag = sqrt((double)((dirbin_grid_w*dirbin_grid_w)+
|
||||||
|
(dirbin_grid_h*dirbin_grid_h)));
|
||||||
|
/* Assumption: all grid centers reside in valid/allocated memory. */
|
||||||
|
/* dirbin grids are computed with pixel offsets RELATIVE2CENTER. */
|
||||||
|
pad = (diag-1)/(double)2.0;
|
||||||
|
/* Need to truncate precision so that answers are consistent */
|
||||||
|
/* on different computer architectures when rounding doubles. */
|
||||||
|
pad = trunc_dbl_precision(pad, TRUNC_SCALE);
|
||||||
|
dirbin_pad = sround(pad);
|
||||||
|
|
||||||
|
/* Compute pad required for grids used in isotropic binarization. */
|
||||||
|
pad = (isobin_grid_dim - 1)/(double)2.0;
|
||||||
|
/* Need to truncate precision so that answers are consistent */
|
||||||
|
/* on different computer architectures when rounding doubles. */
|
||||||
|
pad = trunc_dbl_precision(pad, TRUNC_SCALE);
|
||||||
|
isobin_pad = sround((isobin_grid_dim - 1)/(double)2.0);
|
||||||
|
|
||||||
|
max_pad = max(dft_pad, dirbin_pad);
|
||||||
|
max_pad = max(max_pad, isobin_pad);
|
||||||
|
|
||||||
|
/* Return the maximum of the three required paddings. This padding will */
|
||||||
|
/* be sufficiently large for all three purposes, so that padding of the */
|
||||||
|
/* input image will only be required once. */
|
||||||
|
return(max_pad);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: get_max_padding_V2 - Deterines the maximum amount of image pixel padding
|
||||||
|
#cat: required by all LFS (Version 2) processes. Padding is currently
|
||||||
|
#cat: required by the rotated grids used in DFT analyses and in
|
||||||
|
#cat: directional binarization. The NIST generalized code enables
|
||||||
|
#cat: the parameters governing these processes to be redefined, so a
|
||||||
|
#cat: check at runtime is required to determine which process
|
||||||
|
#cat: requires the most padding. By using the maximum as the padding
|
||||||
|
#cat: factor, all processes will run safely with a single padding of
|
||||||
|
#cat: the input image avoiding the need to repad for further processes.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
map_windowsize - the size (in pixels) of each window centered about
|
||||||
|
each block in the image used in DFT analyses
|
||||||
|
map_windowoffset - the offset (in pixels) from the orgin of the
|
||||||
|
surrounding window to the origin of the block
|
||||||
|
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
|
||||||
|
Return Code:
|
||||||
|
Non-negative - the maximum padding required for all processes
|
||||||
|
**************************************************************************/
|
||||||
|
int get_max_padding_V2(const int map_windowsize, const int map_windowoffset,
|
||||||
|
const int dirbin_grid_w, const int dirbin_grid_h)
|
||||||
|
{
|
||||||
|
int dft_pad, dirbin_pad, max_pad;
|
||||||
|
double diag;
|
||||||
|
double pad;
|
||||||
|
|
||||||
|
|
||||||
|
/* 1. Compute pad required for rotated windows used in DFT analyses. */
|
||||||
|
|
||||||
|
/* Explanation of DFT padding:
|
||||||
|
|
||||||
|
B---------------------
|
||||||
|
| window |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| A.......______|__________
|
||||||
|
| : : |
|
||||||
|
|<-C-->: block: |
|
||||||
|
<--|--D-->: : | image
|
||||||
|
| ........ |
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
----------------------
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
||||||
|
Pixel A = Origin of entire fingerprint image
|
||||||
|
= Also origin of first block in image. Each pixel in
|
||||||
|
this block gets the same DFT results computed from
|
||||||
|
the surrounding window. Note that in general
|
||||||
|
blocks are adjacent and non-overlapping.
|
||||||
|
|
||||||
|
Pixel B = Origin of surrounding window in which DFT
|
||||||
|
analysis is conducted. Note that this window is not
|
||||||
|
completely contained in the image but extends to the
|
||||||
|
top and to the right.
|
||||||
|
|
||||||
|
Distance C = Number of pixels in which the window extends
|
||||||
|
beyond the image (map_windowoffset).
|
||||||
|
|
||||||
|
Distance D = Amount of padding required to hold the entire
|
||||||
|
rotated window in memory.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Compute pad as difference between the MAP windowsize */
|
||||||
|
/* and the diagonal distance of the window. */
|
||||||
|
/* (DFT grids are computed with pixel offsets RELATIVE2ORIGIN.) */
|
||||||
|
diag = sqrt((double)(2.0 * map_windowsize * map_windowsize));
|
||||||
|
pad = (diag-map_windowsize)/(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);
|
||||||
|
/* Must add the window offset to the rotational padding. */
|
||||||
|
dft_pad = sround(pad) + map_windowoffset;
|
||||||
|
|
||||||
|
/* 2. Compute pad required for rotated blocks used in directional */
|
||||||
|
/* binarization. Binarization blocks are applied to each pixel */
|
||||||
|
/* in the input image. */
|
||||||
|
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);
|
||||||
|
|
||||||
|
max_pad = max(dft_pad, dirbin_pad);
|
||||||
|
|
||||||
|
/* Return the maximum of the two required paddings. This padding will */
|
||||||
|
/* be sufficiently large for all purposes, so that padding of the */
|
||||||
|
/* input image will only be required once. */
|
||||||
|
return(max_pad);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: init_rotgrids - Allocates and initializes a set of offsets that address
|
||||||
|
#cat: individual rotated pixels within a grid.
|
||||||
|
#cat: These rotated grids are used to conduct DFT analyses
|
||||||
|
#cat: on blocks of input image data, and they are used
|
||||||
|
#cat: in isotropic binarization.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
iw - width (in pixels) of the input image
|
||||||
|
ih - height (in pixels) of the input image
|
||||||
|
pad - designates the number of pixels to be padded to the perimeter
|
||||||
|
of the input image. May be passed as UNDEFINED, in which
|
||||||
|
case the specific padding required by the rotated grids
|
||||||
|
will be computed and returned in ROTGRIDS.
|
||||||
|
start_dir_angle - angle from which rotations are to start
|
||||||
|
ndirs - number of rotations to compute (within a semicircle)
|
||||||
|
grid_w - width of the grid in pixels to be rotated
|
||||||
|
grid_h - height of the grid in pixels to be rotated
|
||||||
|
relative2 - designates whether pixel offsets whould be computed
|
||||||
|
relative to the ORIGIN or the CENTER of the grid
|
||||||
|
Output:
|
||||||
|
optr - points to the allcated/initialized ROTGRIDS structure
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int init_rotgrids(ROTGRIDS **optr, const int iw, const int ih, const int ipad,
|
||||||
|
const double start_dir_angle, const int ndirs,
|
||||||
|
const int grid_w, const int grid_h, const int relative2)
|
||||||
|
{
|
||||||
|
ROTGRIDS *rotgrids;
|
||||||
|
double pi_offset, pi_incr;
|
||||||
|
int dir, ix, iy, grid_size, pw, grid_pad, min_dim;
|
||||||
|
int *grid;
|
||||||
|
double diag, theta, cs, sn, cx, cy;
|
||||||
|
double fxm, fym, fx, fy;
|
||||||
|
int ixt, iyt;
|
||||||
|
double pad;
|
||||||
|
|
||||||
|
/* Allocate structure */
|
||||||
|
rotgrids = (ROTGRIDS *)malloc(sizeof(ROTGRIDS));
|
||||||
|
if(rotgrids == (ROTGRIDS *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : init_rotgrids : malloc : rotgrids\n");
|
||||||
|
return(-30);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set rotgrid attributes */
|
||||||
|
rotgrids->ngrids = ndirs;
|
||||||
|
rotgrids->grid_w = grid_w;
|
||||||
|
rotgrids->grid_h = grid_h;
|
||||||
|
rotgrids->start_angle = start_dir_angle;
|
||||||
|
rotgrids->relative2 = relative2;
|
||||||
|
|
||||||
|
/* Compute pad based on diagonal of the grid */
|
||||||
|
diag = sqrt((double)((grid_w*grid_w)+(grid_h*grid_h)));
|
||||||
|
switch(relative2){
|
||||||
|
case RELATIVE2CENTER:
|
||||||
|
/* Assumption: all grid centers reside in valid/allocated memory. */
|
||||||
|
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);
|
||||||
|
grid_pad = sround(pad);
|
||||||
|
break;
|
||||||
|
case RELATIVE2ORIGIN:
|
||||||
|
/* Assumption: all grid origins reside in valid/allocated memory. */
|
||||||
|
min_dim = min(grid_w, grid_h);
|
||||||
|
/* Compute pad as difference between the smallest grid dimension */
|
||||||
|
/* and the diagonal distance of the grid. */
|
||||||
|
pad = (diag-min_dim)/(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);
|
||||||
|
grid_pad = sround(pad);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR : init_rotgrids : Illegal relative flag : %d\n",
|
||||||
|
relative2);
|
||||||
|
free(rotgrids);
|
||||||
|
return(-31);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If input padding is UNDEFINED ... */
|
||||||
|
if(ipad == UNDEFINED)
|
||||||
|
/* Use the padding specifically required by the rotated grids herein. */
|
||||||
|
rotgrids->pad = grid_pad;
|
||||||
|
else{
|
||||||
|
/* Otherwise, input pad was specified, so check to make sure it is */
|
||||||
|
/* sufficiently large to handle the rotated grids herein. */
|
||||||
|
if(ipad < grid_pad){
|
||||||
|
/* If input pad is NOT large enough, then ERROR. */
|
||||||
|
fprintf(stderr, "ERROR : init_rotgrids : Pad passed is too small\n");
|
||||||
|
free(rotgrids);
|
||||||
|
return(-32);
|
||||||
|
}
|
||||||
|
/* Otherwise, use the specified input pad in computing grid offsets. */
|
||||||
|
rotgrids->pad = ipad;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Total number of points in grid */
|
||||||
|
grid_size = grid_w * grid_h;
|
||||||
|
|
||||||
|
/* Compute width of "padded" image */
|
||||||
|
pw = iw + (rotgrids->pad<<1);
|
||||||
|
|
||||||
|
/* Center coord of grid (0-oriented). */
|
||||||
|
cx = (grid_w-1)/(double)2.0;
|
||||||
|
cy = (grid_h-1)/(double)2.0;
|
||||||
|
|
||||||
|
/* Allocate list of rotgrid pointers */
|
||||||
|
rotgrids->grids = (int **)malloc(ndirs * sizeof(int *));
|
||||||
|
if(rotgrids->grids == (int **)NULL){
|
||||||
|
/* Free memory allocated to this point. */
|
||||||
|
free(rotgrids);
|
||||||
|
fprintf(stderr, "ERROR : init_rotgrids : malloc : rotgrids->grids\n");
|
||||||
|
return(-33);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pi_offset is the offset in radians from which angles are to begin. */
|
||||||
|
pi_offset = start_dir_angle;
|
||||||
|
pi_incr = M_PI/(double)ndirs; /* if ndirs == 16, incr = 11.25 degrees */
|
||||||
|
|
||||||
|
/* For each direction to rotate a grid ... */
|
||||||
|
for (dir = 0, theta = pi_offset;
|
||||||
|
dir < ndirs; dir++, theta += pi_incr) {
|
||||||
|
|
||||||
|
/* Allocate a rotgrid */
|
||||||
|
rotgrids->grids[dir] = (int *)malloc(grid_size * sizeof(int));
|
||||||
|
if(rotgrids->grids[dir] == (int *)NULL){
|
||||||
|
/* Free memory allocated to this point. */
|
||||||
|
{ int _j; for(_j = 0; _j < dir; _j++){
|
||||||
|
free(rotgrids->grids[_j]);
|
||||||
|
}}
|
||||||
|
free(rotgrids);
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR : init_rotgrids : malloc : rotgrids->grids[dir]\n");
|
||||||
|
return(-34);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set pointer to current grid */
|
||||||
|
grid = rotgrids->grids[dir];
|
||||||
|
|
||||||
|
/* Compute cos and sin of current angle */
|
||||||
|
cs = cos(theta);
|
||||||
|
sn = sin(theta);
|
||||||
|
|
||||||
|
/* This next section of nested FOR loops precomputes a */
|
||||||
|
/* rotated grid. The rotation is set up to rotate a GRID_W X */
|
||||||
|
/* GRID_H grid on its center point at C=(Cx,Cy). The current */
|
||||||
|
/* pixel being rotated is P=(Ix,Iy). Therefore, we have a */
|
||||||
|
/* rotation transformation of point P about pivot point C. */
|
||||||
|
/* The rotation transformation about a pivot point in matrix */
|
||||||
|
/* form is: */
|
||||||
|
/*
|
||||||
|
+- -+
|
||||||
|
| cos(T) sin(T) 0 |
|
||||||
|
[Ix Iy 1] | -sin(T) cos(T) 0 |
|
||||||
|
| (1-cos(T))*Cx + Cy*sin(T) (1-cos(T))*Cy - Cx*sin(T) 1 |
|
||||||
|
+- -+
|
||||||
|
*/
|
||||||
|
/* Multiplying the 2 matrices and combining terms yeilds the */
|
||||||
|
/* equations for rotated coordinates (Rx, Ry): */
|
||||||
|
/* Rx = Cx + (Ix - Cx)*cos(T) - (Iy - Cy)*sin(T) */
|
||||||
|
/* Ry = Cy + (Ix - Cx)*sin(T) + (Iy - Cy)*cos(T) */
|
||||||
|
/* */
|
||||||
|
/* Care has been taken to ensure that (for example) when */
|
||||||
|
/* BLOCKSIZE==24 the rotated indices stay within a centered */
|
||||||
|
/* 34X34 area. */
|
||||||
|
/* This is important for computing an accurate padding of */
|
||||||
|
/* the input image. The rotation occurs "in-place" so that */
|
||||||
|
/* outer pixels in the grid are mapped at times from */
|
||||||
|
/* adjoining blocks. As a result, to keep from accessing */
|
||||||
|
/* "unknown" memory or pixels wrapped from the other side of */
|
||||||
|
/* the image, the input image should first be padded by */
|
||||||
|
/* PAD=round((DIAG - BLOCKSIZE)/2.0) where DIAG is the */
|
||||||
|
/* diagonal distance of the grid. */
|
||||||
|
/* For example, when BLOCKSIZE==24, Dx=34, so PAD=5. */
|
||||||
|
|
||||||
|
/* Foreach each y coord in block ... */
|
||||||
|
for (iy = 0; iy < grid_h; ++iy) {
|
||||||
|
/* Compute rotation factors dependent on Iy (include constant) */
|
||||||
|
fxm = -1.0 * ((iy - cy) * sn);
|
||||||
|
fym = ((iy - cy) * cs);
|
||||||
|
|
||||||
|
/* If offsets are to be relative to the grids origin, then */
|
||||||
|
/* we need to subtract CX and CY. */
|
||||||
|
if(relative2 == RELATIVE2ORIGIN){
|
||||||
|
fxm += cx;
|
||||||
|
fym += cy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* foreach each x coord in block ... */
|
||||||
|
for (ix = 0; ix < grid_w; ++ix) {
|
||||||
|
|
||||||
|
/* Now combine factors dependent on Iy with those of Ix */
|
||||||
|
fx = fxm + ((ix - cx) * cs);
|
||||||
|
fy = fym + ((ix - cx) * sn);
|
||||||
|
/* Need to truncate precision so that answers are consistent */
|
||||||
|
/* on different computer architectures when rounding doubles. */
|
||||||
|
fx = trunc_dbl_precision(fx, TRUNC_SCALE);
|
||||||
|
fy = trunc_dbl_precision(fy, TRUNC_SCALE);
|
||||||
|
ixt = sround(fx);
|
||||||
|
iyt = sround(fy);
|
||||||
|
|
||||||
|
/* Store the current pixels relative */
|
||||||
|
/* rotated offset. Make sure to */
|
||||||
|
/* multiply the y-component of the */
|
||||||
|
/* offset by the "padded" image width! */
|
||||||
|
*grid++ = ixt + (iyt * pw);
|
||||||
|
}/* ix */
|
||||||
|
}/* iy */
|
||||||
|
}/* dir */
|
||||||
|
|
||||||
|
*optr = rotgrids;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: alloc_dir_powers - Allocates the memory associated with DFT power
|
||||||
|
#cat: vectors. The DFT analysis is conducted block by block in the
|
||||||
|
#cat: input image, and within each block, N wave forms are applied
|
||||||
|
#cat: at M different directions.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
nwaves - number of DFT wave forms
|
||||||
|
ndirs - number of orientations (directions) used in DFT analysis
|
||||||
|
Output:
|
||||||
|
opowers - pointer to the allcated power vectors
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int alloc_dir_powers(double ***opowers, const int nwaves, const int ndirs)
|
||||||
|
{
|
||||||
|
int w;
|
||||||
|
double **powers;
|
||||||
|
|
||||||
|
/* Allocate list of double pointers to hold power vectors */
|
||||||
|
powers = (double **)malloc(nwaves * sizeof(double*));
|
||||||
|
if(powers == (double **)NULL){
|
||||||
|
fprintf(stderr, "ERROR : alloc_dir_powers : malloc : powers\n");
|
||||||
|
return(-40);
|
||||||
|
}
|
||||||
|
/* Foreach DFT wave ... */
|
||||||
|
for(w = 0; w < nwaves; w++){
|
||||||
|
/* Allocate power vector for all directions */
|
||||||
|
powers[w] = (double *)malloc(ndirs * sizeof(double));
|
||||||
|
if(powers[w] == (double *)NULL){
|
||||||
|
/* Free memory allocated to this point. */
|
||||||
|
{ int _j; for(_j = 0; _j < w; _j++){
|
||||||
|
free(powers[_j]);
|
||||||
|
}}
|
||||||
|
free(powers);
|
||||||
|
fprintf(stderr, "ERROR : alloc_dir_powers : malloc : powers[w]\n");
|
||||||
|
return(-41);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*opowers = powers;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: alloc_power_stats - Allocates memory associated with set of statistics
|
||||||
|
#cat: derived from DFT power vectors computed in a block of the
|
||||||
|
#cat: input image. Statistics are not computed for the lowest DFT
|
||||||
|
#cat: wave form, so the length of the statistics arrays is 1 less
|
||||||
|
#cat: than the number of DFT wave forms used. The staistics
|
||||||
|
#cat: include the Maximum power for each wave form, the direction
|
||||||
|
#cat: at which the maximum power occured, and a normalized value
|
||||||
|
#cat: for the maximum power. In addition, the statistics are
|
||||||
|
#cat: ranked in descending order based on normalized squared
|
||||||
|
#cat: maximum power.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
nstats - the number of waves forms from which statistics are to be
|
||||||
|
derived (N Waves - 1)
|
||||||
|
Output:
|
||||||
|
owis - points to an array to hold the ranked wave form indicies
|
||||||
|
of the corresponding statistics
|
||||||
|
opowmaxs - points to an array to hold the maximum DFT power for each
|
||||||
|
wave form
|
||||||
|
opowmax_dirs - points to an array to hold the direction corresponding to
|
||||||
|
each maximum power value
|
||||||
|
opownorms - points to an array to hold the normalized maximum power
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int alloc_power_stats(int **owis, double **opowmaxs, int **opowmax_dirs,
|
||||||
|
double **opownorms, const int nstats)
|
||||||
|
{
|
||||||
|
int *wis, *powmax_dirs;
|
||||||
|
double *powmaxs, *pownorms;
|
||||||
|
|
||||||
|
/* Allocate DFT wave index vector */
|
||||||
|
wis = (int *)malloc(nstats * sizeof(int));
|
||||||
|
if(wis == (int *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : alloc_power_stats : malloc : wis\n");
|
||||||
|
return(-50);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate max power vector */
|
||||||
|
powmaxs = (double *)malloc(nstats * sizeof(double));
|
||||||
|
if(powmaxs == (double *)NULL){
|
||||||
|
/* Free memory allocated to this point. */
|
||||||
|
free(wis);
|
||||||
|
fprintf(stderr, "ERROR : alloc_power_stats : malloc : powmaxs\n");
|
||||||
|
return(-51);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate max power direction vector */
|
||||||
|
powmax_dirs = (int *)malloc(nstats * sizeof(int));
|
||||||
|
if(powmax_dirs == (int *)NULL){
|
||||||
|
/* Free memory allocated to this point. */
|
||||||
|
free(wis);
|
||||||
|
free(powmaxs);
|
||||||
|
fprintf(stderr, "ERROR : alloc_power_stats : malloc : powmax_dirs\n");
|
||||||
|
return(-52);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate normalized power vector */
|
||||||
|
pownorms = (double *)malloc(nstats * sizeof(double));
|
||||||
|
if(pownorms == (double *)NULL){
|
||||||
|
/* Free memory allocated to this point. */
|
||||||
|
free(wis);
|
||||||
|
free(powmaxs);
|
||||||
|
free(pownorms);
|
||||||
|
fprintf(stderr, "ERROR : alloc_power_stats : malloc : pownorms\n");
|
||||||
|
return(-53);
|
||||||
|
}
|
||||||
|
|
||||||
|
*owis = wis;
|
||||||
|
*opowmaxs = powmaxs;
|
||||||
|
*opowmax_dirs = powmax_dirs;
|
||||||
|
*opownorms = pownorms;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
94
libfprint/nbis/mindtct/isempty.c
Normal file
94
libfprint/nbis/mindtct/isempty.c
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: ISEMPTY.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 09/13/2004
|
||||||
|
|
||||||
|
Contains routines responsible for determining if a fingerprint
|
||||||
|
image is empty.
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
is_image_empty()
|
||||||
|
is_qmap_empty()
|
||||||
|
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
************************************************************************
|
||||||
|
#cat: is_image_empty - Routine determines if statistics passed indicate
|
||||||
|
#cat: an empty image.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
quality_map - quality map computed by NIST's Mindtct
|
||||||
|
map_w - width of map
|
||||||
|
map_h - height of map
|
||||||
|
Return Code:
|
||||||
|
True - image determined empty
|
||||||
|
False - image determined NOT empty
|
||||||
|
************************************************************************/
|
||||||
|
int is_image_empty(int *quality_map, const int map_w, const int map_h)
|
||||||
|
{
|
||||||
|
/* This routine is designed to be expanded as more statistical */
|
||||||
|
/* tests are developed. */
|
||||||
|
|
||||||
|
if(is_qmap_empty(quality_map, map_w, map_h))
|
||||||
|
return(TRUE);
|
||||||
|
else
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
************************************************************************
|
||||||
|
#cat: is_qmap_empty - Routine determines if quality map is all set to zero
|
||||||
|
|
||||||
|
Input:
|
||||||
|
quality_map - quality map computed by NIST's Mindtct
|
||||||
|
map_w - width of map
|
||||||
|
map_h - height of map
|
||||||
|
Return Code:
|
||||||
|
True - quality map is empty
|
||||||
|
False - quality map is NOT empty
|
||||||
|
************************************************************************/
|
||||||
|
int is_qmap_empty(int *quality_map, const int map_w, const int map_h)
|
||||||
|
{
|
||||||
|
int i, maplen;
|
||||||
|
int *qptr;
|
||||||
|
|
||||||
|
qptr = quality_map;
|
||||||
|
maplen = map_w * map_h;
|
||||||
|
for(i = 0; i < maplen; i++){
|
||||||
|
if(*qptr++ != 0){
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
203
libfprint/nbis/mindtct/line.c
Normal file
203
libfprint/nbis/mindtct/line.c
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: LINE.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 03/16/1999
|
||||||
|
|
||||||
|
Contains routines that compute contiguous linear trajectories
|
||||||
|
between two coordinate points required by the NIST Latent
|
||||||
|
Fingerprint System (LFS).
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
line_points()
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: line_points - Returns the contiguous coordinates of a line connecting
|
||||||
|
#cat: 2 specified points.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
x1 - x-coord of first point
|
||||||
|
y1 - y-coord of first point
|
||||||
|
x2 - x-coord of second point
|
||||||
|
y2 - y-coord of second point
|
||||||
|
Output:
|
||||||
|
ox_list - x-coords along line trajectory
|
||||||
|
oy_list - y-coords along line trajectory
|
||||||
|
onum - number of points along line trajectory
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int line_points(int **ox_list, int **oy_list, int *onum,
|
||||||
|
const int x1, const int y1, const int x2, const int y2)
|
||||||
|
{
|
||||||
|
int asize;
|
||||||
|
int dx, dy, adx, ady;
|
||||||
|
int x_incr, y_incr;
|
||||||
|
int i, inx, iny, intx, inty;
|
||||||
|
double x_factor, y_factor;
|
||||||
|
double rx, ry;
|
||||||
|
int ix, iy;
|
||||||
|
int *x_list, *y_list;
|
||||||
|
|
||||||
|
/* Compute maximum number of points needed to hold line segment. */
|
||||||
|
asize = max(abs(x2-x1)+2, abs(y2-y1)+2);
|
||||||
|
|
||||||
|
/* Allocate x and y-pixel coordinate lists to length 'asize'. */
|
||||||
|
x_list = (int *)malloc(asize*sizeof(int));
|
||||||
|
if(x_list == (int *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : line_points : malloc : x_list\n");
|
||||||
|
return(-410);
|
||||||
|
}
|
||||||
|
y_list = (int *)malloc(asize*sizeof(int));
|
||||||
|
if(y_list == (int *)NULL){
|
||||||
|
free(x_list);
|
||||||
|
fprintf(stderr, "ERROR : line_points : malloc : y_list\n");
|
||||||
|
return(-411);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute delta x and y. */
|
||||||
|
dx = x2 - x1;
|
||||||
|
dy = y2 - y1;
|
||||||
|
|
||||||
|
/* Set x and y increments. */
|
||||||
|
if(dx >= 0)
|
||||||
|
x_incr = 1;
|
||||||
|
else
|
||||||
|
x_incr = -1;
|
||||||
|
|
||||||
|
if(dy >= 0)
|
||||||
|
y_incr = 1;
|
||||||
|
else
|
||||||
|
y_incr = -1;
|
||||||
|
|
||||||
|
/* Compute |DX| and |DY|. */
|
||||||
|
adx = abs(dx);
|
||||||
|
ady = abs(dy);
|
||||||
|
|
||||||
|
/* Set x-orientation. */
|
||||||
|
if(adx > ady)
|
||||||
|
inx = 1;
|
||||||
|
else
|
||||||
|
inx = 0;
|
||||||
|
|
||||||
|
/* Set y-orientation. */
|
||||||
|
if(ady > adx)
|
||||||
|
iny = 1;
|
||||||
|
else
|
||||||
|
iny = 0;
|
||||||
|
|
||||||
|
/* CASE 1: |DX| > |DY| */
|
||||||
|
/* Increment in X by +-1 */
|
||||||
|
/* in Y by +-|DY|/|DX| */
|
||||||
|
/* inx = 1 */
|
||||||
|
/* iny = 0 */
|
||||||
|
/* intx = 1 (inx) */
|
||||||
|
/* inty = 0 (iny) */
|
||||||
|
/* CASE 2: |DX| < |DY| */
|
||||||
|
/* Increment in Y by +-1 */
|
||||||
|
/* in X by +-|DX|/|DY| */
|
||||||
|
/* inx = 0 */
|
||||||
|
/* iny = 1 */
|
||||||
|
/* intx = 0 (inx) */
|
||||||
|
/* inty = 1 (iny) */
|
||||||
|
/* CASE 3: |DX| == |DY| */
|
||||||
|
/* inx = 0 */
|
||||||
|
/* iny = 0 */
|
||||||
|
/* intx = 1 */
|
||||||
|
/* inty = 1 */
|
||||||
|
intx = 1 - iny;
|
||||||
|
inty = 1 - inx;
|
||||||
|
|
||||||
|
/* DX */
|
||||||
|
/* x_factor = (inx * +-1) + ( iny * ------------ ) */
|
||||||
|
/* max(1, |DY|) */
|
||||||
|
/* */
|
||||||
|
x_factor = (inx * x_incr) + (iny * ((double)dx/max(1, ady)));
|
||||||
|
|
||||||
|
/* DY */
|
||||||
|
/* y_factor = (iny * +-1) + ( inx * ------------ ) */
|
||||||
|
/* max(1, |DX|) */
|
||||||
|
/* */
|
||||||
|
y_factor = (iny * y_incr) + (inx * ((double)dy/max(1, adx)));
|
||||||
|
|
||||||
|
/* Initialize integer coordinates. */
|
||||||
|
ix = x1;
|
||||||
|
iy = y1;
|
||||||
|
/* Set floating point coordinates. */
|
||||||
|
rx = (double)x1;
|
||||||
|
ry = (double)y1;
|
||||||
|
|
||||||
|
/* Initialize to first point in line segment. */
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
/* Assign first point into coordinate list. */
|
||||||
|
x_list[i] = x1;
|
||||||
|
y_list[i++] = y1;
|
||||||
|
|
||||||
|
while((ix != x2) || (iy != y2)){
|
||||||
|
|
||||||
|
if(i >= asize){
|
||||||
|
fprintf(stderr, "ERROR : line_points : coord list overflow\n");
|
||||||
|
free(x_list);
|
||||||
|
free(y_list);
|
||||||
|
return(-412);
|
||||||
|
}
|
||||||
|
|
||||||
|
rx += x_factor;
|
||||||
|
ry += y_factor;
|
||||||
|
|
||||||
|
/* Need to truncate precision so that answers are consistent */
|
||||||
|
/* on different computer architectures when truncating doubles. */
|
||||||
|
rx = trunc_dbl_precision(rx, TRUNC_SCALE);
|
||||||
|
ry = trunc_dbl_precision(ry, TRUNC_SCALE);
|
||||||
|
|
||||||
|
/* Compute new x and y-pixel coords in floating point and */
|
||||||
|
/* then round to the nearest integer. */
|
||||||
|
ix = (intx * (ix + x_incr)) + (iny * (int)(rx + 0.5));
|
||||||
|
iy = (inty * (iy + y_incr)) + (inx * (int)(ry + 0.5));
|
||||||
|
|
||||||
|
/* Assign first point into coordinate list. */
|
||||||
|
x_list[i] = ix;
|
||||||
|
y_list[i++] = iy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set output pointers. */
|
||||||
|
*ox_list = x_list;
|
||||||
|
*oy_list = y_list;
|
||||||
|
*onum = i;
|
||||||
|
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
1238
libfprint/nbis/mindtct/link.c
Normal file
1238
libfprint/nbis/mindtct/link.c
Normal file
File diff suppressed because it is too large
Load diff
90
libfprint/nbis/mindtct/log.c
Normal file
90
libfprint/nbis/mindtct/log.c
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: LOG.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 08/02/1999
|
||||||
|
|
||||||
|
Contains routines responsible for dynamically updating a log file
|
||||||
|
during the execution of the NIST Latent Fingerprint System (LFS).
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
open_logfile()
|
||||||
|
print2log()
|
||||||
|
close_logfile()
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <log.h>
|
||||||
|
|
||||||
|
/* If logging is on, declare global file pointer and supporting */
|
||||||
|
/* global variable for logging intermediate results. */
|
||||||
|
FILE *logfp;
|
||||||
|
int avrdir;
|
||||||
|
float dir_strength;
|
||||||
|
int nvalid;
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/***************************************************************************/
|
||||||
|
int open_logfile()
|
||||||
|
{
|
||||||
|
#ifdef LOG_REPORT
|
||||||
|
if((logfp = fopen(LOG_FILE, "wb")) == NULL){
|
||||||
|
fprintf(stderr, "ERROR : open_logfile : fopen : %s\n", LOG_FILE);
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/***************************************************************************/
|
||||||
|
void print2log(char *fmt, ...)
|
||||||
|
{
|
||||||
|
#ifdef LOG_REPORT
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(logfp, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
/***************************************************************************/
|
||||||
|
int close_logfile()
|
||||||
|
{
|
||||||
|
#ifdef LOG_REPORT
|
||||||
|
if(fclose(logfp)){
|
||||||
|
fprintf(stderr, "ERROR : close_logfile : fclose : %s\n", LOG_FILE);
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
1228
libfprint/nbis/mindtct/loop.c
Normal file
1228
libfprint/nbis/mindtct/loop.c
Normal file
File diff suppressed because it is too large
Load diff
2552
libfprint/nbis/mindtct/maps.c
Normal file
2552
libfprint/nbis/mindtct/maps.c
Normal file
File diff suppressed because it is too large
Load diff
271
libfprint/nbis/mindtct/matchpat.c
Normal file
271
libfprint/nbis/mindtct/matchpat.c
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: MATCHPAT.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 05/11/1999
|
||||||
|
UPDATED: 03/16/2005 by MDG
|
||||||
|
|
||||||
|
Contains routines responsible for matching minutia feature
|
||||||
|
patterns as part of the NIST Latent Fingerprint System (LFS).
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
match_1st_pair()
|
||||||
|
match_2nd_pair()
|
||||||
|
match_3rd_pair()
|
||||||
|
skip_repeated_horizontal_pair()
|
||||||
|
skip_repeated_vertical_pair()
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: match_1st_pair - Determines which of the feature_patterns[] have their
|
||||||
|
#cat: first pixel pair match the specified pixel pair.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
p1 - first pixel value of pair
|
||||||
|
p2 - second pixel value of pair
|
||||||
|
Output:
|
||||||
|
possible - list of matching feature_patterns[] indices
|
||||||
|
nposs - number of matches
|
||||||
|
Return Code:
|
||||||
|
nposs - number of matches
|
||||||
|
*************************************************************************/
|
||||||
|
int match_1st_pair(unsigned char p1, unsigned char p2,
|
||||||
|
int *possible, int *nposs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Set possibilities to 0 */
|
||||||
|
*nposs = 0;
|
||||||
|
|
||||||
|
/* Foreach set of feature pairs ... */
|
||||||
|
for(i = 0; i < NFEATURES; i++){
|
||||||
|
/* If current scan pair matches first pair for feature ... */
|
||||||
|
if((p1==feature_patterns[i].first[0]) &&
|
||||||
|
(p2==feature_patterns[i].first[1])){
|
||||||
|
/* Store feature as a possible match. */
|
||||||
|
possible[*nposs] = i;
|
||||||
|
/* Bump number of stored possibilities. */
|
||||||
|
(*nposs)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return number of stored possibilities. */
|
||||||
|
return(*nposs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: match_2nd_pair - Determines which of the passed feature_patterns[] have
|
||||||
|
#cat: their second pixel pair match the specified pixel pair.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
p1 - first pixel value of pair
|
||||||
|
p2 - second pixel value of pair
|
||||||
|
possible - list of potentially-matching feature_patterns[] indices
|
||||||
|
nposs - number of potential matches
|
||||||
|
Output:
|
||||||
|
possible - list of matching feature_patterns[] indices
|
||||||
|
nposs - number of matches
|
||||||
|
Return Code:
|
||||||
|
nposs - number of matches
|
||||||
|
*************************************************************************/
|
||||||
|
int match_2nd_pair(unsigned char p1, unsigned char p2,
|
||||||
|
int *possible, int *nposs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int tnposs;
|
||||||
|
|
||||||
|
/* Store input possibilities. */
|
||||||
|
tnposs = *nposs;
|
||||||
|
/* Reset output possibilities to 0. */
|
||||||
|
*nposs = 0;
|
||||||
|
|
||||||
|
/* If current scan pair values are the same ... */
|
||||||
|
if(p1 == p2)
|
||||||
|
/* Simply return because pair can't be a second feature pair. */
|
||||||
|
return(*nposs);
|
||||||
|
|
||||||
|
/* Foreach possible match based on first pair ... */
|
||||||
|
for(i = 0; i < tnposs; i++){
|
||||||
|
/* If current scan pair matches second pair for feature ... */
|
||||||
|
if((p1==feature_patterns[possible[i]].second[0]) &&
|
||||||
|
(p2==feature_patterns[possible[i]].second[1])){
|
||||||
|
/* Store feature as a possible match. */
|
||||||
|
possible[*nposs] = possible[i];
|
||||||
|
/* Bump number of stored possibilities. */
|
||||||
|
(*nposs)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return number of stored possibilities. */
|
||||||
|
return(*nposs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: match_3rd_pair - Determines which of the passed feature_patterns[] have
|
||||||
|
#cat: their third pixel pair match the specified pixel pair.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
p1 - first pixel value of pair
|
||||||
|
p2 - second pixel value of pair
|
||||||
|
possible - list of potentially-matching feature_patterns[] indices
|
||||||
|
nposs - number of potential matches
|
||||||
|
Output:
|
||||||
|
possible - list of matching feature_patterns[] indices
|
||||||
|
nposs - number of matches
|
||||||
|
Return Code:
|
||||||
|
nposs - number of matches
|
||||||
|
*************************************************************************/
|
||||||
|
int match_3rd_pair(unsigned char p1, unsigned char p2,
|
||||||
|
int *possible, int *nposs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int tnposs;
|
||||||
|
|
||||||
|
/* Store input possibilities. */
|
||||||
|
tnposs = *nposs;
|
||||||
|
/* Reset output possibilities to 0. */
|
||||||
|
*nposs = 0;
|
||||||
|
|
||||||
|
/* Foreach possible match based on first and second pairs ... */
|
||||||
|
for(i = 0; i < tnposs; i++){
|
||||||
|
/* If current scan pair matches third pair for feature ... */
|
||||||
|
if((p1==feature_patterns[possible[i]].third[0]) &&
|
||||||
|
(p2==feature_patterns[possible[i]].third[1])){
|
||||||
|
/* Store feature as a possible match. */
|
||||||
|
possible[*nposs] = possible[i];
|
||||||
|
/* Bump number of stored possibilities. */
|
||||||
|
(*nposs)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return number of stored possibilities. */
|
||||||
|
return(*nposs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: skip_repeated_horizontal_pair - Takes the location of two pixel in
|
||||||
|
#cat: adjacent pixel rows within an image region and skips
|
||||||
|
#cat: rightward until the either the pixel pair no longer repeats
|
||||||
|
#cat: itself or the image region is exhausted.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
cx - current x-coord of starting pixel pair
|
||||||
|
ex - right edge of the image region
|
||||||
|
p1ptr - pointer to current top pixel in pair
|
||||||
|
p2ptr - pointer to current bottom pixel in pair
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
ih - height (in pixels) of image
|
||||||
|
Output:
|
||||||
|
cx - x-coord of where rightward skip terminated
|
||||||
|
p1ptr - points to top pixel where rightward skip terminated
|
||||||
|
p2ptr - points to bottom pixel where rightward skip terminated
|
||||||
|
*************************************************************************/
|
||||||
|
void skip_repeated_horizontal_pair(int *cx, const int ex,
|
||||||
|
unsigned char **p1ptr, unsigned char **p2ptr,
|
||||||
|
const int iw, const int ih)
|
||||||
|
{
|
||||||
|
int old1, old2;
|
||||||
|
|
||||||
|
/* Store starting pixel pair. */
|
||||||
|
old1 = **p1ptr;
|
||||||
|
old2 = **p2ptr;
|
||||||
|
|
||||||
|
/* Bump horizontally to next pixel pair. */
|
||||||
|
(*cx)++;
|
||||||
|
(*p1ptr)++;
|
||||||
|
(*p2ptr)++;
|
||||||
|
|
||||||
|
/* While not at right of scan region... */
|
||||||
|
while(*cx < ex){
|
||||||
|
/* If one or the other pixels in the new pair are different */
|
||||||
|
/* from the starting pixel pair... */
|
||||||
|
if((**p1ptr != old1) || (**p2ptr != old2))
|
||||||
|
/* Done skipping repreated pixel pairs. */
|
||||||
|
return;
|
||||||
|
/* Otherwise, bump horizontally to next pixel pair. */
|
||||||
|
(*cx)++;
|
||||||
|
(*p1ptr)++;
|
||||||
|
(*p2ptr)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: skip_repeated_vertical_pair - Takes the location of two pixel in
|
||||||
|
#cat: adjacent pixel columns within an image region and skips
|
||||||
|
#cat: downward until the either the pixel pair no longer repeats
|
||||||
|
#cat: itself or the image region is exhausted.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
cy - current y-coord of starting pixel pair
|
||||||
|
ey - bottom of the image region
|
||||||
|
p1ptr - pointer to current left pixel in pair
|
||||||
|
p2ptr - pointer to current right pixel in pair
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
ih - height (in pixels) of image
|
||||||
|
Output:
|
||||||
|
cy - y-coord of where downward skip terminated
|
||||||
|
p1ptr - points to left pixel where downward skip terminated
|
||||||
|
p2ptr - points to right pixel where donward skip terminated
|
||||||
|
*************************************************************************/
|
||||||
|
void skip_repeated_vertical_pair(int *cy, const int ey,
|
||||||
|
unsigned char **p1ptr, unsigned char **p2ptr,
|
||||||
|
const int iw, const int ih)
|
||||||
|
{
|
||||||
|
int old1, old2;
|
||||||
|
|
||||||
|
/* Store starting pixel pair. */
|
||||||
|
old1 = **p1ptr;
|
||||||
|
old2 = **p2ptr;
|
||||||
|
|
||||||
|
/* Bump vertically to next pixel pair. */
|
||||||
|
(*cy)++;
|
||||||
|
(*p1ptr)+=iw;
|
||||||
|
(*p2ptr)+=iw;
|
||||||
|
|
||||||
|
/* While not at bottom of scan region... */
|
||||||
|
while(*cy < ey){
|
||||||
|
/* If one or the other pixels in the new pair are different */
|
||||||
|
/* from the starting pixel pair... */
|
||||||
|
if((**p1ptr != old1) || (**p2ptr != old2))
|
||||||
|
/* Done skipping repreated pixel pairs. */
|
||||||
|
return;
|
||||||
|
/* Otherwise, bump vertically to next pixel pair. */
|
||||||
|
(*cy)++;
|
||||||
|
(*p1ptr)+=iw;
|
||||||
|
(*p2ptr)+=iw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
3557
libfprint/nbis/mindtct/minutia.c
Normal file
3557
libfprint/nbis/mindtct/minutia.c
Normal file
File diff suppressed because it is too large
Load diff
226
libfprint/nbis/mindtct/morph.c
Normal file
226
libfprint/nbis/mindtct/morph.c
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: MORPH.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 10/04/1999
|
||||||
|
UPDATED: 10/26/1999 by MDG
|
||||||
|
To avoid indisciminate erosion of pixels along
|
||||||
|
the edge of the binary image.
|
||||||
|
UPDATED: 03/16/2005 by MDG
|
||||||
|
|
||||||
|
Contains general support image morphology routines required by
|
||||||
|
the NIST Latent Fingerprint System (LFS).
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
erode_charimage_2()
|
||||||
|
dilate_charimage_2()
|
||||||
|
get_south8_2()
|
||||||
|
get_north8_2()
|
||||||
|
get_east8_2()
|
||||||
|
get_west8_2()
|
||||||
|
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <morph.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: erode_charimage_2 - Erodes an 8-bit image by setting true pixels to zero
|
||||||
|
#cat: if any of their 4 neighbors is zero. Allocation of the
|
||||||
|
#cat: output image is the responsibility of the caller. The
|
||||||
|
#cat: input image remains unchanged. This routine will NOT
|
||||||
|
#cat: erode pixels indiscriminately along the image border.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
inp - input 8-bit image to be eroded
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
ih - height (in pixels) of image
|
||||||
|
Output:
|
||||||
|
out - contains to the resulting eroded image
|
||||||
|
**************************************************************************/
|
||||||
|
void erode_charimage_2(unsigned char *inp, unsigned char *out,
|
||||||
|
const int iw, const int ih)
|
||||||
|
{
|
||||||
|
int row, col;
|
||||||
|
unsigned char *itr = inp, *otr = out;
|
||||||
|
|
||||||
|
memcpy(out, inp, iw*ih);
|
||||||
|
|
||||||
|
/* for true pixels. kill pixel if there is at least one false neighbor */
|
||||||
|
for ( row = 0 ; row < ih ; row++ )
|
||||||
|
for ( col = 0 ; col < iw ; col++ )
|
||||||
|
{
|
||||||
|
if (*itr) /* erode only operates on true pixels */
|
||||||
|
{
|
||||||
|
/* more efficient with C's left to right evaluation of */
|
||||||
|
/* conjuctions. E N S functions not executed if W is false */
|
||||||
|
if (!(get_west8_2 ((char *)itr, col , 1 ) &&
|
||||||
|
get_east8_2 ((char *)itr, col, iw , 1 ) &&
|
||||||
|
get_north8_2((char *)itr, row, iw , 1 ) &&
|
||||||
|
get_south8_2((char *)itr, row, iw, ih, 1)))
|
||||||
|
*otr = 0;
|
||||||
|
}
|
||||||
|
itr++ ; otr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: dilate_charimage_2 - Dilates an 8-bit image by setting false pixels to
|
||||||
|
#cat: one if any of their 4 neighbors is non-zero. Allocation
|
||||||
|
#cat: of the output image is the responsibility of the caller.
|
||||||
|
#cat: The input image remains unchanged.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
inp - input 8-bit image to be dilated
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
ih - height (in pixels) of image
|
||||||
|
Output:
|
||||||
|
out - contains to the resulting dilated image
|
||||||
|
**************************************************************************/
|
||||||
|
void dilate_charimage_2(unsigned char *inp, unsigned char *out,
|
||||||
|
const int iw, const int ih)
|
||||||
|
{
|
||||||
|
int row, col;
|
||||||
|
unsigned char *itr = inp, *otr = out;
|
||||||
|
|
||||||
|
memcpy(out, inp, iw*ih);
|
||||||
|
|
||||||
|
/* for all pixels. set pixel if there is at least one true neighbor */
|
||||||
|
for ( row = 0 ; row < ih ; row++ )
|
||||||
|
for ( col = 0 ; col < iw ; col++ )
|
||||||
|
{
|
||||||
|
if (!*itr) /* pixel is already true, neighbors irrelevant */
|
||||||
|
{
|
||||||
|
/* more efficient with C's left to right evaluation of */
|
||||||
|
/* conjuctions. E N S functions not executed if W is false */
|
||||||
|
if (get_west8_2 ((char *)itr, col , 0) ||
|
||||||
|
get_east8_2 ((char *)itr, col, iw , 0) ||
|
||||||
|
get_north8_2((char *)itr, row, iw , 0) ||
|
||||||
|
get_south8_2((char *)itr, row, iw, ih, 0))
|
||||||
|
*otr = 1;
|
||||||
|
}
|
||||||
|
itr++ ; otr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: get_south8_2 - Returns the value of the 8-bit image pixel 1 below the
|
||||||
|
#cat: current pixel if defined else it returns (char)0.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
ptr - points to current pixel in image
|
||||||
|
row - y-coord of current pixel
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
ih - height (in pixels) of image
|
||||||
|
failcode - return value if desired pixel does not exist
|
||||||
|
Return Code:
|
||||||
|
Zero - if neighboring pixel is undefined
|
||||||
|
(outside of image boundaries)
|
||||||
|
Pixel - otherwise, value of neighboring pixel
|
||||||
|
**************************************************************************/
|
||||||
|
char get_south8_2(char *ptr, const int row, const int iw, const int ih,
|
||||||
|
const int failcode)
|
||||||
|
{
|
||||||
|
if (row >= ih-1) /* catch case where image is undefined southwards */
|
||||||
|
return failcode; /* use plane geometry and return code. */
|
||||||
|
|
||||||
|
return *(ptr+iw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: get_north8_2 - Returns the value of the 8-bit image pixel 1 above the
|
||||||
|
#cat: current pixel if defined else it returns (char)0.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
ptr - points to current pixel in image
|
||||||
|
row - y-coord of current pixel
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
failcode - return value if desired pixel does not exist
|
||||||
|
Return Code:
|
||||||
|
Zero - if neighboring pixel is undefined
|
||||||
|
(outside of image boundaries)
|
||||||
|
Pixel - otherwise, value of neighboring pixel
|
||||||
|
**************************************************************************/
|
||||||
|
char get_north8_2(char *ptr, const int row, const int iw,
|
||||||
|
const int failcode)
|
||||||
|
{
|
||||||
|
if (row < 1) /* catch case where image is undefined northwards */
|
||||||
|
return failcode; /* use plane geometry and return code. */
|
||||||
|
|
||||||
|
return *(ptr-iw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: get_east8_2 - Returns the value of the 8-bit image pixel 1 right of the
|
||||||
|
#cat: current pixel if defined else it returns (char)0.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
ptr - points to current pixel in image
|
||||||
|
col - x-coord of current pixel
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
failcode - return value if desired pixel does not exist
|
||||||
|
Return Code:
|
||||||
|
Zero - if neighboring pixel is undefined
|
||||||
|
(outside of image boundaries)
|
||||||
|
Pixel - otherwise, value of neighboring pixel
|
||||||
|
**************************************************************************/
|
||||||
|
char get_east8_2(char *ptr, const int col, const int iw,
|
||||||
|
const int failcode)
|
||||||
|
{
|
||||||
|
if (col >= iw-1) /* catch case where image is undefined eastwards */
|
||||||
|
return failcode; /* use plane geometry and return code. */
|
||||||
|
|
||||||
|
return *(ptr+ 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: get_west8_2 - Returns the value of the 8-bit image pixel 1 left of the
|
||||||
|
#cat: current pixel if defined else it returns (char)0.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
ptr - points to current pixel in image
|
||||||
|
col - x-coord of current pixel
|
||||||
|
failcode - return value if desired pixel does not exist
|
||||||
|
Return Code:
|
||||||
|
Zero - if neighboring pixel is undefined
|
||||||
|
(outside of image boundaries)
|
||||||
|
Pixel - otherwise, value of neighboring pixel
|
||||||
|
**************************************************************************/
|
||||||
|
char get_west8_2(char *ptr, const int col, const int failcode)
|
||||||
|
{
|
||||||
|
if (col < 1) /* catch case where image is undefined westwards */
|
||||||
|
return failcode; /* use plane geometry and return code. */
|
||||||
|
|
||||||
|
return *(ptr- 1);
|
||||||
|
}
|
60
libfprint/nbis/mindtct/mytime.c
Normal file
60
libfprint/nbis/mindtct/mytime.c
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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 */
|
467
libfprint/nbis/mindtct/quality.c
Normal file
467
libfprint/nbis/mindtct/quality.c
Normal file
|
@ -0,0 +1,467 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: QUALITY.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 09/25/2000
|
||||||
|
UPDATED: 03/16/2005 by MDG
|
||||||
|
|
||||||
|
Contains routines responsible for assessing minutia quality
|
||||||
|
and assigning different reliability measures. These routines
|
||||||
|
are primarily to support the rejection of bad minutiae.
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
gen_quality_map()
|
||||||
|
combined_minutia_quality()
|
||||||
|
grayscale_reliability()
|
||||||
|
get_neighborhood_stats()
|
||||||
|
reliability_fr_quality_map()
|
||||||
|
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
************************************************************************
|
||||||
|
#cat: gen_quality_map - Takes a direction map, low contrast map, low ridge
|
||||||
|
#cat: flow map, and high curvature map, and combines them
|
||||||
|
#cat: into a single map containing 5 levels of decreasing
|
||||||
|
#cat: quality. This is done through a set of heuristics.
|
||||||
|
|
||||||
|
Code originally written by Austin Hicklin for FBI ATU
|
||||||
|
Modified by Michael D. Garris (NIST) Sept. 1, 2000
|
||||||
|
|
||||||
|
Set quality of 0(unusable)..4(good) (I call these grades A..F)
|
||||||
|
0/F: low contrast OR no direction
|
||||||
|
1/D: low flow OR high curve
|
||||||
|
(with low contrast OR no direction neighbor)
|
||||||
|
(or within NEIGHBOR_DELTA of edge)
|
||||||
|
2/C: low flow OR high curve
|
||||||
|
(or good quality with low contrast/no direction neighbor)
|
||||||
|
3/B: good quality with low flow / high curve neighbor
|
||||||
|
4/A: good quality (none of the above)
|
||||||
|
|
||||||
|
Generally, the features in A/B quality are useful, the C/D quality
|
||||||
|
ones are not.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
direction_map - map with blocks assigned dominant ridge flow direction
|
||||||
|
low_contrast_map - map with blocks flagged as low contrast
|
||||||
|
low_flow_map - map with blocks flagged as low ridge flow
|
||||||
|
high_curve_map - map with blocks flagged as high curvature
|
||||||
|
map_w - width (in blocks) of the maps
|
||||||
|
map_h - height (in blocks) of the maps
|
||||||
|
Output:
|
||||||
|
oqmap - points to new quality map
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
************************************************************************/
|
||||||
|
int gen_quality_map(int **oqmap, int *direction_map, int *low_contrast_map,
|
||||||
|
int *low_flow_map, int *high_curve_map,
|
||||||
|
const int map_w, const int map_h)
|
||||||
|
{
|
||||||
|
|
||||||
|
int *QualMap;
|
||||||
|
int thisX, thisY;
|
||||||
|
int compX, compY;
|
||||||
|
int arrayPos, arrayPos2;
|
||||||
|
int QualOffset;
|
||||||
|
|
||||||
|
QualMap = (int *)malloc(map_w * map_h * sizeof(int));
|
||||||
|
if(QualMap == (int *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : gen_quality_map : malloc : QualMap\n");
|
||||||
|
return(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Foreach row of blocks in maps ... */
|
||||||
|
for(thisY=0; thisY<map_h; thisY++){
|
||||||
|
/* Foreach block in current row ... */
|
||||||
|
for(thisX=0; thisX<map_w; thisX++) {
|
||||||
|
/* Compute block index. */
|
||||||
|
arrayPos=(thisY*map_w)+thisX;
|
||||||
|
/* If current block has low contrast or INVALID direction ... */
|
||||||
|
if(low_contrast_map[arrayPos] || direction_map[arrayPos]<0)
|
||||||
|
/* Set block's quality to 0/F. */
|
||||||
|
QualMap[arrayPos]=0;
|
||||||
|
else{
|
||||||
|
/* Set baseline quality before looking at neighbors */
|
||||||
|
/* (will subtract QualOffset below) */
|
||||||
|
/* If current block has low flow or high curvature ... */
|
||||||
|
if(low_flow_map[arrayPos] || high_curve_map[arrayPos])
|
||||||
|
/* Set block's quality initially to 3/B. */
|
||||||
|
QualMap[arrayPos] = 3; /* offset will be -1..-2 */
|
||||||
|
/* Otherwise, block is NOT low flow AND NOT high curvature... */
|
||||||
|
else
|
||||||
|
/* Set block's quality to 4/A. */
|
||||||
|
QualMap[arrayPos]=4; /* offset will be 0..-2 */
|
||||||
|
|
||||||
|
/* If block within NEIGHBOR_DELTA of edge ... */
|
||||||
|
if(thisY < NEIGHBOR_DELTA || thisY > map_h - 1 - NEIGHBOR_DELTA ||
|
||||||
|
thisX < NEIGHBOR_DELTA || thisX > map_w - 1 - NEIGHBOR_DELTA)
|
||||||
|
/* Set block's quality to 1/E. */
|
||||||
|
QualMap[arrayPos]=1;
|
||||||
|
/* Otherwise, test neighboring blocks ... */
|
||||||
|
else{
|
||||||
|
/* Initialize quality adjustment to 0. */
|
||||||
|
QualOffset=0;
|
||||||
|
/* Foreach row in neighborhood ... */
|
||||||
|
for(compY=thisY-NEIGHBOR_DELTA;
|
||||||
|
compY<=thisY+NEIGHBOR_DELTA;compY++){
|
||||||
|
/* Foreach block in neighborhood */
|
||||||
|
/* (including current block)... */
|
||||||
|
for(compX=thisX-NEIGHBOR_DELTA;
|
||||||
|
compX<=thisX+NEIGHBOR_DELTA;compX++) {
|
||||||
|
/* Compute neighboring block's index. */
|
||||||
|
arrayPos2 = (compY*map_w)+compX;
|
||||||
|
/* If neighbor block (which might be itself) has */
|
||||||
|
/* low contrast or INVALID direction .. */
|
||||||
|
if(low_contrast_map[arrayPos2] ||
|
||||||
|
direction_map[arrayPos2]<0) {
|
||||||
|
/* Set quality adjustment to -2. */
|
||||||
|
QualOffset=-2;
|
||||||
|
/* Done with neighborhood row. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Otherwise, if neighbor block (which might be */
|
||||||
|
/* itself) has low flow or high curvature ... */
|
||||||
|
else if(low_flow_map[arrayPos2] ||
|
||||||
|
high_curve_map[arrayPos2]) {
|
||||||
|
/* Set quality to -1 if not already -2. */
|
||||||
|
QualOffset=min(QualOffset,-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Decrement minutia quality by neighborhood adjustment. */
|
||||||
|
QualMap[arrayPos]+=QualOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set output pointer. */
|
||||||
|
*oqmap = QualMap;
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
************************************************************************
|
||||||
|
#cat: combined_minutia_quality - Combines quality measures derived from
|
||||||
|
#cat: the quality map and neighboring pixel statistics to
|
||||||
|
#cat: infer a reliability measure on the scale [0...1].
|
||||||
|
|
||||||
|
Input:
|
||||||
|
minutiae - structure contining the detected minutia
|
||||||
|
quality_map - map with blocks assigned 1 of 5 quality levels
|
||||||
|
map_w - width (in blocks) of the map
|
||||||
|
map_h - height (in blocks) of the map
|
||||||
|
blocksize - size (in pixels) of each block in the map
|
||||||
|
idata - 8-bit grayscale fingerprint image
|
||||||
|
iw - width (in pixels) of the image
|
||||||
|
ih - height (in pixels) of the image
|
||||||
|
id - depth (in pixels) of the image
|
||||||
|
ppmm - scan resolution of the image in pixels/mm
|
||||||
|
Output:
|
||||||
|
minutiae - updated reliability members
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
************************************************************************/
|
||||||
|
int combined_minutia_quality(MINUTIAE *minutiae,
|
||||||
|
int *quality_map, const int mw, const int mh, const int blocksize,
|
||||||
|
unsigned char *idata, const int iw, const int ih, const int id,
|
||||||
|
const double ppmm)
|
||||||
|
{
|
||||||
|
int ret, i, index, radius_pix;
|
||||||
|
int *pquality_map, qmap_value;
|
||||||
|
MINUTIA *minutia;
|
||||||
|
double gs_reliability, reliability;
|
||||||
|
|
||||||
|
/* If image is not 8-bit grayscale ... */
|
||||||
|
if(id != 8){
|
||||||
|
fprintf(stderr, "ERROR : combined_miutia_quality : ");
|
||||||
|
fprintf(stderr, "image must pixel depth = %d must be 8 ", id);
|
||||||
|
fprintf(stderr, "to compute reliability\n");
|
||||||
|
return(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute pixel radius of neighborhood based on image's scan resolution. */
|
||||||
|
radius_pix = sround(RADIUS_MM * ppmm);
|
||||||
|
|
||||||
|
/* Expand block map values to pixel map. */
|
||||||
|
if((ret = pixelize_map(&pquality_map, iw, ih,
|
||||||
|
quality_map, mw, mh, blocksize))){
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Foreach minutiae detected ... */
|
||||||
|
for(i = 0; i < minutiae->num; i++){
|
||||||
|
/* Assign minutia pointer. */
|
||||||
|
minutia = minutiae->list[i];
|
||||||
|
|
||||||
|
/* Compute reliability from stdev and mean of pixel neighborhood. */
|
||||||
|
gs_reliability = grayscale_reliability(minutia,
|
||||||
|
idata, iw, ih, radius_pix);
|
||||||
|
|
||||||
|
/* Lookup quality map value. */
|
||||||
|
/* Compute minutia pixel index. */
|
||||||
|
index = (minutia->y * iw) + minutia->x;
|
||||||
|
/* Switch on pixel's quality value ... */
|
||||||
|
qmap_value = pquality_map[index];
|
||||||
|
|
||||||
|
/* Combine grayscale reliability and quality map value. */
|
||||||
|
switch(qmap_value){
|
||||||
|
/* Quality A : [50..99]% */
|
||||||
|
case 4 :
|
||||||
|
reliability = 0.50 + (0.49 * gs_reliability);
|
||||||
|
break;
|
||||||
|
/* Quality B : [25..49]% */
|
||||||
|
case 3 :
|
||||||
|
reliability = 0.25 + (0.24 * gs_reliability);
|
||||||
|
break;
|
||||||
|
/* Quality C : [10..24]% */
|
||||||
|
case 2 :
|
||||||
|
reliability = 0.10 + (0.14 * gs_reliability);
|
||||||
|
break;
|
||||||
|
/* Quality D : [5..9]% */
|
||||||
|
case 1 :
|
||||||
|
reliability = 0.05 + (0.04 * gs_reliability);
|
||||||
|
break;
|
||||||
|
/* Quality E : 1% */
|
||||||
|
case 0 :
|
||||||
|
reliability = 0.01;
|
||||||
|
break;
|
||||||
|
/* Error if quality value not in range [0..4]. */
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "ERROR : combined_miutia_quality : ");
|
||||||
|
fprintf(stderr, "unexpected quality map value %d ", qmap_value);
|
||||||
|
fprintf(stderr, "not in range [0..4]\n");
|
||||||
|
free(pquality_map);
|
||||||
|
return(-3);
|
||||||
|
}
|
||||||
|
minutia->reliability = reliability;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NEW 05-08-2002 */
|
||||||
|
free(pquality_map);
|
||||||
|
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
************************************************************************
|
||||||
|
#cat: grayscale_reliability - Given a minutia point, computes a reliability
|
||||||
|
#cat: measure from the stdev and mean of its pixel neighborhood.
|
||||||
|
|
||||||
|
Code originally written by Austin Hicklin for FBI ATU
|
||||||
|
Modified by Michael D. Garris (NIST) Sept. 25, 2000
|
||||||
|
|
||||||
|
GrayScaleReliability - reasonable reliability heuristic, returns
|
||||||
|
0.0 .. 1.0 based on stdev and Mean of a localized histogram where
|
||||||
|
"ideal" stdev is >=64; "ideal" Mean is 127. In a 1 ridge radius
|
||||||
|
(11 pixels), if the bytevalue (shade of gray) in the image has a
|
||||||
|
stdev of >= 64 & a mean of 127, returns 1.0 (well defined
|
||||||
|
light & dark areas in equal proportions).
|
||||||
|
|
||||||
|
Input:
|
||||||
|
minutia - structure containing detected minutia
|
||||||
|
idata - 8-bit grayscale fingerprint image
|
||||||
|
iw - width (in pixels) of the image
|
||||||
|
ih - height (in pixels) of the image
|
||||||
|
radius_pix - pixel radius of surrounding neighborhood
|
||||||
|
Return Value:
|
||||||
|
reliability - computed reliability measure
|
||||||
|
************************************************************************/
|
||||||
|
double grayscale_reliability(MINUTIA *minutia, unsigned char *idata,
|
||||||
|
const int iw, const int ih, const int radius_pix)
|
||||||
|
{
|
||||||
|
double mean, stdev;
|
||||||
|
double reliability;
|
||||||
|
|
||||||
|
get_neighborhood_stats(&mean, &stdev, minutia, idata, iw, ih, radius_pix);
|
||||||
|
|
||||||
|
reliability = min((stdev>IDEALSTDEV ? 1.0 : stdev/(double)IDEALSTDEV),
|
||||||
|
(1.0-(fabs(mean-IDEALMEAN)/(double)IDEALMEAN)));
|
||||||
|
|
||||||
|
return(reliability);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
************************************************************************
|
||||||
|
#cat: get_neighborhood_stats - Given a minutia point, computes the mean
|
||||||
|
#cat: and stdev of the 8-bit grayscale pixels values in a
|
||||||
|
#cat: surrounding neighborhood with specified radius.
|
||||||
|
|
||||||
|
Code originally written by Austin Hicklin for FBI ATU
|
||||||
|
Modified by Michael D. Garris (NIST) Sept. 25, 2000
|
||||||
|
|
||||||
|
Input:
|
||||||
|
minutia - structure containing detected minutia
|
||||||
|
idata - 8-bit grayscale fingerprint image
|
||||||
|
iw - width (in pixels) of the image
|
||||||
|
ih - height (in pixels) of the image
|
||||||
|
radius_pix - pixel radius of surrounding neighborhood
|
||||||
|
Output:
|
||||||
|
mean - mean of neighboring pixels
|
||||||
|
stdev - standard deviation of neighboring pixels
|
||||||
|
************************************************************************/
|
||||||
|
void get_neighborhood_stats(double *mean, double *stdev, MINUTIA *minutia,
|
||||||
|
unsigned char *idata, const int iw, const int ih,
|
||||||
|
const int radius_pix)
|
||||||
|
{
|
||||||
|
int i, x, y, rows, cols;
|
||||||
|
int n = 0, sumX = 0, sumXX = 0;
|
||||||
|
int histogram[256];
|
||||||
|
|
||||||
|
/* Zero out histogram. */
|
||||||
|
memset(histogram, 0, 256 * sizeof(int));
|
||||||
|
|
||||||
|
/* Set minutia's coordinate variables. */
|
||||||
|
x = minutia->x;
|
||||||
|
y = minutia->y;
|
||||||
|
|
||||||
|
|
||||||
|
/* If minutiae point is within sampleboxsize distance of image border, */
|
||||||
|
/* a value of 0 reliability is returned. */
|
||||||
|
if ((x < radius_pix) || (x > iw-radius_pix-1) ||
|
||||||
|
(y < radius_pix) || (y > ih-radius_pix-1)) {
|
||||||
|
*mean = 0.0;
|
||||||
|
*stdev = 0.0;
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Foreach row in neighborhood ... */
|
||||||
|
for(rows = y - radius_pix;
|
||||||
|
rows <= y + radius_pix;
|
||||||
|
rows++){
|
||||||
|
/* Foreach column in neighborhood ... */
|
||||||
|
for(cols = x - radius_pix;
|
||||||
|
cols <= x + radius_pix;
|
||||||
|
cols++){
|
||||||
|
/* Bump neighbor's pixel value bin in histogram. */
|
||||||
|
histogram[*(idata+(rows * iw)+cols)]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Foreach grayscale pixel bin ... */
|
||||||
|
for(i = 0; i < 256; i++){
|
||||||
|
if(histogram[i]){
|
||||||
|
/* Accumulate Sum(X[i]) */
|
||||||
|
sumX += (i * histogram[i]);
|
||||||
|
/* Accumulate Sum(X[i]^2) */
|
||||||
|
sumXX += (i * i * histogram[i]);
|
||||||
|
/* Accumulate N samples */
|
||||||
|
n += histogram[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mean = Sum(X[i])/N */
|
||||||
|
*mean = sumX/(double)n;
|
||||||
|
/* Stdev = sqrt((Sum(X[i]^2)/N) - Mean^2) */
|
||||||
|
*stdev = sqrt((sumXX/(double)n) - ((*mean)*(*mean)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
************************************************************************
|
||||||
|
#cat: reliability_fr_quality_map - Takes a set of minutiae and assigns
|
||||||
|
#cat: each one a reliability measure based on 1 of 5 possible
|
||||||
|
#cat: quality levels from its location in a quality map.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
minutiae - structure contining the detected minutia
|
||||||
|
quality_map - map with blocks assigned 1 of 5 quality levels
|
||||||
|
map_w - width (in blocks) of the map
|
||||||
|
map_h - height (in blocks) of the map
|
||||||
|
blocksize - size (in pixels) of each block in the map
|
||||||
|
Output:
|
||||||
|
minutiae - updated reliability members
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
************************************************************************/
|
||||||
|
int reliability_fr_quality_map(MINUTIAE *minutiae,
|
||||||
|
int *quality_map, const int mw, const int mh,
|
||||||
|
const int iw, const int ih, const int blocksize)
|
||||||
|
{
|
||||||
|
int ret, i, index;
|
||||||
|
int *pquality_map;
|
||||||
|
MINUTIA *minutia;
|
||||||
|
|
||||||
|
/* Expand block map values to pixel map. */
|
||||||
|
if((ret = pixelize_map(&pquality_map, iw, ih,
|
||||||
|
quality_map, mw, mh, blocksize))){
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Foreach minutiae detected ... */
|
||||||
|
for(i = 0; i < minutiae->num; i++){
|
||||||
|
/* Assign minutia pointer. */
|
||||||
|
minutia = minutiae->list[i];
|
||||||
|
/* Compute minutia pixel index. */
|
||||||
|
index = (minutia->y * iw) + minutia->x;
|
||||||
|
/* Switch on pixel's quality value ... */
|
||||||
|
switch(pquality_map[index]){
|
||||||
|
case 0:
|
||||||
|
minutia->reliability = 0.0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
minutia->reliability = 0.25;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
minutia->reliability = 0.50;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
minutia->reliability = 0.75;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
minutia->reliability = 0.99;
|
||||||
|
break;
|
||||||
|
/* Error if quality value not in range [0..4]. */
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "ERROR : reliability_fr_quality_map :");
|
||||||
|
fprintf(stderr, "unexpected quality value %d ",
|
||||||
|
pquality_map[index]);
|
||||||
|
fprintf(stderr, "not in range [0..4]\n");
|
||||||
|
return(-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deallocate pixelized quality map. */
|
||||||
|
free(pquality_map);
|
||||||
|
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
3404
libfprint/nbis/mindtct/remove.c
Normal file
3404
libfprint/nbis/mindtct/remove.c
Normal file
File diff suppressed because it is too large
Load diff
682
libfprint/nbis/mindtct/results.c
Normal file
682
libfprint/nbis/mindtct/results.c
Normal file
|
@ -0,0 +1,682 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
831
libfprint/nbis/mindtct/ridges.c
Normal file
831
libfprint/nbis/mindtct/ridges.c
Normal file
|
@ -0,0 +1,831 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: RIDGES.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 08/09/1999
|
||||||
|
UPDATED: 03/16/2005 by MDG
|
||||||
|
|
||||||
|
Contains routines responsible for locating nearest minutia
|
||||||
|
neighbors and counting intervening ridges as part of the
|
||||||
|
NIST Latent Fingerprint System (LFS).
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
count_minutiae_ridges()
|
||||||
|
count_minutia_ridges()
|
||||||
|
find_neighbors()
|
||||||
|
update_nbr_dists()
|
||||||
|
insert_neighbor()
|
||||||
|
sort_neighbors()
|
||||||
|
ridge_count()
|
||||||
|
find_transition()
|
||||||
|
validate_ridge_crossing()
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <lfs.h>
|
||||||
|
#include <log.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: count_minutiae_ridges - Takes a list of minutiae, and for each one,
|
||||||
|
#cat: determines its closest neighbors and counts the number
|
||||||
|
#cat: of interveining ridges between the minutia point and
|
||||||
|
#cat: each of its neighbors.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
minutiae - list of minutiae
|
||||||
|
bdata - binary image data (0==while & 1==black)
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
ih - height (in pixels) of image
|
||||||
|
lfsparms - parameters and thresholds for controlling LFS
|
||||||
|
Output:
|
||||||
|
minutiae - list of minutiae augmented with neighbors and ridge counts
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int count_minutiae_ridges(MINUTIAE *minutiae,
|
||||||
|
unsigned char *bdata, const int iw, const int ih,
|
||||||
|
const LFSPARMS *lfsparms)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
print2log("\nFINDING NBRS AND COUNTING RIDGES:\n");
|
||||||
|
|
||||||
|
/* Sort minutia points on x then y (column-oriented). */
|
||||||
|
if((ret = sort_minutiae_x_y(minutiae, iw, ih))){
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove any duplicate minutia points from the list. */
|
||||||
|
if((ret = rm_dup_minutiae(minutiae))){
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Foreach remaining sorted minutia in list ... */
|
||||||
|
for(i = 0; i < minutiae->num-1; i++){
|
||||||
|
/* Located neighbors and count number of ridges in between. */
|
||||||
|
/* NOTE: neighbor and ridge count results are stored in */
|
||||||
|
/* minutiae->list[i]. */
|
||||||
|
if((ret = count_minutia_ridges(i, minutiae, bdata, iw, ih, lfsparms))){
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: count_minutia_ridges - Takes a minutia, and determines its closest
|
||||||
|
#cat: neighbors and counts the number of interveining ridges
|
||||||
|
#cat: between the minutia point and each of its neighbors.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
minutia - input minutia
|
||||||
|
bdata - binary image data (0==while & 1==black)
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
ih - height (in pixels) of image
|
||||||
|
lfsparms - parameters and thresholds for controlling LFS
|
||||||
|
Output:
|
||||||
|
minutiae - minutia augmented with neighbors and ridge counts
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int count_minutia_ridges(const int first, MINUTIAE *minutiae,
|
||||||
|
unsigned char *bdata, const int iw, const int ih,
|
||||||
|
const LFSPARMS *lfsparms)
|
||||||
|
{
|
||||||
|
int i, ret, *nbr_list, *nbr_nridges, nnbrs;
|
||||||
|
|
||||||
|
/* Find up to the maximum number of qualifying neighbors. */
|
||||||
|
if((ret = find_neighbors(&nbr_list, &nnbrs, lfsparms->max_nbrs,
|
||||||
|
first, minutiae))){
|
||||||
|
free(nbr_list);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
print2log("NBRS FOUND: %d,%d = %d\n", minutiae->list[first]->x,
|
||||||
|
minutiae->list[first]->y, nnbrs);
|
||||||
|
|
||||||
|
/* If no neighors found ... */
|
||||||
|
if(nnbrs == 0){
|
||||||
|
/* Then no list returned and no ridges to count. */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sort neighbors on delta dirs. */
|
||||||
|
if((ret = sort_neighbors(nbr_list, nnbrs, first, minutiae))){
|
||||||
|
free(nbr_list);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Count ridges between first and neighbors. */
|
||||||
|
/* List of ridge counts, one for each neighbor stored. */
|
||||||
|
nbr_nridges = (int *)malloc(nnbrs * sizeof(int));
|
||||||
|
if(nbr_nridges == (int *)NULL){
|
||||||
|
free(nbr_list);
|
||||||
|
fprintf(stderr, "ERROR : count_minutia_ridges : malloc : nbr_nridges\n");
|
||||||
|
return(-450);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Foreach neighbor found and sorted in list ... */
|
||||||
|
for(i = 0; i < nnbrs; i++){
|
||||||
|
/* Count the ridges between the primary minutia and the neighbor. */
|
||||||
|
ret = ridge_count(first, nbr_list[i], minutiae, bdata, iw, ih, lfsparms);
|
||||||
|
/* If system error ... */
|
||||||
|
if(ret < 0){
|
||||||
|
/* Deallocate working memories. */
|
||||||
|
free(nbr_list);
|
||||||
|
free(nbr_nridges);
|
||||||
|
/* Return error code. */
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, ridge count successful, so store ridge count to list. */
|
||||||
|
nbr_nridges[i] = ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign neighbor indices and ridge counts to primary minutia. */
|
||||||
|
minutiae->list[first]->nbrs = nbr_list;
|
||||||
|
minutiae->list[first]->ridge_counts = nbr_nridges;
|
||||||
|
minutiae->list[first]->num_nbrs = nnbrs;
|
||||||
|
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: find_neighbors - Takes a primary minutia and a list of all minutiae
|
||||||
|
#cat: and locates a specified maximum number of closest neighbors
|
||||||
|
#cat: to the primary point. Neighbors are searched, starting
|
||||||
|
#cat: in the same pixel column, below, the primary point and then
|
||||||
|
#cat: along consecutive and complete pixel columns in the image
|
||||||
|
#cat: to the right of the primary point.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
max_nbrs - maximum number of closest neighbors to be returned
|
||||||
|
first - index of the primary minutia point
|
||||||
|
minutiae - list of minutiae
|
||||||
|
Output:
|
||||||
|
onbr_list - points to list of detected closest neighbors
|
||||||
|
onnbrs - points to number of neighbors returned
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs,
|
||||||
|
const int first, MINUTIAE *minutiae)
|
||||||
|
{
|
||||||
|
int ret, second, last_nbr;
|
||||||
|
MINUTIA *minutia1, *minutia2;
|
||||||
|
int *nbr_list, nnbrs;
|
||||||
|
double *nbr_sqr_dists, xdist, xdist2;
|
||||||
|
|
||||||
|
/* Allocate list of neighbor minutiae indices. */
|
||||||
|
nbr_list = (int *)malloc(max_nbrs * sizeof(int));
|
||||||
|
if(nbr_list == (int *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : find_neighbors : malloc : nbr_list\n");
|
||||||
|
return(-460);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate list of squared euclidean distances between neighbors */
|
||||||
|
/* and current primary minutia point. */
|
||||||
|
nbr_sqr_dists = (double *)malloc(max_nbrs * sizeof(double));
|
||||||
|
if(nbr_sqr_dists == (double *)NULL){
|
||||||
|
free(nbr_list);
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR : find_neighbors : malloc : nbr_sqr_dists\n");
|
||||||
|
return(-461);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize number of stored neighbors to 0. */
|
||||||
|
nnbrs = 0;
|
||||||
|
/* Assign secondary to one passed current primary minutia. */
|
||||||
|
second = first + 1;
|
||||||
|
/* Compute location of maximum last stored neighbor. */
|
||||||
|
last_nbr = max_nbrs - 1;
|
||||||
|
|
||||||
|
/* While minutia (in sorted order) still remian for processing ... */
|
||||||
|
/* NOTE: The minutia in the input list have been sorted on X and */
|
||||||
|
/* then on Y. So, the neighbors are selected according to those */
|
||||||
|
/* that lie below the primary minutia in the same pixel column and */
|
||||||
|
/* then subsequently those that lie in complete pixel columns to */
|
||||||
|
/* the right of the primary minutia. */
|
||||||
|
while(second < minutiae->num){
|
||||||
|
/* Assign temporary minutia pointers. */
|
||||||
|
minutia1 = minutiae->list[first];
|
||||||
|
minutia2 = minutiae->list[second];
|
||||||
|
|
||||||
|
/* Compute squared distance between minutiae along x-axis. */
|
||||||
|
xdist = minutia2->x - minutia1->x;
|
||||||
|
xdist2 = xdist * xdist;
|
||||||
|
|
||||||
|
/* If the neighbor lists are not full OR the x-distance to current */
|
||||||
|
/* secondary is smaller than maximum neighbor distance stored ... */
|
||||||
|
if((nnbrs < max_nbrs) ||
|
||||||
|
(xdist2 < nbr_sqr_dists[last_nbr])){
|
||||||
|
/* Append or insert the new neighbor into the neighbor lists. */
|
||||||
|
if((ret = update_nbr_dists(nbr_list, nbr_sqr_dists, &nnbrs, max_nbrs,
|
||||||
|
first, second, minutiae))){
|
||||||
|
free(nbr_sqr_dists);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Otherwise, if the neighbor lists is full AND the x-distance */
|
||||||
|
/* to current secondary is larger than maximum neighbor distance */
|
||||||
|
/* stored ... */
|
||||||
|
else
|
||||||
|
/* So, stop searching for more neighbors. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Bump to next secondary minutia. */
|
||||||
|
second++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deallocate working memory. */
|
||||||
|
free(nbr_sqr_dists);
|
||||||
|
|
||||||
|
/* If no neighbors found ... */
|
||||||
|
if(nnbrs == 0){
|
||||||
|
/* Deallocate the neighbor list. */
|
||||||
|
free(nbr_list);
|
||||||
|
*onnbrs = 0;
|
||||||
|
}
|
||||||
|
/* Otherwise, assign neighbors to output pointer. */
|
||||||
|
else{
|
||||||
|
*onbr_list = nbr_list;
|
||||||
|
*onnbrs = nnbrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: update_nbr_dists - Takes the current list of neighbors along with a
|
||||||
|
#cat: primary minutia and a potential new neighbor, and
|
||||||
|
#cat: determines if the new neighbor is sufficiently close
|
||||||
|
#cat: to be added to the list of nearest neighbors. If added,
|
||||||
|
#cat: it is placed in the list in its proper order based on
|
||||||
|
#cat: squared distance to the primary point.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
nbr_list - current list of nearest neighbor minutia indices
|
||||||
|
nbr_sqr_dists - corresponding squared euclidean distance of each
|
||||||
|
neighbor to the primary minutia point
|
||||||
|
nnbrs - number of neighbors currently in the list
|
||||||
|
max_nbrs - maximum number of closest neighbors to be returned
|
||||||
|
first - index of the primary minutia point
|
||||||
|
second - index of the secondary (new neighbor) point
|
||||||
|
minutiae - list of minutiae
|
||||||
|
Output:
|
||||||
|
nbr_list - updated list of nearest neighbor indices
|
||||||
|
nbr_sqr_dists - updated list of nearest neighbor distances
|
||||||
|
nnbrs - number of neighbors in the update lists
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int update_nbr_dists(int *nbr_list, double *nbr_sqr_dists,
|
||||||
|
int *nnbrs, const int max_nbrs,
|
||||||
|
const int first, const int second, MINUTIAE *minutiae)
|
||||||
|
{
|
||||||
|
double dist2;
|
||||||
|
MINUTIA *minutia1, *minutia2;
|
||||||
|
int pos, last_nbr;
|
||||||
|
|
||||||
|
/* Compute position of maximum last neighbor stored. */
|
||||||
|
last_nbr = max_nbrs - 1;
|
||||||
|
|
||||||
|
/* Assigne temporary minutia pointers. */
|
||||||
|
minutia1 = minutiae->list[first];
|
||||||
|
minutia2 = minutiae->list[second];
|
||||||
|
|
||||||
|
/* Compute squared euclidean distance between minutia pair. */
|
||||||
|
dist2 = squared_distance(minutia1->x, minutia1->y,
|
||||||
|
minutia2->x, minutia2->y);
|
||||||
|
|
||||||
|
/* If maximum number of neighbors not yet stored in lists OR */
|
||||||
|
/* if the squared distance to current secondary is less */
|
||||||
|
/* than the largest stored neighbor distance ... */
|
||||||
|
if((*nnbrs < max_nbrs) ||
|
||||||
|
(dist2 < nbr_sqr_dists[last_nbr])){
|
||||||
|
|
||||||
|
/* Find insertion point in neighbor lists. */
|
||||||
|
pos = find_incr_position_dbl(dist2, nbr_sqr_dists, *nnbrs);
|
||||||
|
/* If the position returned is >= maximum list length (this should */
|
||||||
|
/* never happen, but just in case) ... */
|
||||||
|
if(pos >= max_nbrs){
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR : update_nbr_dists : illegal position for new neighbor\n");
|
||||||
|
return(-470);
|
||||||
|
}
|
||||||
|
/* Insert the new neighbor into the neighbor lists at the */
|
||||||
|
/* specified location. */
|
||||||
|
if(insert_neighbor(pos, second, dist2,
|
||||||
|
nbr_list, nbr_sqr_dists, nnbrs, max_nbrs))
|
||||||
|
return(-471);
|
||||||
|
|
||||||
|
/* Otherwise, neighbor inserted successfully, so return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
/* Otherwise, the new neighbor is not sufficiently close to be */
|
||||||
|
/* added or inserted into the neighbor lists, so ignore the neighbor */
|
||||||
|
/* and return normally. */
|
||||||
|
else
|
||||||
|
return(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: insert_neighbor - Takes a minutia index and its squared distance to a
|
||||||
|
#cat: primary minutia point, and inserts them in the specified
|
||||||
|
#cat: position of their respective lists, shifting previously
|
||||||
|
#cat: stored values down and off the lists as necessary.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
pos - postions where values are to be inserted in lists
|
||||||
|
nbr_index - index of minutia being inserted
|
||||||
|
nbr_dist2 - squared distance of minutia to its primary point
|
||||||
|
nbr_list - current list of nearest neighbor minutia indices
|
||||||
|
nbr_sqr_dists - corresponding squared euclidean distance of each
|
||||||
|
neighbor to the primary minutia point
|
||||||
|
nnbrs - number of neighbors currently in the list
|
||||||
|
max_nbrs - maximum number of closest neighbors to be returned
|
||||||
|
Output:
|
||||||
|
nbr_list - updated list of nearest neighbor indices
|
||||||
|
nbr_sqr_dists - updated list of nearest neighbor distances
|
||||||
|
nnbrs - number of neighbors in the update lists
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int insert_neighbor(const int pos, const int nbr_index, const double nbr_dist2,
|
||||||
|
int *nbr_list, double *nbr_sqr_dists,
|
||||||
|
int *nnbrs, const int max_nbrs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* If the desired insertion position is beyond one passed the last */
|
||||||
|
/* neighbor in the lists OR greater than equal to the maximum ... */
|
||||||
|
/* NOTE: pos is zero-oriented while nnbrs and max_nbrs are 1-oriented. */
|
||||||
|
if((pos > *nnbrs) ||
|
||||||
|
(pos >= max_nbrs)){
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR : insert_neighbor : insertion point exceeds lists\n");
|
||||||
|
return(-480);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the neighbor lists are NOT full ... */
|
||||||
|
if(*nnbrs < max_nbrs){
|
||||||
|
/* Then we have room to shift everything down to make room for new */
|
||||||
|
/* neighbor and increase the number of neighbors stored by 1. */
|
||||||
|
i = *nnbrs-1;
|
||||||
|
(*nnbrs)++;
|
||||||
|
}
|
||||||
|
/* Otherwise, the neighbors lists are full ... */
|
||||||
|
else if(*nnbrs == max_nbrs)
|
||||||
|
/* So, we must bump the last neighbor in the lists off to make */
|
||||||
|
/* room for the new neighbor (ignore last neighbor in lists). */
|
||||||
|
i = *nnbrs-2;
|
||||||
|
/* Otherwise, there is a list overflow error condition */
|
||||||
|
/* (shouldn't ever happen, but just in case) ... */
|
||||||
|
else{
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR : insert_neighbor : overflow in neighbor lists\n");
|
||||||
|
return(-481);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* While we havn't reached the desired insertion point ... */
|
||||||
|
while(i >= pos){
|
||||||
|
/* Shift the current neighbor down the list 1 positon. */
|
||||||
|
nbr_list[i+1] = nbr_list[i];
|
||||||
|
nbr_sqr_dists[i+1] = nbr_sqr_dists[i];
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We are now ready to put our new neighbor in the position where */
|
||||||
|
/* we shifted everything down from to make room. */
|
||||||
|
nbr_list[pos] = nbr_index;
|
||||||
|
nbr_sqr_dists[pos] = nbr_dist2;
|
||||||
|
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: sort_neighbors - Takes a list of primary minutia and its neighboring
|
||||||
|
#cat: minutia indices and sorts the neighbors based on their
|
||||||
|
#cat: position relative to the primary minutia point. Neighbors
|
||||||
|
#cat: are sorted starting vertical to the primary point and
|
||||||
|
#cat: proceeding clockwise.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
nbr_list - list of neighboring minutia indices
|
||||||
|
nnbrs - number of neighbors in the list
|
||||||
|
first - the index of the primary minutia point
|
||||||
|
minutiae - list of minutiae
|
||||||
|
Output:
|
||||||
|
nbr_list - neighboring minutia indices in sorted order
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int sort_neighbors(int *nbr_list, const int nnbrs, const int first,
|
||||||
|
MINUTIAE *minutiae)
|
||||||
|
{
|
||||||
|
double *join_thetas, theta;
|
||||||
|
int i;
|
||||||
|
static double pi2 = M_PI*2.0;
|
||||||
|
|
||||||
|
/* List of angles of lines joining the current primary to each */
|
||||||
|
/* of the secondary neighbors. */
|
||||||
|
join_thetas = (double *)malloc(nnbrs * sizeof(double));
|
||||||
|
if(join_thetas == (double *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : sort_neighbors : malloc : join_thetas\n");
|
||||||
|
return(-490);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < nnbrs; i++){
|
||||||
|
/* Compute angle to line connecting the 2 points. */
|
||||||
|
/* Coordinates are swapped and order of points reversed to */
|
||||||
|
/* account for 0 direction is vertical and positive direction */
|
||||||
|
/* is clockwise. */
|
||||||
|
theta = angle2line(minutiae->list[nbr_list[i]]->y,
|
||||||
|
minutiae->list[nbr_list[i]]->x,
|
||||||
|
minutiae->list[first]->y,
|
||||||
|
minutiae->list[first]->x);
|
||||||
|
|
||||||
|
/* Make sure the angle is positive. */
|
||||||
|
theta += pi2;
|
||||||
|
theta = fmod(theta, pi2);
|
||||||
|
join_thetas[i] = theta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sort the neighbor indicies into rank order. */
|
||||||
|
bubble_sort_double_inc_2(join_thetas, nbr_list, nnbrs);
|
||||||
|
|
||||||
|
/* Deallocate the list of angles. */
|
||||||
|
free(join_thetas);
|
||||||
|
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: ridge_count - Takes a pair of minutiae, and counts the number of
|
||||||
|
#cat: ridges crossed along the linear trajectory connecting
|
||||||
|
#cat: the 2 points in the image.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
first - index of primary minutia
|
||||||
|
second - index of secondary (neighbor) minutia
|
||||||
|
minutiae - list of minutiae
|
||||||
|
bdata - binary image data (0==while & 1==black)
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
ih - height (in pixels) of image
|
||||||
|
lfsparms - parameters and thresholds for controlling LFS
|
||||||
|
Return Code:
|
||||||
|
Zero or Positive - number of ridges counted
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int ridge_count(const int first, const int second, MINUTIAE *minutiae,
|
||||||
|
unsigned char *bdata, const int iw, const int ih,
|
||||||
|
const LFSPARMS *lfsparms)
|
||||||
|
{
|
||||||
|
MINUTIA *minutia1, *minutia2;
|
||||||
|
int i, ret, found;
|
||||||
|
int *xlist, *ylist, num;
|
||||||
|
int ridge_count, ridge_start, ridge_end;
|
||||||
|
int prevpix, curpix;
|
||||||
|
|
||||||
|
minutia1 = minutiae->list[first];
|
||||||
|
minutia2 = minutiae->list[second];
|
||||||
|
|
||||||
|
/* If the 2 mintuia have identical pixel coords ... */
|
||||||
|
if((minutia1->x == minutia2->x) &&
|
||||||
|
(minutia1->y == minutia2->y))
|
||||||
|
/* Then zero ridges between points. */
|
||||||
|
return(0);
|
||||||
|
|
||||||
|
/* Compute linear trajectory of contiguous pixels between first */
|
||||||
|
/* and second minutia points. */
|
||||||
|
if((ret = line_points(&xlist, &ylist, &num,
|
||||||
|
minutia1->x, minutia1->y, minutia2->x, minutia2->y))){
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* It there are no points on the line trajectory, then no ridges */
|
||||||
|
/* to count (this should not happen, but just in case) ... */
|
||||||
|
if(num == 0){
|
||||||
|
free(xlist);
|
||||||
|
free(ylist);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find first pixel opposite type along linear trajectory from */
|
||||||
|
/* first minutia. */
|
||||||
|
prevpix = *(bdata+(ylist[0]*iw)+xlist[0]);
|
||||||
|
i = 1;
|
||||||
|
found = FALSE;
|
||||||
|
while(i < num){
|
||||||
|
curpix = *(bdata+(ylist[i]*iw)+xlist[i]);
|
||||||
|
if(curpix != prevpix){
|
||||||
|
found = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If opposite pixel not found ... then no ridges to count */
|
||||||
|
if(!found){
|
||||||
|
free(xlist);
|
||||||
|
free(ylist);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ready to count ridges, so initialize counter to 0. */
|
||||||
|
ridge_count = 0;
|
||||||
|
|
||||||
|
print2log("RIDGE COUNT: %d,%d to %d,%d ", minutia1->x, minutia1->y,
|
||||||
|
minutia2->x, minutia2->y);
|
||||||
|
|
||||||
|
/* While not at the end of the trajectory ... */
|
||||||
|
while(i < num){
|
||||||
|
/* If 0-to-1 transition not found ... */
|
||||||
|
if(!find_transition(&i, 0, 1, xlist, ylist, num, bdata, iw, ih)){
|
||||||
|
/* Then we are done looking for ridges. */
|
||||||
|
free(xlist);
|
||||||
|
free(ylist);
|
||||||
|
|
||||||
|
print2log("\n");
|
||||||
|
|
||||||
|
/* Return number of ridges counted to this point. */
|
||||||
|
return(ridge_count);
|
||||||
|
}
|
||||||
|
/* Otherwise, we found a new ridge start transition, so store */
|
||||||
|
/* its location (the location of the 1 in 0-to-1 transition). */
|
||||||
|
ridge_start = i;
|
||||||
|
|
||||||
|
print2log(": RS %d,%d ", xlist[i], ylist[i]);
|
||||||
|
|
||||||
|
/* If 1-to-0 transition not found ... */
|
||||||
|
if(!find_transition(&i, 1, 0, xlist, ylist, num, bdata, iw, ih)){
|
||||||
|
/* Then we are done looking for ridges. */
|
||||||
|
free(xlist);
|
||||||
|
free(ylist);
|
||||||
|
|
||||||
|
print2log("\n");
|
||||||
|
|
||||||
|
/* Return number of ridges counted to this point. */
|
||||||
|
return(ridge_count);
|
||||||
|
}
|
||||||
|
/* Otherwise, we found a new ridge end transition, so store */
|
||||||
|
/* its location (the location of the 0 in 1-to-0 transition). */
|
||||||
|
ridge_end = i;
|
||||||
|
|
||||||
|
print2log("; RE %d,%d ", xlist[i], ylist[i]);
|
||||||
|
|
||||||
|
/* Conduct the validation, tracing the contour of the ridge */
|
||||||
|
/* from the ridge ending point a specified number of steps */
|
||||||
|
/* scanning for neighbors clockwise and counter-clockwise. */
|
||||||
|
/* If the ridge starting point is encounted during the trace */
|
||||||
|
/* then we can assume we do not have a valid ridge crossing */
|
||||||
|
/* and instead we are walking on and off the edge of the */
|
||||||
|
/* side of a ridge. */
|
||||||
|
ret = validate_ridge_crossing(ridge_start, ridge_end,
|
||||||
|
xlist, ylist, num, bdata, iw, ih,
|
||||||
|
lfsparms->max_ridge_steps);
|
||||||
|
|
||||||
|
/* If system error ... */
|
||||||
|
if(ret < 0){
|
||||||
|
free(xlist);
|
||||||
|
free(ylist);
|
||||||
|
/* Return the error code. */
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
print2log("; V%d ", ret);
|
||||||
|
|
||||||
|
/* If validation result is TRUE ... */
|
||||||
|
if(ret){
|
||||||
|
/* Then assume we have found a valid ridge crossing and bump */
|
||||||
|
/* the ridge counter. */
|
||||||
|
ridge_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, ignore the current ridge start and end transitions */
|
||||||
|
/* and go back and search for new ridge start. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deallocate working memories. */
|
||||||
|
free(xlist);
|
||||||
|
free(ylist);
|
||||||
|
|
||||||
|
print2log("\n");
|
||||||
|
|
||||||
|
/* Return the number of ridges counted. */
|
||||||
|
return(ridge_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: find_transition - Takes a pixel trajectory and a starting index, and
|
||||||
|
#cat: searches forward along the trajectory until the specified
|
||||||
|
#cat: adjacent pixel pair is found, returning the index where
|
||||||
|
#cat: the pair was found (the index of the second pixel).
|
||||||
|
|
||||||
|
Input:
|
||||||
|
iptr - pointer to starting pixel index into trajectory
|
||||||
|
pix1 - first pixel value in transition pair
|
||||||
|
pix2 - second pixel value in transition pair
|
||||||
|
xlist - x-pixel coords of line trajectory
|
||||||
|
ylist - y-pixel coords of line trajectory
|
||||||
|
num - number of coords in line trajectory
|
||||||
|
bdata - binary image data (0==while & 1==black)
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
ih - height (in pixels) of image
|
||||||
|
Output:
|
||||||
|
iptr - points to location where 2nd pixel in pair is found
|
||||||
|
Return Code:
|
||||||
|
TRUE - pixel pair transition found
|
||||||
|
FALSE - pixel pair transition not found
|
||||||
|
**************************************************************************/
|
||||||
|
int find_transition(int *iptr, const int pix1, const int pix2,
|
||||||
|
const int *xlist, const int *ylist, const int num,
|
||||||
|
unsigned char *bdata, const int iw, const int ih)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
/* Set previous index to starting position. */
|
||||||
|
i = *iptr;
|
||||||
|
/* Bump previous index by 1 to get next index. */
|
||||||
|
j = i+1;
|
||||||
|
|
||||||
|
/* While not one point from the end of the trajectory .. */
|
||||||
|
while(i < num-1){
|
||||||
|
/* If we have found the desired transition ... */
|
||||||
|
if((*(bdata+(ylist[i]*iw)+xlist[i]) == pix1) &&
|
||||||
|
(*(bdata+(ylist[j]*iw)+xlist[j]) == pix2)){
|
||||||
|
/* Adjust the position pointer to the location of the */
|
||||||
|
/* second pixel in the transition. */
|
||||||
|
*iptr = j;
|
||||||
|
|
||||||
|
/* Return TRUE. */
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
/* Otherwise, the desired transition was not found in current */
|
||||||
|
/* pixel pair, so bump to the next pair along the trajector. */
|
||||||
|
i++;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get here, then we exhausted the trajector without finding */
|
||||||
|
/* the desired transition, so set the position pointer to the end */
|
||||||
|
/* of the trajector, and return FALSE. */
|
||||||
|
*iptr = num;
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: validate_ridge_crossing - Takes a pair of points, a ridge start
|
||||||
|
#cat: transition and a ridge end transition, and walks the
|
||||||
|
#cat: ridge contour from thre ridge end points a specified
|
||||||
|
#cat: number of steps, looking for the ridge start point.
|
||||||
|
#cat: If found, then transitions determined not to be a valid
|
||||||
|
#cat: ridge crossing.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
ridge_start - index into line trajectory of ridge start transition
|
||||||
|
ridge_end - index into line trajectory of ridge end transition
|
||||||
|
xlist - x-pixel coords of line trajectory
|
||||||
|
ylist - y-pixel coords of line trajectory
|
||||||
|
num - number of coords in line trajectory
|
||||||
|
bdata - binary image data (0==while & 1==black)
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
ih - height (in pixels) of image
|
||||||
|
max_ridge_steps - number of steps taken in search in both
|
||||||
|
scan directions
|
||||||
|
Return Code:
|
||||||
|
TRUE - ridge crossing VALID
|
||||||
|
FALSE - ridge corssing INVALID
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int validate_ridge_crossing(const int ridge_start, const int ridge_end,
|
||||||
|
const int *xlist, const int *ylist, const int num,
|
||||||
|
unsigned char *bdata, const int iw, const int ih,
|
||||||
|
const int max_ridge_steps)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int feat_x, feat_y, edge_x, edge_y;
|
||||||
|
int *contour_x, *contour_y, *contour_ex, *contour_ey, ncontour;
|
||||||
|
|
||||||
|
/* Assign edge pixel pair for contour trace. */
|
||||||
|
feat_x = xlist[ridge_end];
|
||||||
|
feat_y = ylist[ridge_end];
|
||||||
|
edge_x = xlist[ridge_end-1];
|
||||||
|
edge_y = ylist[ridge_end-1];
|
||||||
|
|
||||||
|
/* Adjust pixel pair if they neighbor each other diagonally. */
|
||||||
|
fix_edge_pixel_pair(&feat_x, &feat_y, &edge_x, &edge_y,
|
||||||
|
bdata, iw, ih);
|
||||||
|
|
||||||
|
/* Trace ridge contour, starting at the ridge end transition, and */
|
||||||
|
/* taking a specified number of step scanning for edge neighbors */
|
||||||
|
/* clockwise. As we trace the ridge, we want to detect if we */
|
||||||
|
/* encounter the ridge start transition. NOTE: The ridge end */
|
||||||
|
/* position is on the white (of a black to white transition) and */
|
||||||
|
/* the ridge start is on the black (of a black to white trans), */
|
||||||
|
/* so the edge trace needs to look for the what pixel (not the */
|
||||||
|
/* black one) of the ridge start transition. */
|
||||||
|
ret = trace_contour(&contour_x, &contour_y,
|
||||||
|
&contour_ex, &contour_ey, &ncontour,
|
||||||
|
max_ridge_steps,
|
||||||
|
xlist[ridge_start-1], ylist[ridge_start-1],
|
||||||
|
feat_x, feat_y, edge_x, edge_y,
|
||||||
|
SCAN_CLOCKWISE, bdata, iw, ih);
|
||||||
|
/* If a system error occurred ... */
|
||||||
|
if(ret < 0)
|
||||||
|
/* Return error code. */
|
||||||
|
return(ret);
|
||||||
|
|
||||||
|
/* Otherwise, if the trace was not IGNORED, then a contour was */
|
||||||
|
/* was generated and returned. We aren't interested in the */
|
||||||
|
/* actual contour, so deallocate it. */
|
||||||
|
if(ret != IGNORE)
|
||||||
|
free_contour(contour_x, contour_y, contour_ex, contour_ey);
|
||||||
|
|
||||||
|
/* If the trace was IGNORED, then we had some sort of initialization */
|
||||||
|
/* problem, so treat this the same as if was actually located the */
|
||||||
|
/* ridge start point (in which case LOOP_FOUND is returned). */
|
||||||
|
/* So, If not IGNORED and ridge start not encounted in trace ... */
|
||||||
|
if((ret != IGNORE) &&
|
||||||
|
(ret != LOOP_FOUND)){
|
||||||
|
|
||||||
|
/* Now conduct contour trace scanning for edge neighbors counter- */
|
||||||
|
/* clockwise. */
|
||||||
|
ret = trace_contour(&contour_x, &contour_y,
|
||||||
|
&contour_ex, &contour_ey, &ncontour,
|
||||||
|
max_ridge_steps,
|
||||||
|
xlist[ridge_start-1], ylist[ridge_start-1],
|
||||||
|
feat_x, feat_y, edge_x, edge_y,
|
||||||
|
SCAN_COUNTER_CLOCKWISE, bdata, iw, ih);
|
||||||
|
/* If a system error occurred ... */
|
||||||
|
if(ret < 0)
|
||||||
|
/* Return error code. */
|
||||||
|
return(ret);
|
||||||
|
|
||||||
|
/* Otherwise, if the trace was not IGNORED, then a contour was */
|
||||||
|
/* was generated and returned. We aren't interested in the */
|
||||||
|
/* actual contour, so deallocate it. */
|
||||||
|
if(ret != IGNORE)
|
||||||
|
free_contour(contour_x, contour_y, contour_ex, contour_ey);
|
||||||
|
|
||||||
|
/* If trace not IGNORED and ridge start not encounted in 2nd trace ... */
|
||||||
|
if((ret != IGNORE) &&
|
||||||
|
(ret != LOOP_FOUND)){
|
||||||
|
/* If we get here, assume we have a ridge crossing. */
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
/* Otherwise, second trace returned IGNORE or ridge start found. */
|
||||||
|
}
|
||||||
|
/* Otherwise, first trace returned IGNORE or ridge start found. */
|
||||||
|
|
||||||
|
/* If we get here, then we failed to validate a ridge crossing. */
|
||||||
|
return(FALSE);
|
||||||
|
}
|
304
libfprint/nbis/mindtct/shape.c
Normal file
304
libfprint/nbis/mindtct/shape.c
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: SHAPE.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 05/11/1999
|
||||||
|
UPDATED: 03/16/2005 by MDG
|
||||||
|
|
||||||
|
Contains routines responsible for creating and manipulating
|
||||||
|
shape stuctures as part of the NIST Latent Fingerprint System (LFS).
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
alloc_shape()
|
||||||
|
free_shape()
|
||||||
|
dump_shape()
|
||||||
|
shape_from_contour()
|
||||||
|
sort_row_on_x()
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: alloc_shape - Allocates and initializes a shape structure given the
|
||||||
|
#cat: the X and Y limits of the shape.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
xmin - left-most x-coord in shape
|
||||||
|
ymin - top-most y-coord in shape
|
||||||
|
xmax - right-most x-coord in shape
|
||||||
|
ymax - bottom-most y-coord in shape
|
||||||
|
Output:
|
||||||
|
oshape - pointer to the allocated & initialized shape structure
|
||||||
|
Return Code:
|
||||||
|
Zero - Shape successfully allocated and initialized
|
||||||
|
Negative - System error
|
||||||
|
**************************************************************************/
|
||||||
|
int alloc_shape(SHAPE **oshape, const int xmin, const int ymin,
|
||||||
|
const int xmax, const int ymax)
|
||||||
|
{
|
||||||
|
SHAPE *shape;
|
||||||
|
int alloc_rows, alloc_pts;
|
||||||
|
int i, j, y;
|
||||||
|
|
||||||
|
/* Compute allocation parameters. */
|
||||||
|
/* First, compute the number of scanlines spanned by the shape. */
|
||||||
|
alloc_rows = ymax - ymin + 1;
|
||||||
|
/* Second, compute the "maximum" number of contour points possible */
|
||||||
|
/* on a row. Here we are allocating the maximum number of contiguous */
|
||||||
|
/* pixels on each row which will be sufficiently larger than the */
|
||||||
|
/* number of actual contour points. */
|
||||||
|
alloc_pts = xmax - xmin + 1;
|
||||||
|
|
||||||
|
/* Allocate the shape structure. */
|
||||||
|
shape = (SHAPE *)malloc(sizeof(SHAPE));
|
||||||
|
/* If there is an allocation error... */
|
||||||
|
if(shape == (SHAPE *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : alloc_shape : malloc : shape\n");
|
||||||
|
return(-250);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate the list of row pointers. We now this number will fit */
|
||||||
|
/* the shape exactly. */
|
||||||
|
shape->rows = (ROW **)malloc(alloc_rows * sizeof(ROW *));
|
||||||
|
/* If there is an allocation error... */
|
||||||
|
if(shape->rows == (ROW **)NULL){
|
||||||
|
/* Deallocate memory alloated by this routine to this point. */
|
||||||
|
free(shape);
|
||||||
|
fprintf(stderr, "ERROR : alloc_shape : malloc : shape->rows\n");
|
||||||
|
return(-251);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the shape structure's attributes. */
|
||||||
|
shape->ymin = ymin;
|
||||||
|
shape->ymax = ymax;
|
||||||
|
/* The number of allocated rows will be exactly the number of */
|
||||||
|
/* assigned rows for the shape. */
|
||||||
|
shape->alloc = alloc_rows;
|
||||||
|
shape->nrows = alloc_rows;
|
||||||
|
|
||||||
|
/* Foreach row in the shape... */
|
||||||
|
for(i = 0, y = ymin; i < alloc_rows; i++, y++){
|
||||||
|
/* Allocate a row structure and store it in its respective position */
|
||||||
|
/* in the shape structure's list of row pointers. */
|
||||||
|
shape->rows[i] = (ROW *)malloc(sizeof(ROW));
|
||||||
|
/* If there is an allocation error... */
|
||||||
|
if(shape->rows[i] == (ROW *)NULL){
|
||||||
|
/* Deallocate memory alloated by this routine to this point. */
|
||||||
|
for(j = 0; j < i; j++){
|
||||||
|
free(shape->rows[j]->xs);
|
||||||
|
free(shape->rows[j]);
|
||||||
|
}
|
||||||
|
free(shape->rows);
|
||||||
|
free(shape);
|
||||||
|
fprintf(stderr, "ERROR : alloc_shape : malloc : shape->rows[i]\n");
|
||||||
|
return(-252);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate the current rows list of x-coords. */
|
||||||
|
shape->rows[i]->xs = (int *)malloc(alloc_pts * sizeof(int));
|
||||||
|
/* If there is an allocation error... */
|
||||||
|
if(shape->rows[i]->xs == (int *)NULL){
|
||||||
|
/* Deallocate memory alloated by this routine to this point. */
|
||||||
|
for(j = 0; j < i; j++){
|
||||||
|
free(shape->rows[j]->xs);
|
||||||
|
free(shape->rows[j]);
|
||||||
|
}
|
||||||
|
free(shape->rows[i]);
|
||||||
|
free(shape->rows);
|
||||||
|
free(shape);
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR : alloc_shape : malloc : shape->rows[i]->xs\n");
|
||||||
|
return(-253);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the current row structure's attributes. */
|
||||||
|
shape->rows[i]->y = y;
|
||||||
|
shape->rows[i]->alloc = alloc_pts;
|
||||||
|
/* There are initially ZERO points assigned to the row. */
|
||||||
|
shape->rows[i]->npts = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign structure to output pointer. */
|
||||||
|
*oshape = shape;
|
||||||
|
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: free_shape - Deallocates a shape structure and all its allocated
|
||||||
|
#cat: attributes.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
shape - pointer to the shape structure to be deallocated
|
||||||
|
**************************************************************************/
|
||||||
|
void free_shape(SHAPE *shape)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Foreach allocated row in the shape ... */
|
||||||
|
for(i = 0; i < shape->alloc; i++){
|
||||||
|
/* Deallocate the current row's list of x-coords. */
|
||||||
|
free(shape->rows[i]->xs);
|
||||||
|
/* Deallocate the current row structure. */
|
||||||
|
free(shape->rows[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deallocate the list of row pointers. */
|
||||||
|
free(shape->rows);
|
||||||
|
/* Deallocate the shape structure. */
|
||||||
|
free(shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: dump_shape - Takes an initialized shape structure and dumps its contents
|
||||||
|
#cat: as formatted text to the specified open file pointer.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
shape - shape structure to be dumped
|
||||||
|
Output:
|
||||||
|
fpout - open file pointer to be written to
|
||||||
|
**************************************************************************/
|
||||||
|
void dump_shape(FILE *fpout, const SHAPE *shape)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: shape_from_contour - Converts a contour list that has been determined
|
||||||
|
#cat: to form a complete loop into a shape representation where
|
||||||
|
#cat: the contour points on each contiguous scanline of the shape
|
||||||
|
#cat: are stored in left-to-right order.
|
||||||
|
|
||||||
|
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:
|
||||||
|
oshape - points to the resulting shape structure
|
||||||
|
Return Code:
|
||||||
|
Zero - shape successfully derived
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int shape_from_contour(SHAPE **oshape, const int *contour_x,
|
||||||
|
const int *contour_y, const int ncontour)
|
||||||
|
{
|
||||||
|
SHAPE *shape;
|
||||||
|
ROW *row;
|
||||||
|
int ret, i, xmin, ymin, xmax, ymax;
|
||||||
|
|
||||||
|
/* Find xmin, ymin, xmax, ymax on contour. */
|
||||||
|
contour_limits(&xmin, &ymin, &xmax, &ymax,
|
||||||
|
contour_x, contour_y, ncontour);
|
||||||
|
|
||||||
|
/* Allocate and initialize a shape structure. */
|
||||||
|
if((ret = alloc_shape(&shape, xmin, ymin, xmax, ymax)))
|
||||||
|
/* If system error, then return error code. */
|
||||||
|
return(ret);
|
||||||
|
|
||||||
|
/* Foreach point on contour ... */
|
||||||
|
for(i = 0; i < ncontour; i++){
|
||||||
|
/* Add point to corresponding row. */
|
||||||
|
/* First set a pointer to the current row. We need to subtract */
|
||||||
|
/* ymin because the rows are indexed relative to the top-most */
|
||||||
|
/* scanline in the shape. */
|
||||||
|
row = shape->rows[contour_y[i]-ymin];
|
||||||
|
|
||||||
|
/* It is possible with complex shapes to reencounter points */
|
||||||
|
/* already visited on a contour, especially at "pinching" points */
|
||||||
|
/* along the contour. So we need to test to see if a point has */
|
||||||
|
/* already been stored in the row. If not in row list already ... */
|
||||||
|
if(in_int_list(contour_x[i], row->xs, row->npts) < 0){
|
||||||
|
/* If row is full ... */
|
||||||
|
if(row->npts >= row->alloc){
|
||||||
|
/* This should never happen becuase we have allocated */
|
||||||
|
/* based on shape bounding limits. */
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR : shape_from_contour : row overflow\n");
|
||||||
|
return(-260);
|
||||||
|
}
|
||||||
|
/* Assign the x-coord of the current contour point to the row */
|
||||||
|
/* and bump the row's point counter. All the contour points */
|
||||||
|
/* on the same row share the same y-coord. */
|
||||||
|
row->xs[row->npts++] = contour_x[i];
|
||||||
|
}
|
||||||
|
/* Otherwise, point is already stored in row, so ignore. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Foreach row in the shape. */
|
||||||
|
for(i = 0; i < shape->nrows; i++)
|
||||||
|
/* Sort row points increasing on their x-coord. */
|
||||||
|
sort_row_on_x(shape->rows[i]);
|
||||||
|
|
||||||
|
/* Assign shape structure to output pointer. */
|
||||||
|
*oshape = shape;
|
||||||
|
|
||||||
|
/* Return normally. */
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
320
libfprint/nbis/mindtct/sort.c
Normal file
320
libfprint/nbis/mindtct/sort.c
Normal file
|
@ -0,0 +1,320 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: SORT.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 03/16/1999
|
||||||
|
UPDATED: 03/16/2005 by MDG
|
||||||
|
|
||||||
|
Contains sorting routines required by the NIST Latent Fingerprint
|
||||||
|
System (LFS).
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
sort_indices_int_inc()
|
||||||
|
sort_indices_double_inc()
|
||||||
|
bubble_sort_int_inc_2()
|
||||||
|
bubble_sort_double_inc_2()
|
||||||
|
bubble_sort_double_dec_2()
|
||||||
|
bubble_sort_int_inc()
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: sort_indices_int_inc - Takes a list of integers and returns a list of
|
||||||
|
#cat: indices referencing the integer list in increasing order.
|
||||||
|
#cat: The original list of integers is also returned in sorted
|
||||||
|
#cat: order.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
ranks - list of integers to be sorted
|
||||||
|
num - number of integers in the list
|
||||||
|
Output:
|
||||||
|
optr - list of indices referencing the integer list in sorted order
|
||||||
|
ranks - list of integers in increasing order
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int sort_indices_int_inc(int **optr, int *ranks, const int num)
|
||||||
|
{
|
||||||
|
int *order;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Allocate list of sequential indices. */
|
||||||
|
order = (int *)malloc(num * sizeof(int));
|
||||||
|
if(order == (int *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : sort_indices_int_inc : malloc : order\n");
|
||||||
|
return(-390);
|
||||||
|
}
|
||||||
|
/* Initialize list of sequential indices. */
|
||||||
|
for(i = 0; i < num; i++)
|
||||||
|
order[i] = i;
|
||||||
|
|
||||||
|
/* Sort the indecies into rank order. */
|
||||||
|
bubble_sort_int_inc_2(ranks, order, num);
|
||||||
|
|
||||||
|
/* Set output pointer to the resulting order of sorted indices. */
|
||||||
|
*optr = order;
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: sort_indices_double_inc - Takes a list of doubles and returns a list of
|
||||||
|
#cat: indices referencing the double list in increasing order.
|
||||||
|
#cat: The original list of doubles is also returned in sorted
|
||||||
|
#cat: order.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
ranks - list of doubles to be sorted
|
||||||
|
num - number of doubles in the list
|
||||||
|
Output:
|
||||||
|
optr - list of indices referencing the double list in sorted order
|
||||||
|
ranks - list of doubles in increasing order
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int sort_indices_double_inc(int **optr, double *ranks, const int num)
|
||||||
|
{
|
||||||
|
int *order;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Allocate list of sequential indices. */
|
||||||
|
order = (int *)malloc(num * sizeof(int));
|
||||||
|
if(order == (int *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : sort_indices_double_inc : malloc : order\n");
|
||||||
|
return(-400);
|
||||||
|
}
|
||||||
|
/* Initialize list of sequential indices. */
|
||||||
|
for(i = 0; i < num; i++)
|
||||||
|
order[i] = i;
|
||||||
|
|
||||||
|
/* Sort the indicies into rank order. */
|
||||||
|
bubble_sort_double_inc_2(ranks, order, num);
|
||||||
|
|
||||||
|
/* Set output pointer to the resulting order of sorted indices. */
|
||||||
|
*optr = order;
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: bubble_sort_int_inc_2 - Takes a list of integer ranks and a corresponding
|
||||||
|
#cat: list of integer attributes, and sorts the ranks
|
||||||
|
#cat: into increasing order moving the attributes
|
||||||
|
#cat: correspondingly.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
ranks - list of integers to be sort on
|
||||||
|
items - list of corresponding integer attributes
|
||||||
|
len - number of items in list
|
||||||
|
Output:
|
||||||
|
ranks - list of integers sorted in increasing order
|
||||||
|
items - list of attributes in corresponding sorted order
|
||||||
|
**************************************************************************/
|
||||||
|
void bubble_sort_int_inc_2(int *ranks, int *items, const int len)
|
||||||
|
{
|
||||||
|
int done = 0;
|
||||||
|
int i, p, n, trank, titem;
|
||||||
|
|
||||||
|
/* Set counter to the length of the list being sorted. */
|
||||||
|
n = len;
|
||||||
|
|
||||||
|
/* While swaps in order continue to occur from the */
|
||||||
|
/* previous iteration... */
|
||||||
|
while(!done){
|
||||||
|
/* Reset the done flag to TRUE. */
|
||||||
|
done = TRUE;
|
||||||
|
/* Foreach rank in list up to current end index... */
|
||||||
|
/* ("p" points to current rank and "i" points to the next rank.) */
|
||||||
|
for (i=1, p = 0; i<n; i++, p++){
|
||||||
|
/* If previous rank is < current rank ... */
|
||||||
|
if(ranks[p] > ranks[i]){
|
||||||
|
/* Swap ranks. */
|
||||||
|
trank = ranks[i];
|
||||||
|
ranks[i] = ranks[p];
|
||||||
|
ranks[p] = trank;
|
||||||
|
/* Swap items. */
|
||||||
|
titem = items[i];
|
||||||
|
items[i] = items[p];
|
||||||
|
items[p] = titem;
|
||||||
|
/* Changes were made, so set done flag to FALSE. */
|
||||||
|
done = FALSE;
|
||||||
|
}
|
||||||
|
/* Otherwise, rank pair is in order, so continue. */
|
||||||
|
}
|
||||||
|
/* Decrement the ending index. */
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: bubble_sort_double_inc_2 - Takes a list of double ranks and a
|
||||||
|
#cat: corresponding list of integer attributes, and sorts the
|
||||||
|
#cat: ranks into increasing order moving the attributes
|
||||||
|
#cat: correspondingly.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
ranks - list of double to be sort on
|
||||||
|
items - list of corresponding integer attributes
|
||||||
|
len - number of items in list
|
||||||
|
Output:
|
||||||
|
ranks - list of doubles sorted in increasing order
|
||||||
|
items - list of attributes in corresponding sorted order
|
||||||
|
**************************************************************************/
|
||||||
|
void bubble_sort_double_inc_2(double *ranks, int *items, const int len)
|
||||||
|
{
|
||||||
|
int done = 0;
|
||||||
|
int i, p, n, titem;
|
||||||
|
double trank;
|
||||||
|
|
||||||
|
/* Set counter to the length of the list being sorted. */
|
||||||
|
n = len;
|
||||||
|
|
||||||
|
/* While swaps in order continue to occur from the */
|
||||||
|
/* previous iteration... */
|
||||||
|
while(!done){
|
||||||
|
/* Reset the done flag to TRUE. */
|
||||||
|
done = TRUE;
|
||||||
|
/* Foreach rank in list up to current end index... */
|
||||||
|
/* ("p" points to current rank and "i" points to the next rank.) */
|
||||||
|
for (i=1, p = 0; i<n; i++, p++){
|
||||||
|
/* If previous rank is < current rank ... */
|
||||||
|
if(ranks[p] > ranks[i]){
|
||||||
|
/* Swap ranks. */
|
||||||
|
trank = ranks[i];
|
||||||
|
ranks[i] = ranks[p];
|
||||||
|
ranks[p] = trank;
|
||||||
|
/* Swap items. */
|
||||||
|
titem = items[i];
|
||||||
|
items[i] = items[p];
|
||||||
|
items[p] = titem;
|
||||||
|
/* Changes were made, so set done flag to FALSE. */
|
||||||
|
done = FALSE;
|
||||||
|
}
|
||||||
|
/* Otherwise, rank pair is in order, so continue. */
|
||||||
|
}
|
||||||
|
/* Decrement the ending index. */
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: bubble_sort_double_dec_2 - Conducts a simple bubble sort returning a list
|
||||||
|
#cat: of ranks in decreasing order and their associated items in sorted
|
||||||
|
#cat: order as well.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
ranks - list of values to be sorted
|
||||||
|
items - list of items, each corresponding to a particular rank value
|
||||||
|
len - length of the lists to be sorted
|
||||||
|
Output:
|
||||||
|
ranks - list of values sorted in descending order
|
||||||
|
items - list of items in the corresponding sorted order of the ranks.
|
||||||
|
If these items are indices, upon return, they may be used as
|
||||||
|
indirect addresses reflecting the sorted order of the ranks.
|
||||||
|
****************************************************************************/
|
||||||
|
void bubble_sort_double_dec_2(double *ranks, int *items, const int len)
|
||||||
|
{
|
||||||
|
int done = 0;
|
||||||
|
int i, p, n, titem;
|
||||||
|
double trank;
|
||||||
|
|
||||||
|
n = len;
|
||||||
|
while(!done){
|
||||||
|
done = 1;
|
||||||
|
for (i=1, p = 0;i<n;i++, p++){
|
||||||
|
/* If previous rank is < current rank ... */
|
||||||
|
if(ranks[p] < ranks[i]){
|
||||||
|
/* Swap ranks */
|
||||||
|
trank = ranks[i];
|
||||||
|
ranks[i] = ranks[p];
|
||||||
|
ranks[p] = trank;
|
||||||
|
/* Swap corresponding items */
|
||||||
|
titem = items[i];
|
||||||
|
items[i] = items[p];
|
||||||
|
items[p] = titem;
|
||||||
|
done = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: bubble_sort_int_inc - Takes a list of integers and sorts them into
|
||||||
|
#cat: increasing order using a simple bubble sort.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
ranks - list of integers to be sort on
|
||||||
|
len - number of items in list
|
||||||
|
Output:
|
||||||
|
ranks - list of integers sorted in increasing order
|
||||||
|
**************************************************************************/
|
||||||
|
void bubble_sort_int_inc(int *ranks, const int len)
|
||||||
|
{
|
||||||
|
int done = 0;
|
||||||
|
int i, p, n;
|
||||||
|
int trank;
|
||||||
|
|
||||||
|
/* Set counter to the length of the list being sorted. */
|
||||||
|
n = len;
|
||||||
|
|
||||||
|
/* While swaps in order continue to occur from the */
|
||||||
|
/* previous iteration... */
|
||||||
|
while(!done){
|
||||||
|
/* Reset the done flag to TRUE. */
|
||||||
|
done = TRUE;
|
||||||
|
/* Foreach rank in list up to current end index... */
|
||||||
|
/* ("p" points to current rank and "i" points to the next rank.) */
|
||||||
|
for (i=1, p = 0; i<n; i++, p++){
|
||||||
|
/* If previous rank is < current rank ... */
|
||||||
|
if(ranks[p] > ranks[i]){
|
||||||
|
/* Swap ranks. */
|
||||||
|
trank = ranks[i];
|
||||||
|
ranks[i] = ranks[p];
|
||||||
|
ranks[p] = trank;
|
||||||
|
/* Changes were made, so set done flag to FALSE. */
|
||||||
|
done = FALSE;
|
||||||
|
}
|
||||||
|
/* Otherwise, rank pair is in order, so continue. */
|
||||||
|
}
|
||||||
|
/* Decrement the ending index. */
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
605
libfprint/nbis/mindtct/util.c
Normal file
605
libfprint/nbis/mindtct/util.c
Normal file
|
@ -0,0 +1,605 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: UTIL.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 03/16/1999
|
||||||
|
|
||||||
|
Contains general support routines required by the NIST
|
||||||
|
Latent Fingerprint System (LFS).
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
maxv()
|
||||||
|
minv()
|
||||||
|
minmaxs()
|
||||||
|
distance()
|
||||||
|
squared_distance()
|
||||||
|
in_int_list()
|
||||||
|
remove_from_int_list()
|
||||||
|
find_incr_position_dbl()
|
||||||
|
angle2line()
|
||||||
|
line2direction()
|
||||||
|
closest_dir_dist()
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <lfs.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: maxv - Determines the maximum value in the given list of integers.
|
||||||
|
#cat: NOTE, the list is assumed to be NOT empty!
|
||||||
|
|
||||||
|
Input:
|
||||||
|
list - non-empty list of integers to be searched
|
||||||
|
num - number of integers in the list
|
||||||
|
Return Code:
|
||||||
|
Maximum - maximum value in the list
|
||||||
|
**************************************************************************/
|
||||||
|
int maxv(const int *list, const int num)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int maxval;
|
||||||
|
|
||||||
|
/* NOTE: The list is assumed to be NOT empty. */
|
||||||
|
/* Initialize running maximum to first item in list. */
|
||||||
|
maxval = list[0];
|
||||||
|
|
||||||
|
/* Foreach subsequent item in the list... */
|
||||||
|
for(i = 1; i < num; i++){
|
||||||
|
/* If current item is larger than running maximum... */
|
||||||
|
if(list[i] > maxval)
|
||||||
|
/* Set running maximum to the larger item. */
|
||||||
|
maxval = list[i];
|
||||||
|
/* Otherwise, skip to next item. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the resulting maximum. */
|
||||||
|
return(maxval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: minv - Determines the minimum value in the given list of integers.
|
||||||
|
#cat: NOTE, the list is assumed to be NOT empty!
|
||||||
|
|
||||||
|
Input:
|
||||||
|
list - non-empty list of integers to be searched
|
||||||
|
num - number of integers in the list
|
||||||
|
Return Code:
|
||||||
|
Minimum - minimum value in the list
|
||||||
|
**************************************************************************/
|
||||||
|
int minv(const int *list, const int num)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int minval;
|
||||||
|
|
||||||
|
/* NOTE: The list is assumed to be NOT empty. */
|
||||||
|
/* Initialize running minimum to first item in list. */
|
||||||
|
minval = list[0];
|
||||||
|
|
||||||
|
/* Foreach subsequent item in the list... */
|
||||||
|
for(i = 1; i < num; i++){
|
||||||
|
/* If current item is smaller than running minimum... */
|
||||||
|
if(list[i] < minval)
|
||||||
|
/* Set running minimum to the smaller item. */
|
||||||
|
minval = list[i];
|
||||||
|
/* Otherwise, skip to next item. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the resulting minimum. */
|
||||||
|
return(minval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: minmaxs - Takes a list of integers and identifies points of relative
|
||||||
|
#cat: minima and maxima. The midpoint of flat plateaus and valleys
|
||||||
|
#cat: are selected when they are detected.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
items - list of integers to be analyzed
|
||||||
|
num - number of items in the list
|
||||||
|
Output:
|
||||||
|
ominmax_val - value of the item at each minima or maxima
|
||||||
|
ominmax_type - identifies a minima as '-1' and maxima as '1'
|
||||||
|
ominmax_i - index of item's position in list
|
||||||
|
ominmax_alloc - number of allocated minima and/or maxima
|
||||||
|
ominmax_num - number of detected minima and/or maxima
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int minmaxs(int **ominmax_val, int **ominmax_type, int **ominmax_i,
|
||||||
|
int *ominmax_alloc, int *ominmax_num,
|
||||||
|
const int *items, const int num)
|
||||||
|
{
|
||||||
|
int i, diff, state, start, loc;
|
||||||
|
int *minmax_val, *minmax_type, *minmax_i, minmax_alloc, minmax_num;
|
||||||
|
|
||||||
|
|
||||||
|
/* Determine maximum length for allocation of buffers. */
|
||||||
|
/* If there are fewer than 3 items ... */
|
||||||
|
if(num < 3){
|
||||||
|
/* Then no min/max is possible, so set allocated length */
|
||||||
|
/* to 0 and return. */
|
||||||
|
*ominmax_alloc = 0;
|
||||||
|
*ominmax_num = 0;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
/* Otherwise, set allocation length to number of items - 2 */
|
||||||
|
/* (one for the first item in the list, and on for the last). */
|
||||||
|
/* Every other intermediate point can potentially represent a */
|
||||||
|
/* min or max. */
|
||||||
|
minmax_alloc = num - 2;
|
||||||
|
/* Allocate the buffers. */
|
||||||
|
minmax_val = (int *)malloc(minmax_alloc * sizeof(int));
|
||||||
|
if(minmax_val == (int *)NULL){
|
||||||
|
fprintf(stderr, "ERROR : minmaxs : malloc : minmax_val\n");
|
||||||
|
return(-290);
|
||||||
|
}
|
||||||
|
minmax_type = (int *)malloc(minmax_alloc * sizeof(int));
|
||||||
|
if(minmax_type == (int *)NULL){
|
||||||
|
free(minmax_val);
|
||||||
|
fprintf(stderr, "ERROR : minmaxs : malloc : minmax_type\n");
|
||||||
|
return(-291);
|
||||||
|
}
|
||||||
|
minmax_i = (int *)malloc(minmax_alloc * sizeof(int));
|
||||||
|
if(minmax_i == (int *)NULL){
|
||||||
|
free(minmax_val);
|
||||||
|
free(minmax_type);
|
||||||
|
fprintf(stderr, "ERROR : minmaxs : malloc : minmax_i\n");
|
||||||
|
return(-292);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize number of min/max to 0. */
|
||||||
|
minmax_num = 0;
|
||||||
|
|
||||||
|
/* Start witht the first item in the list. */
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
/* Get starting state between first pair of items. */
|
||||||
|
diff = items[1] - items[0];
|
||||||
|
if(diff > 0)
|
||||||
|
state = 1;
|
||||||
|
else if (diff < 0)
|
||||||
|
state = -1;
|
||||||
|
else
|
||||||
|
state = 0;
|
||||||
|
|
||||||
|
/* Set start location to first item in list. */
|
||||||
|
start = 0;
|
||||||
|
|
||||||
|
/* Bump to next item in list. */
|
||||||
|
i++;
|
||||||
|
|
||||||
|
/* While not at the last item in list. */
|
||||||
|
while(i < num-1){
|
||||||
|
|
||||||
|
/* Compute difference between next pair of items. */
|
||||||
|
diff = items[i+1] - items[i];
|
||||||
|
/* If items are increasing ... */
|
||||||
|
if(diff > 0){
|
||||||
|
/* If previously increasing ... */
|
||||||
|
if(state == 1){
|
||||||
|
/* Reset start to current location. */
|
||||||
|
start = i;
|
||||||
|
}
|
||||||
|
/* If previously decreasing ... */
|
||||||
|
else if (state == -1){
|
||||||
|
/* Then we have incurred a minima ... */
|
||||||
|
/* Compute midpoint of minima. */
|
||||||
|
loc = (start + i)/2;
|
||||||
|
/* Store value at minima midpoint. */
|
||||||
|
minmax_val[minmax_num] = items[loc];
|
||||||
|
/* Store type code for minima. */
|
||||||
|
minmax_type[minmax_num] = -1;
|
||||||
|
/* Store location of minima midpoint. */
|
||||||
|
minmax_i[minmax_num++] = loc;
|
||||||
|
/* Change state to increasing. */
|
||||||
|
state = 1;
|
||||||
|
/* Reset start location. */
|
||||||
|
start = i;
|
||||||
|
}
|
||||||
|
/* If previously level (this state only can occur at the */
|
||||||
|
/* beginning of the list of items) ... */
|
||||||
|
else {
|
||||||
|
/* If more than one level state in a row ... */
|
||||||
|
if(i-start > 1){
|
||||||
|
/* Then consider a minima ... */
|
||||||
|
/* Compute midpoint of minima. */
|
||||||
|
loc = (start + i)/2;
|
||||||
|
/* Store value at minima midpoint. */
|
||||||
|
minmax_val[minmax_num] = items[loc];
|
||||||
|
/* Store type code for minima. */
|
||||||
|
minmax_type[minmax_num] = -1;
|
||||||
|
/* Store location of minima midpoint. */
|
||||||
|
minmax_i[minmax_num++] = loc;
|
||||||
|
/* Change state to increasing. */
|
||||||
|
state = 1;
|
||||||
|
/* Reset start location. */
|
||||||
|
start = i;
|
||||||
|
}
|
||||||
|
/* Otherwise, ignore single level state. */
|
||||||
|
else{
|
||||||
|
/* Change state to increasing. */
|
||||||
|
state = 1;
|
||||||
|
/* Reset start location. */
|
||||||
|
start = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* If items are decreasing ... */
|
||||||
|
else if(diff < 0){
|
||||||
|
/* If previously decreasing ... */
|
||||||
|
if(state == -1){
|
||||||
|
/* Reset start to current location. */
|
||||||
|
start = i;
|
||||||
|
}
|
||||||
|
/* If previously increasing ... */
|
||||||
|
else if (state == 1){
|
||||||
|
/* Then we have incurred a maxima ... */
|
||||||
|
/* Compute midpoint of maxima. */
|
||||||
|
loc = (start + i)/2;
|
||||||
|
/* Store value at maxima midpoint. */
|
||||||
|
minmax_val[minmax_num] = items[loc];
|
||||||
|
/* Store type code for maxima. */
|
||||||
|
minmax_type[minmax_num] = 1;
|
||||||
|
/* Store location of maxima midpoint. */
|
||||||
|
minmax_i[minmax_num++] = loc;
|
||||||
|
/* Change state to decreasing. */
|
||||||
|
state = -1;
|
||||||
|
/* Reset start location. */
|
||||||
|
start = i;
|
||||||
|
}
|
||||||
|
/* If previously level (this state only can occur at the */
|
||||||
|
/* beginning of the list of items) ... */
|
||||||
|
else {
|
||||||
|
/* If more than one level state in a row ... */
|
||||||
|
if(i-start > 1){
|
||||||
|
/* Then consider a maxima ... */
|
||||||
|
/* Compute midpoint of maxima. */
|
||||||
|
loc = (start + i)/2;
|
||||||
|
/* Store value at maxima midpoint. */
|
||||||
|
minmax_val[minmax_num] = items[loc];
|
||||||
|
/* Store type code for maxima. */
|
||||||
|
minmax_type[minmax_num] = 1;
|
||||||
|
/* Store location of maxima midpoint. */
|
||||||
|
minmax_i[minmax_num++] = loc;
|
||||||
|
/* Change state to decreasing. */
|
||||||
|
state = -1;
|
||||||
|
/* Reset start location. */
|
||||||
|
start = i;
|
||||||
|
}
|
||||||
|
/* Otherwise, ignore single level state. */
|
||||||
|
else{
|
||||||
|
/* Change state to decreasing. */
|
||||||
|
state = -1;
|
||||||
|
/* Reset start location. */
|
||||||
|
start = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Otherwise, items are level, so continue to next item pair. */
|
||||||
|
|
||||||
|
/* Advance to next item pair in list. */
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set results to output pointers. */
|
||||||
|
*ominmax_val = minmax_val;
|
||||||
|
*ominmax_type = minmax_type;
|
||||||
|
*ominmax_i = minmax_i;
|
||||||
|
*ominmax_alloc = minmax_alloc;
|
||||||
|
*ominmax_num = minmax_num;
|
||||||
|
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: distance - Takes two coordinate points and computes the
|
||||||
|
#cat: Euclidean distance between the two points.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
x1 - x-coord of first point
|
||||||
|
y1 - y-coord of first point
|
||||||
|
x2 - x-coord of second point
|
||||||
|
y2 - y-coord of second point
|
||||||
|
Return Code:
|
||||||
|
Distance - computed Euclidean distance
|
||||||
|
**************************************************************************/
|
||||||
|
double distance(const int x1, const int y1, const int x2, const int y2)
|
||||||
|
{
|
||||||
|
double dx, dy, dist;
|
||||||
|
|
||||||
|
/* Compute delta x between points. */
|
||||||
|
dx = (double)(x1 - x2);
|
||||||
|
/* Compute delta y between points. */
|
||||||
|
dy = (double)(y1 - y2);
|
||||||
|
/* Compute the squared distance between points. */
|
||||||
|
dist = (dx*dx) + (dy*dy);
|
||||||
|
/* Take square root of squared distance. */
|
||||||
|
dist = sqrt(dist);
|
||||||
|
|
||||||
|
/* Return the squared distance. */
|
||||||
|
return(dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: squared_distance - Takes two coordinate points and computes the
|
||||||
|
#cat: squared distance between the two points.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
x1 - x-coord of first point
|
||||||
|
y1 - y-coord of first point
|
||||||
|
x2 - x-coord of second point
|
||||||
|
y2 - y-coord of second point
|
||||||
|
Return Code:
|
||||||
|
Distance - computed squared distance
|
||||||
|
**************************************************************************/
|
||||||
|
double squared_distance(const int x1, const int y1, const int x2, const int y2)
|
||||||
|
{
|
||||||
|
double dx, dy, dist;
|
||||||
|
|
||||||
|
/* Compute delta x between points. */
|
||||||
|
dx = (double)(x1 - x2);
|
||||||
|
/* Compute delta y between points. */
|
||||||
|
dy = (double)(y1 - y2);
|
||||||
|
/* Compute the squared distance between points. */
|
||||||
|
dist = (dx*dx) + (dy*dy);
|
||||||
|
|
||||||
|
/* Return the squared distance. */
|
||||||
|
return(dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: in_int_list - Determines if a specified value is store in a list of
|
||||||
|
#cat: integers and returns its location if found.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
item - value to search for in list
|
||||||
|
list - list of integers to be searched
|
||||||
|
len - number of integers in search list
|
||||||
|
Return Code:
|
||||||
|
Zero or greater - first location found equal to search value
|
||||||
|
Negative - search value not found in the list of integers
|
||||||
|
**************************************************************************/
|
||||||
|
int in_int_list(const int item, const int *list, const int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Foreach item in list ... */
|
||||||
|
for(i = 0; i < len; i++){
|
||||||
|
/* If search item found in list ... */
|
||||||
|
if(list[i] == item)
|
||||||
|
/* Return the location in list where found. */
|
||||||
|
return(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get here, then search item not found in list, */
|
||||||
|
/* so return -1 ==> NOT FOUND. */
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: remove_from_int_list - Takes a position index into an integer list and
|
||||||
|
#cat: removes the value from the list, collapsing the resulting
|
||||||
|
#cat: list.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
index - position of value to be removed from list
|
||||||
|
list - input list of integers
|
||||||
|
num - number of integers in the list
|
||||||
|
Output:
|
||||||
|
list - list with specified integer removed
|
||||||
|
num - decremented number of integers in list
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int remove_from_int_list(const int index, int *list, const int num)
|
||||||
|
{
|
||||||
|
int fr, to;
|
||||||
|
|
||||||
|
/* Make sure the requested index is within range. */
|
||||||
|
if((index < 0) && (index >= num)){
|
||||||
|
fprintf(stderr, "ERROR : remove_from_int_list : index out of range\n");
|
||||||
|
return(-370);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Slide the remaining list of integers up over top of the */
|
||||||
|
/* position of the integer being removed. */
|
||||||
|
for(to = index, fr = index+1; fr < num; to++, fr++)
|
||||||
|
list[to] = list[fr];
|
||||||
|
|
||||||
|
/* NOTE: Decrementing the number of integers remaining in the list is */
|
||||||
|
/* the responsibility of the caller! */
|
||||||
|
|
||||||
|
/* Return normally. */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: ind_incr_position_dbl - Takes a double value and a list of doubles and
|
||||||
|
#cat: determines where in the list the double may be inserted,
|
||||||
|
#cat: preserving the increasing sorted order of the list.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
val - value to be inserted into the list
|
||||||
|
list - list of double in increasing sorted order
|
||||||
|
num - number of values in the list
|
||||||
|
Return Code:
|
||||||
|
Zero or Positive - insertion position in the list
|
||||||
|
**************************************************************************/
|
||||||
|
int find_incr_position_dbl(const double val, double *list, const int num)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Foreach item in double list ... */
|
||||||
|
for(i = 0; i < num; i++){
|
||||||
|
/* If the value is smaller than the current item in list ... */
|
||||||
|
if(val < list[i])
|
||||||
|
/* Then we found were to insert the value in the list maintaining */
|
||||||
|
/* an increasing sorted order. */
|
||||||
|
return(i);
|
||||||
|
|
||||||
|
/* Otherwise, the value is still larger than current item, so */
|
||||||
|
/* continue to next item in the list. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, we never found a slot within the list to insert the */
|
||||||
|
/* the value, so place at the end of the sorted list. */
|
||||||
|
return(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: angle2line - Takes two coordinate points and computes the angle
|
||||||
|
#cat: to the line formed by the two points.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
fx - x-coord of first point
|
||||||
|
fy - y-coord of first point
|
||||||
|
tx - x-coord of second point
|
||||||
|
ty - y-coord of second point
|
||||||
|
Return Code:
|
||||||
|
Angle - angle to the specified line
|
||||||
|
**************************************************************************/
|
||||||
|
double angle2line(const int fx, const int fy, const int tx, const int ty)
|
||||||
|
{
|
||||||
|
double dx, dy, theta;
|
||||||
|
|
||||||
|
/* Compute slope of line connecting the 2 specified points. */
|
||||||
|
dy = (double)(fy - ty);
|
||||||
|
dx = (double)(tx - fx);
|
||||||
|
/* If delta's are sufficiently small ... */
|
||||||
|
if((fabs(dx) < MIN_SLOPE_DELTA) && (fabs(dy) < MIN_SLOPE_DELTA))
|
||||||
|
theta = 0.0;
|
||||||
|
/* Otherwise, compute angle to the line. */
|
||||||
|
else
|
||||||
|
theta = atan2(dy, dx);
|
||||||
|
|
||||||
|
/* Return the compute angle in radians. */
|
||||||
|
return(theta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: line2direction - Takes two coordinate points and computes the
|
||||||
|
#cat: directon (on a full circle) in which the first points
|
||||||
|
#cat: to the second.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
fx - x-coord of first point (pointing from)
|
||||||
|
fy - y-coord of first point (pointing from)
|
||||||
|
tx - x-coord of second point (pointing to)
|
||||||
|
ty - y-coord of second point (pointing to)
|
||||||
|
ndirs - number of IMAP directions (in semicircle)
|
||||||
|
Return Code:
|
||||||
|
Direction - determined direction on a "full" circle
|
||||||
|
**************************************************************************/
|
||||||
|
int line2direction(const int fx, const int fy,
|
||||||
|
const int tx, const int ty, const int ndirs)
|
||||||
|
{
|
||||||
|
double theta, pi_factor;
|
||||||
|
int idir, full_ndirs;
|
||||||
|
static double pi2 = M_PI*2.0;
|
||||||
|
|
||||||
|
/* Compute angle to line connecting the 2 points. */
|
||||||
|
/* Coordinates are swapped and order of points reversed to */
|
||||||
|
/* account for 0 direction is vertical and positive direction */
|
||||||
|
/* is clockwise. */
|
||||||
|
theta = angle2line(ty, tx, fy, fx);
|
||||||
|
|
||||||
|
/* Make sure the angle is positive. */
|
||||||
|
theta += pi2;
|
||||||
|
theta = fmod(theta, pi2);
|
||||||
|
/* Convert from radians to integer direction on range [0..(ndirsX2)]. */
|
||||||
|
/* Multiply radians by units/radian ((ndirsX2)/(2PI)), and you get */
|
||||||
|
/* angle in integer units. */
|
||||||
|
/* Compute number of directions on full circle. */
|
||||||
|
full_ndirs = ndirs<<1;
|
||||||
|
/* Compute the radians to integer direction conversion factor. */
|
||||||
|
pi_factor = (double)full_ndirs/pi2;
|
||||||
|
/* Convert radian angle to integer direction on full circle. */
|
||||||
|
theta *= pi_factor;
|
||||||
|
/* Need to truncate precision so that answers are consistent */
|
||||||
|
/* on different computer architectures when rounding doubles. */
|
||||||
|
theta = trunc_dbl_precision(theta, TRUNC_SCALE);
|
||||||
|
idir = sround(theta);
|
||||||
|
/* Make sure on range [0..(ndirsX2)]. */
|
||||||
|
idir %= full_ndirs;
|
||||||
|
|
||||||
|
/* Return the integer direction. */
|
||||||
|
return(idir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: closest_dir_dist - Takes to integer IMAP directions and determines the
|
||||||
|
#cat: closest distance between them accounting for
|
||||||
|
#cat: wrap-around either at the beginning or ending of
|
||||||
|
#cat: the range of directions.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
dir1 - integer value of the first direction
|
||||||
|
dir2 - integer value of the second direction
|
||||||
|
ndirs - the number of possible directions
|
||||||
|
Return Code:
|
||||||
|
Non-negative - distance between the 2 directions
|
||||||
|
**************************************************************************/
|
||||||
|
int closest_dir_dist(const int dir1, const int dir2, const int ndirs)
|
||||||
|
{
|
||||||
|
int d1, d2, dist;
|
||||||
|
|
||||||
|
/* Initialize distance to -1 = INVALID. */
|
||||||
|
dist = INVALID_DIR;
|
||||||
|
|
||||||
|
/* Measure shortest distance between to directions. */
|
||||||
|
/* If both neighbors are VALID ... */
|
||||||
|
if((dir1 >= 0)&&(dir2 >= 0)){
|
||||||
|
/* Compute inner and outer distances to account for distances */
|
||||||
|
/* that wrap around the end of the range of directions, which */
|
||||||
|
/* may in fact be closer. */
|
||||||
|
d1 = abs(dir2 - dir1);
|
||||||
|
d2 = ndirs - d1;
|
||||||
|
dist = min(d1, d2);
|
||||||
|
}
|
||||||
|
/* Otherwise one or both directions are INVALID, so ignore */
|
||||||
|
/* and return INVALID. */
|
||||||
|
|
||||||
|
/* Return determined closest distance. */
|
||||||
|
return(dist);
|
||||||
|
}
|
||||||
|
|
133
libfprint/nbis/mindtct/xytreps.c
Normal file
133
libfprint/nbis/mindtct/xytreps.c
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
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: XYTREPS.C
|
||||||
|
AUTHOR: Michael D. Garris
|
||||||
|
DATE: 09/16/2004
|
||||||
|
|
||||||
|
Contains routines useful in converting minutiae in LFS "native"
|
||||||
|
representation into other representations, such as
|
||||||
|
M1 (ANSI INCITS 378-2004) & NIST internal representations.
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
ROUTINES:
|
||||||
|
lfs2nist_minutia_XTY()
|
||||||
|
lfs2m1_minutia_XTY()
|
||||||
|
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <lfs.h>
|
||||||
|
#include <defs.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: lfs2nist_minutia_XYT - Converts XYT minutiae attributes in LFS native
|
||||||
|
#cat: representation to NIST internal representation
|
||||||
|
|
||||||
|
Input:
|
||||||
|
minutia - LFS minutia structure containing attributes to be converted
|
||||||
|
Output:
|
||||||
|
ox - NIST internal based x-pixel coordinate
|
||||||
|
oy - NIST internal based y-pixel coordinate
|
||||||
|
ot - NIST internal based minutia direction/orientation
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
void lfs2nist_minutia_XYT(int *ox, int *oy, int *ot,
|
||||||
|
const MINUTIA *minutia, const int iw, const int ih)
|
||||||
|
{
|
||||||
|
int x, y, t;
|
||||||
|
float degrees_per_unit;
|
||||||
|
|
||||||
|
/* XYT's 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) */
|
||||||
|
|
||||||
|
x = minutia->x;
|
||||||
|
y = ih - minutia->y;
|
||||||
|
|
||||||
|
degrees_per_unit = 180 / (float)NUM_DIRECTIONS;
|
||||||
|
|
||||||
|
t = (270 - sround(minutia->direction * degrees_per_unit)) % 360;
|
||||||
|
if(t < 0){
|
||||||
|
t += 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ox = x;
|
||||||
|
*oy = y;
|
||||||
|
*ot = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: lfs2m1_minutia_XYT - Converts XYT minutiae attributes in LFS native
|
||||||
|
#cat: representation to M1 (ANSI INCITS 378-2004) representation
|
||||||
|
|
||||||
|
Input:
|
||||||
|
minutia - LFS minutia structure containing attributes to be converted
|
||||||
|
Output:
|
||||||
|
ox - M1 based x-pixel coordinate
|
||||||
|
oy - M1 based y-pixel coordinate
|
||||||
|
ot - M1 based minutia direction/orientation
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
void lfs2m1_minutia_XYT(int *ox, int *oy, int *ot, const MINUTIA *minutia)
|
||||||
|
{
|
||||||
|
int x, y, t;
|
||||||
|
float degrees_per_unit;
|
||||||
|
|
||||||
|
/* XYT's according to M1 (ANSI INCITS 378-2004): */
|
||||||
|
/* 1. pixel coordinates with origin top-left */
|
||||||
|
/* 2. orientation in degrees on range [0..179] */
|
||||||
|
/* with 0 pointing east and increasing counter */
|
||||||
|
/* clockwise */
|
||||||
|
/* 3. direction pointing up the ridge ending or */
|
||||||
|
/* bifurcaiton valley */
|
||||||
|
|
||||||
|
x = minutia->x;
|
||||||
|
y = minutia->y;
|
||||||
|
|
||||||
|
degrees_per_unit = 180 / (float)NUM_DIRECTIONS;
|
||||||
|
t = (90 - sround(minutia->direction * degrees_per_unit)) % 360;
|
||||||
|
if(t < 0){
|
||||||
|
t += 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* range of theta is 0..179 because angles are in units of 2 degress */
|
||||||
|
t = t / 2;
|
||||||
|
|
||||||
|
*ox = x;
|
||||||
|
*oy = y;
|
||||||
|
*ot = t;
|
||||||
|
}
|
Loading…
Reference in a new issue