More NBIS cleanups
This commit is contained in:
parent
6f633cc771
commit
f0ef386f43
16 changed files with 1063 additions and 3933 deletions
2
TODO
2
TODO
|
@ -27,3 +27,5 @@ upekts/thinkfinger relicensing (GPL --> LGPL)
|
||||||
make library optionally asynchronous and maybe thread-safe
|
make library optionally asynchronous and maybe thread-safe
|
||||||
pkg-config file
|
pkg-config file
|
||||||
nbis cleanups
|
nbis cleanups
|
||||||
|
track open devices, so we can close them during libfprint close
|
||||||
|
free memory during libfprint close
|
||||||
|
|
|
@ -3,7 +3,7 @@ AM_INIT_AUTOMAKE
|
||||||
AC_CONFIG_SRCDIR([libfprint/core.c])
|
AC_CONFIG_SRCDIR([libfprint/core.c])
|
||||||
AM_CONFIG_HEADER([config.h])
|
AM_CONFIG_HEADER([config.h])
|
||||||
|
|
||||||
AC_PREREQ([2.61])
|
AC_PREREQ([2.50])
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AC_PROG_LIBTOOL
|
AC_PROG_LIBTOOL
|
||||||
AC_C_INLINE
|
AC_C_INLINE
|
||||||
|
|
|
@ -15,18 +15,14 @@ NBIS_SRC = \
|
||||||
nbis/bozorth3/bz_sort.c \
|
nbis/bozorth3/bz_sort.c \
|
||||||
nbis/mindtct/binar.c \
|
nbis/mindtct/binar.c \
|
||||||
nbis/mindtct/block.c \
|
nbis/mindtct/block.c \
|
||||||
nbis/mindtct/chaincod.c \
|
|
||||||
nbis/mindtct/contour.c \
|
nbis/mindtct/contour.c \
|
||||||
nbis/mindtct/detect.c \
|
nbis/mindtct/detect.c \
|
||||||
nbis/mindtct/dft.c \
|
nbis/mindtct/dft.c \
|
||||||
nbis/mindtct/free.c \
|
nbis/mindtct/free.c \
|
||||||
nbis/mindtct/getmin.c \
|
|
||||||
nbis/mindtct/globals.c \
|
nbis/mindtct/globals.c \
|
||||||
nbis/mindtct/imgutil.c \
|
nbis/mindtct/imgutil.c \
|
||||||
nbis/mindtct/init.c \
|
nbis/mindtct/init.c \
|
||||||
nbis/mindtct/isempty.c \
|
|
||||||
nbis/mindtct/line.c \
|
nbis/mindtct/line.c \
|
||||||
nbis/mindtct/link.c \
|
|
||||||
nbis/mindtct/log.c \
|
nbis/mindtct/log.c \
|
||||||
nbis/mindtct/loop.c \
|
nbis/mindtct/loop.c \
|
||||||
nbis/mindtct/maps.c \
|
nbis/mindtct/maps.c \
|
||||||
|
@ -38,8 +34,7 @@ NBIS_SRC = \
|
||||||
nbis/mindtct/ridges.c \
|
nbis/mindtct/ridges.c \
|
||||||
nbis/mindtct/shape.c \
|
nbis/mindtct/shape.c \
|
||||||
nbis/mindtct/sort.c \
|
nbis/mindtct/sort.c \
|
||||||
nbis/mindtct/util.c \
|
nbis/mindtct/util.c
|
||||||
nbis/mindtct/xytreps.c
|
|
||||||
|
|
||||||
libfprint_la_CFLAGS = -fvisibility=hidden -Inbis/include $(LIBUSB_CFLAGS) $(GLIB_CFLAGS) $(AM_CFLAGS)
|
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@
|
||||||
|
|
|
@ -721,12 +721,9 @@ extern int find_valid_block(int *, int *, int *, int *, int *,
|
||||||
const int, const int);
|
const int, const int);
|
||||||
extern void set_margin_blocks(int *, const int, const int, const int);
|
extern void set_margin_blocks(int *, const int, const int, const int);
|
||||||
|
|
||||||
/* chaincod.c */
|
|
||||||
extern int chain_code_loop(int **, int *, const int *, const int *, const int);
|
|
||||||
extern int is_chain_clockwise(const int *, const int, const int);
|
|
||||||
|
|
||||||
/* contour.c */
|
/* contour.c */
|
||||||
extern int allocate_contour(int **, int **, int **, int **, const int);
|
int allocate_contour(int **ocontour_x, int **ocontour_y,
|
||||||
|
int **ocontour_ex, int **ocontour_ey, const int ncontour);
|
||||||
extern void free_contour(int *, int *, int *, int *);
|
extern void free_contour(int *, int *, int *, int *);
|
||||||
extern int get_high_curvature_contour(int **, int **, int **, int **, int *,
|
extern int get_high_curvature_contour(int **, int **, int **, int **, int *,
|
||||||
const int, const int, const int, const int, const int,
|
const int, const int, const int, const int, const int,
|
||||||
|
@ -741,11 +738,6 @@ extern int trace_contour(int **, int **, int **, int **, int *,
|
||||||
extern int search_contour(const int, const int, const int,
|
extern int search_contour(const int, const int, const int,
|
||||||
const int, const int, const int, const int, const int,
|
const int, const int, const int, const int, const int,
|
||||||
unsigned char *, const int, const int);
|
unsigned char *, const int, const int);
|
||||||
extern int next_contour_pixel(int *, int *, int *, int *,
|
|
||||||
const int, const int, const int, const int, const int,
|
|
||||||
unsigned char *, const int, const int);
|
|
||||||
extern int start_scan_nbr(const int, const int, const int, const int);
|
|
||||||
extern int next_scan_nbr(const int, const int);
|
|
||||||
extern int min_contour_theta(int *, double *, const int, const int *,
|
extern int min_contour_theta(int *, double *, const int, const int *,
|
||||||
const int *, const int);
|
const int *, const int);
|
||||||
extern void contour_limits(int *, int *, int *, int *, const int *,
|
extern void contour_limits(int *, int *, int *, int *, const int *,
|
||||||
|
@ -754,11 +746,11 @@ extern void fix_edge_pixel_pair(int *, int *, int *, int *,
|
||||||
unsigned char *, const int, const int);
|
unsigned char *, const int, const int);
|
||||||
|
|
||||||
/* detect.c */
|
/* detect.c */
|
||||||
extern int lfs_detect_minutiae_V2(MINUTIAE **,
|
extern int get_minutiae(MINUTIAE **, int **, int **, int **,
|
||||||
int **, int **, int **, int **, int *, int *,
|
int **, int **, int *, int *,
|
||||||
unsigned char **, int *, int *,
|
unsigned char **, int *, int *, int *,
|
||||||
unsigned char *, const int, const int,
|
unsigned char *, const int, const int,
|
||||||
const LFSPARMS *);
|
const int, const double, const LFSPARMS *);
|
||||||
|
|
||||||
/* dft.c */
|
/* dft.c */
|
||||||
extern int dft_dir_powers(double **, unsigned char *, const int,
|
extern int dft_dir_powers(double **, unsigned char *, const int,
|
||||||
|
@ -773,13 +765,6 @@ extern void free_dftwaves(DFTWAVES *);
|
||||||
extern void free_rotgrids(ROTGRIDS *);
|
extern void free_rotgrids(ROTGRIDS *);
|
||||||
extern void free_dir_powers(double **, const int);
|
extern void free_dir_powers(double **, const int);
|
||||||
|
|
||||||
/* getmin.c */
|
|
||||||
extern int get_minutiae(MINUTIAE **, int **, int **, int **,
|
|
||||||
int **, int **, int *, int *,
|
|
||||||
unsigned char **, int *, int *, int *,
|
|
||||||
unsigned char *, const int, const int,
|
|
||||||
const int, const double, const LFSPARMS *);
|
|
||||||
|
|
||||||
/* imgutil.c */
|
/* imgutil.c */
|
||||||
extern void bits_6to8(unsigned char *, const int, const int);
|
extern void bits_6to8(unsigned char *, const int, const int);
|
||||||
extern void bits_8to6(unsigned char *, const int, const int);
|
extern void bits_8to6(unsigned char *, const int, const int);
|
||||||
|
@ -804,33 +789,10 @@ extern int init_rotgrids(ROTGRIDS **, const int, const int, const int,
|
||||||
extern int alloc_dir_powers(double ***, const int, const int);
|
extern int alloc_dir_powers(double ***, const int, const int);
|
||||||
extern int alloc_power_stats(int **, double **, int **, double **, const int);
|
extern int alloc_power_stats(int **, double **, int **, double **, const int);
|
||||||
|
|
||||||
/* isempty.c */
|
|
||||||
extern int is_image_empty(int *, const int, const int);
|
|
||||||
extern int is_qmap_empty(int *, const int, const int);
|
|
||||||
|
|
||||||
|
|
||||||
/* line.c */
|
/* line.c */
|
||||||
extern int line_points(int **, int **, int *,
|
extern int line_points(int **, int **, int *,
|
||||||
const int, const int, const int, const int);
|
const int, const int, const int, const int);
|
||||||
|
|
||||||
/* link.c */
|
|
||||||
extern int link_minutiae(MINUTIAE *, unsigned char *, const int, const int,
|
|
||||||
int *, const int, const int, const LFSPARMS *);
|
|
||||||
extern int create_link_table(int **, int **, int **, int *, int *, int *,
|
|
||||||
const int, const int, const MINUTIAE *, const int *,
|
|
||||||
int *, const int, const int, unsigned char *,
|
|
||||||
const int, const int, const LFSPARMS *);
|
|
||||||
extern int update_link_table(int *, int *, int *, int *, int *, int *,
|
|
||||||
const int, int *, int *, int *, int *,
|
|
||||||
const int, const int, const int);
|
|
||||||
extern int order_link_table(int *, int *, int *, const int, const int,
|
|
||||||
const int, const int, const MINUTIAE *, const int);
|
|
||||||
extern int process_link_table(const int *, const int *, const int *,
|
|
||||||
const int, const int, const int, const int, MINUTIAE *,
|
|
||||||
int *, unsigned char *, const int, const int,
|
|
||||||
const LFSPARMS *);
|
|
||||||
extern double link_score(const double, const double, const LFSPARMS *);
|
|
||||||
|
|
||||||
/* loop.c */
|
/* loop.c */
|
||||||
extern int get_loop_list(int **, MINUTIAE *, const int, unsigned char *,
|
extern int get_loop_list(int **, MINUTIAE *, const int, unsigned char *,
|
||||||
const int, const int);
|
const int, const int);
|
||||||
|
@ -1022,6 +984,8 @@ extern int adjust_high_curvature_minutia_V2(int *, int *, int *,
|
||||||
int *, MINUTIAE *, const LFSPARMS *);
|
int *, MINUTIAE *, const LFSPARMS *);
|
||||||
extern int get_low_curvature_direction(const int, const int, const int,
|
extern int get_low_curvature_direction(const int, const int, const int,
|
||||||
const int);
|
const int);
|
||||||
|
void lfs2nist_minutia_XYT(int *ox, int *oy, int *ot,
|
||||||
|
const MINUTIA *minutia, const int iw, const int ih);
|
||||||
|
|
||||||
/* quality.c */
|
/* quality.c */
|
||||||
extern int gen_quality_map(int **, int *, int *, int *, int *,
|
extern int gen_quality_map(int **, int *, int *, int *, int *,
|
||||||
|
@ -1029,12 +993,6 @@ extern int gen_quality_map(int **, int *, int *, int *, int *,
|
||||||
extern int combined_minutia_quality(MINUTIAE *, int *, const int, const int,
|
extern int combined_minutia_quality(MINUTIAE *, int *, const int, const int,
|
||||||
const int, unsigned char *, const int, const int,
|
const int, unsigned char *, const int, const int,
|
||||||
const int, const double);
|
const int, const double);
|
||||||
double grayscale_reliability(MINUTIA *, unsigned char *,
|
|
||||||
const int, const int, const int);
|
|
||||||
extern void get_neighborhood_stats(double *, double *, MINUTIA *,
|
|
||||||
unsigned char *, const int, const int, const int);
|
|
||||||
extern int reliability_fr_quality_map(MINUTIAE *, int *, const int,
|
|
||||||
const int, const int, const int, const int);
|
|
||||||
|
|
||||||
/* remove.c */
|
/* remove.c */
|
||||||
extern int remove_false_minutia(MINUTIAE *,
|
extern int remove_false_minutia(MINUTIAE *,
|
||||||
|
@ -1049,23 +1007,6 @@ extern int remove_false_minutia_V2(MINUTIAE *,
|
||||||
extern int count_minutiae_ridges(MINUTIAE *,
|
extern int count_minutiae_ridges(MINUTIAE *,
|
||||||
unsigned char *, const int, const int,
|
unsigned char *, const int, const int,
|
||||||
const LFSPARMS *);
|
const LFSPARMS *);
|
||||||
extern int count_minutia_ridges(const int, MINUTIAE *,
|
|
||||||
unsigned char *, const int, const int,
|
|
||||||
const LFSPARMS *);
|
|
||||||
extern int find_neighbors(int **, int *, const int, const int, MINUTIAE *);
|
|
||||||
extern int update_nbr_dists(int *, double *, int *, const int,
|
|
||||||
const int, const int, MINUTIAE *);
|
|
||||||
extern int insert_neighbor(const int, const int, const double,
|
|
||||||
int *, double *, int *, const int);
|
|
||||||
extern int sort_neighbors(int *, const int, const int, MINUTIAE *);
|
|
||||||
extern int ridge_count(const int, const int, MINUTIAE *,
|
|
||||||
unsigned char *, const int, const int, const LFSPARMS *);
|
|
||||||
extern int find_transition(int *, const int, const int,
|
|
||||||
const int *, const int *, const int,
|
|
||||||
unsigned char *, const int, const int);
|
|
||||||
extern int validate_ridge_crossing(const int, const int,
|
|
||||||
const int *, const int *, const int,
|
|
||||||
unsigned char *, const int, const int, const int);
|
|
||||||
|
|
||||||
/* shape.c */
|
/* shape.c */
|
||||||
extern void free_shape(SHAPE *);
|
extern void free_shape(SHAPE *);
|
||||||
|
@ -1094,12 +1035,6 @@ extern int line2direction(const int, const int, const int, const int,
|
||||||
const int);
|
const int);
|
||||||
extern int closest_dir_dist(const int, const int, const int);
|
extern int closest_dir_dist(const int, const int, const int);
|
||||||
|
|
||||||
/* xytreps.c */
|
|
||||||
extern void lfs2nist_minutia_XYT(int *, int *, int *,
|
|
||||||
const MINUTIA *, const int, const int);
|
|
||||||
extern void lfs2m1_minutia_XYT(int *, int *, int *, const MINUTIA *);
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
/* EXTERNAL GLOBAL VARIABLE DEFINITIONS */
|
/* EXTERNAL GLOBAL VARIABLE DEFINITIONS */
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
|
@ -1,191 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
License:
|
|
||||||
This software was developed at the National Institute of Standards and
|
|
||||||
Technology (NIST) by employees of the Federal Government in the course
|
|
||||||
of their official duties. Pursuant to title 17 Section 105 of the
|
|
||||||
United States Code, this software is not subject to copyright protection
|
|
||||||
and is in the public domain. NIST assumes no responsibility whatsoever for
|
|
||||||
its use by other parties, and makes no guarantees, expressed or implied,
|
|
||||||
about its quality, reliability, or any other characteristic.
|
|
||||||
|
|
||||||
Disclaimer:
|
|
||||||
This software was developed to promote biometric standards and biometric
|
|
||||||
technology testing for the Federal Government in accordance with the USA
|
|
||||||
PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act.
|
|
||||||
Specific hardware and software products identified in this software were used
|
|
||||||
in order to perform the software development. In no case does such
|
|
||||||
identification imply recommendation or endorsement by the National Institute
|
|
||||||
of Standards and Technology, nor does it imply that the products and equipment
|
|
||||||
identified are necessarily the best available for the purpose.
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
LIBRARY: LFS - NIST Latent Fingerprint System
|
|
||||||
|
|
||||||
FILE: 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);
|
|
||||||
}
|
|
|
@ -591,6 +591,236 @@ int get_centered_contour(int **ocontour_x, int **ocontour_y,
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: start_scan_nbr - Takes a two pixel coordinates that are either
|
||||||
|
#cat: aligned north-to-south or east-to-west, and returns the
|
||||||
|
#cat: position the second pixel is in realtionship to the first.
|
||||||
|
#cat: The positions returned are based on 8-connectedness.
|
||||||
|
#cat: NOTE, this routine does NOT account for diagonal positions.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
x_prev - x-coord of first point
|
||||||
|
y_prev - y-coord of first point
|
||||||
|
x_next - x-coord of second point
|
||||||
|
y_next - y-coord of second point
|
||||||
|
Return Code:
|
||||||
|
NORTH - second pixel above first
|
||||||
|
SOUTH - second pixel below first
|
||||||
|
EAST - second pixel right of first
|
||||||
|
WEST - second pixel left of first
|
||||||
|
**************************************************************************/
|
||||||
|
static int start_scan_nbr(const int x_prev, const int y_prev,
|
||||||
|
const int x_next, const int y_next)
|
||||||
|
{
|
||||||
|
if((x_prev==x_next) && (y_next > y_prev))
|
||||||
|
return(SOUTH);
|
||||||
|
else if ((x_prev==x_next) && (y_next < y_prev))
|
||||||
|
return(NORTH);
|
||||||
|
else if ((x_next > x_prev) && (y_prev==y_next))
|
||||||
|
return(EAST);
|
||||||
|
else if ((x_next < x_prev) && (y_prev==y_next))
|
||||||
|
return(WEST);
|
||||||
|
|
||||||
|
/* Added by MDG on 03-16-05 */
|
||||||
|
/* Should never reach here. Added to remove compiler warning. */
|
||||||
|
return(INVALID_DIR); /* -1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: next_scan_nbr - Advances the given 8-connected neighbor index
|
||||||
|
#cat: on location in the specifiec direction (clockwise or
|
||||||
|
#cat: counter-clockwise).
|
||||||
|
|
||||||
|
Input:
|
||||||
|
nbr_i - current 8-connected neighbor index
|
||||||
|
scan_clock - direction in which the neighbor index is to be advanced
|
||||||
|
Return Code:
|
||||||
|
Next neighbor - 8-connected index of next neighbor
|
||||||
|
**************************************************************************/
|
||||||
|
static int next_scan_nbr(const int nbr_i, const int scan_clock)
|
||||||
|
{
|
||||||
|
int new_i;
|
||||||
|
|
||||||
|
/* If scanning neighbors clockwise ... */
|
||||||
|
if(scan_clock == SCAN_CLOCKWISE)
|
||||||
|
/* Advance one neighbor clockwise. */
|
||||||
|
new_i = (nbr_i+1)%8;
|
||||||
|
/* Otherwise, scanning neighbors counter-clockwise ... */
|
||||||
|
else
|
||||||
|
/* Advance one neighbor counter-clockwise. */
|
||||||
|
/* There are 8 pixels in the neighborhood, so to */
|
||||||
|
/* decrement with wrapping from 0 around to 7, add */
|
||||||
|
/* the nieghbor index by 7 and mod with 8. */
|
||||||
|
new_i = (nbr_i+7)%8;
|
||||||
|
|
||||||
|
/* Return the new neighbor index. */
|
||||||
|
return(new_i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: next_contour_pixel - Takes a pixel coordinate of a point determined
|
||||||
|
#cat: to be on the interior edge of a feature (ridge or valley-
|
||||||
|
#cat: ending), and attempts to locate a neighboring pixel on the
|
||||||
|
#cat: feature's contour. Neighbors of the current feature pixel
|
||||||
|
#cat: are searched in a specified direction (clockwise or counter-
|
||||||
|
#cat: clockwise) and the first pair of adjacent/neigboring pixels
|
||||||
|
#cat: found with the first pixel having the color of the feature
|
||||||
|
#cat: and the second the opposite color are returned as the next
|
||||||
|
#cat: point on the contour. One exception happens when the new
|
||||||
|
#cat: point is on an "exposed" corner.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
cur_x_loc - x-pixel coord of current point on feature's
|
||||||
|
interior contour
|
||||||
|
cur_y_loc - y-pixel coord of current point on feature's
|
||||||
|
interior contour
|
||||||
|
cur_x_edge - x-pixel coord of corresponding edge pixel
|
||||||
|
(exterior to feature)
|
||||||
|
cur_y_edge - y-pixel coord of corresponding edge pixel
|
||||||
|
(exterior to feature)
|
||||||
|
scan_clock - direction in which neighboring pixels are to be scanned
|
||||||
|
for the next contour pixel
|
||||||
|
bdata - binary image data (0==while & 1==black)
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
ih - height (in pixels) of image
|
||||||
|
Output:
|
||||||
|
next_x_loc - x-pixel coord of next point on feature's interior contour
|
||||||
|
next_y_loc - y-pixel coord of next point on feature's interior contour
|
||||||
|
next_x_edge - x-pixel coord of corresponding edge (exterior to feature)
|
||||||
|
next_y_edge - y-pixel coord of corresponding edge (exterior to feature)
|
||||||
|
Return Code:
|
||||||
|
TRUE - next contour point found and returned
|
||||||
|
FALSE - next contour point NOT found
|
||||||
|
**************************************************************************/
|
||||||
|
/*************************************************************************/
|
||||||
|
static int next_contour_pixel(int *next_x_loc, int *next_y_loc,
|
||||||
|
int *next_x_edge, int *next_y_edge,
|
||||||
|
const int cur_x_loc, const int cur_y_loc,
|
||||||
|
const int cur_x_edge, const int cur_y_edge,
|
||||||
|
const int scan_clock,
|
||||||
|
unsigned char *bdata, const int iw, const int ih)
|
||||||
|
{
|
||||||
|
int feature_pix, edge_pix;
|
||||||
|
int prev_nbr_pix, prev_nbr_x, prev_nbr_y;
|
||||||
|
int cur_nbr_pix, cur_nbr_x, cur_nbr_y;
|
||||||
|
int ni, nx, ny, npix;
|
||||||
|
int nbr_i, i;
|
||||||
|
|
||||||
|
/* Get the feature's pixel value. */
|
||||||
|
feature_pix = *(bdata + (cur_y_loc * iw) + cur_x_loc);
|
||||||
|
/* Get the feature's edge pixel value. */
|
||||||
|
edge_pix = *(bdata + (cur_y_edge * iw) + cur_x_edge);
|
||||||
|
|
||||||
|
/* Get the nieghbor position of the feature's edge pixel in relationship */
|
||||||
|
/* to the feature's actual position. */
|
||||||
|
/* REMEBER: The feature's position is always interior and on a ridge */
|
||||||
|
/* ending (black pixel) or (for bifurcations) on a valley ending (white */
|
||||||
|
/* pixel). The feature's edge pixel is an adjacent pixel to the feature */
|
||||||
|
/* pixel that is exterior to the ridge or valley ending and opposite in */
|
||||||
|
/* pixel value. */
|
||||||
|
nbr_i = start_scan_nbr(cur_x_loc, cur_y_loc, cur_x_edge, cur_y_edge);
|
||||||
|
|
||||||
|
/* Set current neighbor scan pixel to the feature's edge pixel. */
|
||||||
|
cur_nbr_x = cur_x_edge;
|
||||||
|
cur_nbr_y = cur_y_edge;
|
||||||
|
cur_nbr_pix = edge_pix;
|
||||||
|
|
||||||
|
/* Foreach pixel neighboring the feature pixel ... */
|
||||||
|
for(i = 0; i < 8; i++){
|
||||||
|
|
||||||
|
/* Set current neighbor scan pixel to previous scan pixel. */
|
||||||
|
prev_nbr_x = cur_nbr_x;
|
||||||
|
prev_nbr_y = cur_nbr_y;
|
||||||
|
prev_nbr_pix = cur_nbr_pix;
|
||||||
|
|
||||||
|
/* Bump pixel neighbor index clockwise or counter-clockwise. */
|
||||||
|
nbr_i = next_scan_nbr(nbr_i, scan_clock);
|
||||||
|
|
||||||
|
/* Set current scan pixel to the new neighbor. */
|
||||||
|
/* REMEMBER: the neighbors are being scanned around the original */
|
||||||
|
/* feature point. */
|
||||||
|
cur_nbr_x = cur_x_loc + nbr8_dx[nbr_i];
|
||||||
|
cur_nbr_y = cur_y_loc + nbr8_dy[nbr_i];
|
||||||
|
|
||||||
|
/* If new neighbor is not within image boundaries... */
|
||||||
|
if((cur_nbr_x < 0) || (cur_nbr_x >= iw) ||
|
||||||
|
(cur_nbr_y < 0) || (cur_nbr_y >= ih))
|
||||||
|
/* Return (FALSE==>Failure) if neighbor out of bounds. */
|
||||||
|
return(FALSE);
|
||||||
|
|
||||||
|
/* Get the new neighbor's pixel value. */
|
||||||
|
cur_nbr_pix = *(bdata + (cur_nbr_y * iw) + cur_nbr_x);
|
||||||
|
|
||||||
|
/* If the new neighbor's pixel value is the same as the feature's */
|
||||||
|
/* pixel value AND the previous neighbor's pixel value is the same */
|
||||||
|
/* as the features's edge, then we have "likely" found our next */
|
||||||
|
/* contour pixel. */
|
||||||
|
if((cur_nbr_pix == feature_pix) && (prev_nbr_pix == edge_pix)){
|
||||||
|
|
||||||
|
/* Check to see if current neighbor is on the corner of the */
|
||||||
|
/* neighborhood, and if so, test to see if it is "exposed". */
|
||||||
|
/* The neighborhood corners have odd neighbor indicies. */
|
||||||
|
if(nbr_i % 2){
|
||||||
|
/* To do this, look ahead one more neighbor pixel. */
|
||||||
|
ni = next_scan_nbr(nbr_i, scan_clock);
|
||||||
|
nx = cur_x_loc + nbr8_dx[ni];
|
||||||
|
ny = cur_y_loc + nbr8_dy[ni];
|
||||||
|
/* If new neighbor is not within image boundaries... */
|
||||||
|
if((nx < 0) || (nx >= iw) ||
|
||||||
|
(ny < 0) || (ny >= ih))
|
||||||
|
/* Return (FALSE==>Failure) if neighbor out of bounds. */
|
||||||
|
return(FALSE);
|
||||||
|
npix = *(bdata + (ny * iw) + nx);
|
||||||
|
|
||||||
|
/* If the next neighbor's value is also the same as the */
|
||||||
|
/* feature's pixel, then corner is NOT exposed... */
|
||||||
|
if(npix == feature_pix){
|
||||||
|
/* Assign the current neighbor pair to the output pointers. */
|
||||||
|
*next_x_loc = cur_nbr_x;
|
||||||
|
*next_y_loc = cur_nbr_y;
|
||||||
|
*next_x_edge = prev_nbr_x;
|
||||||
|
*next_y_edge = prev_nbr_y;
|
||||||
|
/* Return TRUE==>Success. */
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
/* Otherwise, corner pixel is "exposed" so skip it. */
|
||||||
|
else{
|
||||||
|
/* Skip current corner neighbor by resetting it to the */
|
||||||
|
/* next neighbor, which upon the iteration will immediately */
|
||||||
|
/* become the previous neighbor. */
|
||||||
|
cur_nbr_x = nx;
|
||||||
|
cur_nbr_y = ny;
|
||||||
|
cur_nbr_pix = npix;
|
||||||
|
/* Advance neighbor index. */
|
||||||
|
nbr_i = ni;
|
||||||
|
/* Advance neighbor count. */
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Otherwise, current neighbor is not a corner ... */
|
||||||
|
else{
|
||||||
|
/* Assign the current neighbor pair to the output pointers. */
|
||||||
|
*next_x_loc = cur_nbr_x;
|
||||||
|
*next_y_loc = cur_nbr_y;
|
||||||
|
*next_x_edge = prev_nbr_x;
|
||||||
|
*next_y_edge = prev_nbr_y;
|
||||||
|
/* Return TRUE==>Success. */
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get here, then we did not find the next contour pixel */
|
||||||
|
/* within the 8 neighbors of the current feature pixel so */
|
||||||
|
/* return (FALSE==>Failure). */
|
||||||
|
/* NOTE: This must mean we found a single isolated pixel. */
|
||||||
|
/* Perhaps this should be filled? */
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
#cat: trace_contour - Takes the pixel coordinate of a detected minutia
|
#cat: trace_contour - Takes the pixel coordinate of a detected minutia
|
||||||
|
@ -816,236 +1046,6 @@ int search_contour(const int x_search, const int y_search,
|
||||||
return(NOT_FOUND);
|
return(NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
#cat: next_contour_pixel - Takes a pixel coordinate of a point determined
|
|
||||||
#cat: to be on the interior edge of a feature (ridge or valley-
|
|
||||||
#cat: ending), and attempts to locate a neighboring pixel on the
|
|
||||||
#cat: feature's contour. Neighbors of the current feature pixel
|
|
||||||
#cat: are searched in a specified direction (clockwise or counter-
|
|
||||||
#cat: clockwise) and the first pair of adjacent/neigboring pixels
|
|
||||||
#cat: found with the first pixel having the color of the feature
|
|
||||||
#cat: and the second the opposite color are returned as the next
|
|
||||||
#cat: point on the contour. One exception happens when the new
|
|
||||||
#cat: point is on an "exposed" corner.
|
|
||||||
|
|
||||||
Input:
|
|
||||||
cur_x_loc - x-pixel coord of current point on feature's
|
|
||||||
interior contour
|
|
||||||
cur_y_loc - y-pixel coord of current point on feature's
|
|
||||||
interior contour
|
|
||||||
cur_x_edge - x-pixel coord of corresponding edge pixel
|
|
||||||
(exterior to feature)
|
|
||||||
cur_y_edge - y-pixel coord of corresponding edge pixel
|
|
||||||
(exterior to feature)
|
|
||||||
scan_clock - direction in which neighboring pixels are to be scanned
|
|
||||||
for the next contour pixel
|
|
||||||
bdata - binary image data (0==while & 1==black)
|
|
||||||
iw - width (in pixels) of image
|
|
||||||
ih - height (in pixels) of image
|
|
||||||
Output:
|
|
||||||
next_x_loc - x-pixel coord of next point on feature's interior contour
|
|
||||||
next_y_loc - y-pixel coord of next point on feature's interior contour
|
|
||||||
next_x_edge - x-pixel coord of corresponding edge (exterior to feature)
|
|
||||||
next_y_edge - y-pixel coord of corresponding edge (exterior to feature)
|
|
||||||
Return Code:
|
|
||||||
TRUE - next contour point found and returned
|
|
||||||
FALSE - next contour point NOT found
|
|
||||||
**************************************************************************/
|
|
||||||
/*************************************************************************/
|
|
||||||
int next_contour_pixel(int *next_x_loc, int *next_y_loc,
|
|
||||||
int *next_x_edge, int *next_y_edge,
|
|
||||||
const int cur_x_loc, const int cur_y_loc,
|
|
||||||
const int cur_x_edge, const int cur_y_edge,
|
|
||||||
const int scan_clock,
|
|
||||||
unsigned char *bdata, const int iw, const int ih)
|
|
||||||
{
|
|
||||||
int feature_pix, edge_pix;
|
|
||||||
int prev_nbr_pix, prev_nbr_x, prev_nbr_y;
|
|
||||||
int cur_nbr_pix, cur_nbr_x, cur_nbr_y;
|
|
||||||
int ni, nx, ny, npix;
|
|
||||||
int nbr_i, i;
|
|
||||||
|
|
||||||
/* Get the feature's pixel value. */
|
|
||||||
feature_pix = *(bdata + (cur_y_loc * iw) + cur_x_loc);
|
|
||||||
/* Get the feature's edge pixel value. */
|
|
||||||
edge_pix = *(bdata + (cur_y_edge * iw) + cur_x_edge);
|
|
||||||
|
|
||||||
/* Get the nieghbor position of the feature's edge pixel in relationship */
|
|
||||||
/* to the feature's actual position. */
|
|
||||||
/* REMEBER: The feature's position is always interior and on a ridge */
|
|
||||||
/* ending (black pixel) or (for bifurcations) on a valley ending (white */
|
|
||||||
/* pixel). The feature's edge pixel is an adjacent pixel to the feature */
|
|
||||||
/* pixel that is exterior to the ridge or valley ending and opposite in */
|
|
||||||
/* pixel value. */
|
|
||||||
nbr_i = start_scan_nbr(cur_x_loc, cur_y_loc, cur_x_edge, cur_y_edge);
|
|
||||||
|
|
||||||
/* Set current neighbor scan pixel to the feature's edge pixel. */
|
|
||||||
cur_nbr_x = cur_x_edge;
|
|
||||||
cur_nbr_y = cur_y_edge;
|
|
||||||
cur_nbr_pix = edge_pix;
|
|
||||||
|
|
||||||
/* Foreach pixel neighboring the feature pixel ... */
|
|
||||||
for(i = 0; i < 8; i++){
|
|
||||||
|
|
||||||
/* Set current neighbor scan pixel to previous scan pixel. */
|
|
||||||
prev_nbr_x = cur_nbr_x;
|
|
||||||
prev_nbr_y = cur_nbr_y;
|
|
||||||
prev_nbr_pix = cur_nbr_pix;
|
|
||||||
|
|
||||||
/* Bump pixel neighbor index clockwise or counter-clockwise. */
|
|
||||||
nbr_i = next_scan_nbr(nbr_i, scan_clock);
|
|
||||||
|
|
||||||
/* Set current scan pixel to the new neighbor. */
|
|
||||||
/* REMEMBER: the neighbors are being scanned around the original */
|
|
||||||
/* feature point. */
|
|
||||||
cur_nbr_x = cur_x_loc + nbr8_dx[nbr_i];
|
|
||||||
cur_nbr_y = cur_y_loc + nbr8_dy[nbr_i];
|
|
||||||
|
|
||||||
/* If new neighbor is not within image boundaries... */
|
|
||||||
if((cur_nbr_x < 0) || (cur_nbr_x >= iw) ||
|
|
||||||
(cur_nbr_y < 0) || (cur_nbr_y >= ih))
|
|
||||||
/* Return (FALSE==>Failure) if neighbor out of bounds. */
|
|
||||||
return(FALSE);
|
|
||||||
|
|
||||||
/* Get the new neighbor's pixel value. */
|
|
||||||
cur_nbr_pix = *(bdata + (cur_nbr_y * iw) + cur_nbr_x);
|
|
||||||
|
|
||||||
/* If the new neighbor's pixel value is the same as the feature's */
|
|
||||||
/* pixel value AND the previous neighbor's pixel value is the same */
|
|
||||||
/* as the features's edge, then we have "likely" found our next */
|
|
||||||
/* contour pixel. */
|
|
||||||
if((cur_nbr_pix == feature_pix) && (prev_nbr_pix == edge_pix)){
|
|
||||||
|
|
||||||
/* Check to see if current neighbor is on the corner of the */
|
|
||||||
/* neighborhood, and if so, test to see if it is "exposed". */
|
|
||||||
/* The neighborhood corners have odd neighbor indicies. */
|
|
||||||
if(nbr_i % 2){
|
|
||||||
/* To do this, look ahead one more neighbor pixel. */
|
|
||||||
ni = next_scan_nbr(nbr_i, scan_clock);
|
|
||||||
nx = cur_x_loc + nbr8_dx[ni];
|
|
||||||
ny = cur_y_loc + nbr8_dy[ni];
|
|
||||||
/* If new neighbor is not within image boundaries... */
|
|
||||||
if((nx < 0) || (nx >= iw) ||
|
|
||||||
(ny < 0) || (ny >= ih))
|
|
||||||
/* Return (FALSE==>Failure) if neighbor out of bounds. */
|
|
||||||
return(FALSE);
|
|
||||||
npix = *(bdata + (ny * iw) + nx);
|
|
||||||
|
|
||||||
/* If the next neighbor's value is also the same as the */
|
|
||||||
/* feature's pixel, then corner is NOT exposed... */
|
|
||||||
if(npix == feature_pix){
|
|
||||||
/* Assign the current neighbor pair to the output pointers. */
|
|
||||||
*next_x_loc = cur_nbr_x;
|
|
||||||
*next_y_loc = cur_nbr_y;
|
|
||||||
*next_x_edge = prev_nbr_x;
|
|
||||||
*next_y_edge = prev_nbr_y;
|
|
||||||
/* Return TRUE==>Success. */
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
/* Otherwise, corner pixel is "exposed" so skip it. */
|
|
||||||
else{
|
|
||||||
/* Skip current corner neighbor by resetting it to the */
|
|
||||||
/* next neighbor, which upon the iteration will immediately */
|
|
||||||
/* become the previous neighbor. */
|
|
||||||
cur_nbr_x = nx;
|
|
||||||
cur_nbr_y = ny;
|
|
||||||
cur_nbr_pix = npix;
|
|
||||||
/* Advance neighbor index. */
|
|
||||||
nbr_i = ni;
|
|
||||||
/* Advance neighbor count. */
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Otherwise, current neighbor is not a corner ... */
|
|
||||||
else{
|
|
||||||
/* Assign the current neighbor pair to the output pointers. */
|
|
||||||
*next_x_loc = cur_nbr_x;
|
|
||||||
*next_y_loc = cur_nbr_y;
|
|
||||||
*next_x_edge = prev_nbr_x;
|
|
||||||
*next_y_edge = prev_nbr_y;
|
|
||||||
/* Return TRUE==>Success. */
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we get here, then we did not find the next contour pixel */
|
|
||||||
/* within the 8 neighbors of the current feature pixel so */
|
|
||||||
/* return (FALSE==>Failure). */
|
|
||||||
/* NOTE: This must mean we found a single isolated pixel. */
|
|
||||||
/* Perhaps this should be filled? */
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
#cat: start_scan_nbr - Takes a two pixel coordinates that are either
|
|
||||||
#cat: aligned north-to-south or east-to-west, and returns the
|
|
||||||
#cat: position the second pixel is in realtionship to the first.
|
|
||||||
#cat: The positions returned are based on 8-connectedness.
|
|
||||||
#cat: NOTE, this routine does NOT account for diagonal positions.
|
|
||||||
|
|
||||||
Input:
|
|
||||||
x_prev - x-coord of first point
|
|
||||||
y_prev - y-coord of first point
|
|
||||||
x_next - x-coord of second point
|
|
||||||
y_next - y-coord of second point
|
|
||||||
Return Code:
|
|
||||||
NORTH - second pixel above first
|
|
||||||
SOUTH - second pixel below first
|
|
||||||
EAST - second pixel right of first
|
|
||||||
WEST - second pixel left of first
|
|
||||||
**************************************************************************/
|
|
||||||
int start_scan_nbr(const int x_prev, const int y_prev,
|
|
||||||
const int x_next, const int y_next)
|
|
||||||
{
|
|
||||||
if((x_prev==x_next) && (y_next > y_prev))
|
|
||||||
return(SOUTH);
|
|
||||||
else if ((x_prev==x_next) && (y_next < y_prev))
|
|
||||||
return(NORTH);
|
|
||||||
else if ((x_next > x_prev) && (y_prev==y_next))
|
|
||||||
return(EAST);
|
|
||||||
else if ((x_next < x_prev) && (y_prev==y_next))
|
|
||||||
return(WEST);
|
|
||||||
|
|
||||||
/* Added by MDG on 03-16-05 */
|
|
||||||
/* Should never reach here. Added to remove compiler warning. */
|
|
||||||
return(INVALID_DIR); /* -1 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
#cat: next_scan_nbr - Advances the given 8-connected neighbor index
|
|
||||||
#cat: on location in the specifiec direction (clockwise or
|
|
||||||
#cat: counter-clockwise).
|
|
||||||
|
|
||||||
Input:
|
|
||||||
nbr_i - current 8-connected neighbor index
|
|
||||||
scan_clock - direction in which the neighbor index is to be advanced
|
|
||||||
Return Code:
|
|
||||||
Next neighbor - 8-connected index of next neighbor
|
|
||||||
**************************************************************************/
|
|
||||||
int next_scan_nbr(const int nbr_i, const int scan_clock)
|
|
||||||
{
|
|
||||||
int new_i;
|
|
||||||
|
|
||||||
/* If scanning neighbors clockwise ... */
|
|
||||||
if(scan_clock == SCAN_CLOCKWISE)
|
|
||||||
/* Advance one neighbor clockwise. */
|
|
||||||
new_i = (nbr_i+1)%8;
|
|
||||||
/* Otherwise, scanning neighbors counter-clockwise ... */
|
|
||||||
else
|
|
||||||
/* Advance one neighbor counter-clockwise. */
|
|
||||||
/* There are 8 pixels in the neighborhood, so to */
|
|
||||||
/* decrement with wrapping from 0 around to 7, add */
|
|
||||||
/* the nieghbor index by 7 and mod with 8. */
|
|
||||||
new_i = (nbr_i+7)%8;
|
|
||||||
|
|
||||||
/* Return the new neighbor index. */
|
|
||||||
return(new_i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
#cat: min_contour_theta - Takes a contour list and analyzes it locating the
|
#cat: min_contour_theta - Takes a contour list and analyzes it locating the
|
||||||
|
|
|
@ -36,6 +36,7 @@ identified are necessarily the best available for the purpose.
|
||||||
***********************************************************************
|
***********************************************************************
|
||||||
ROUTINES:
|
ROUTINES:
|
||||||
lfs_detect_minutiae_V2()
|
lfs_detect_minutiae_V2()
|
||||||
|
get_minutiae()
|
||||||
|
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
||||||
|
@ -80,7 +81,7 @@ identified are necessarily the best available for the purpose.
|
||||||
Zero - successful completion
|
Zero - successful completion
|
||||||
Negative - system error
|
Negative - system error
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
|
static int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
|
||||||
int **odmap, int **olcmap, int **olfmap, int **ohcmap,
|
int **odmap, int **olcmap, int **olfmap, int **ohcmap,
|
||||||
int *omw, int *omh,
|
int *omw, int *omh,
|
||||||
unsigned char **obdata, int *obw, int *obh,
|
unsigned char **obdata, int *obw, int *obh,
|
||||||
|
@ -343,3 +344,112 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae,
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
|
@ -1,155 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
License:
|
|
||||||
This software was developed at the National Institute of Standards and
|
|
||||||
Technology (NIST) by employees of the Federal Government in the course
|
|
||||||
of their official duties. Pursuant to title 17 Section 105 of the
|
|
||||||
United States Code, this software is not subject to copyright protection
|
|
||||||
and is in the public domain. NIST assumes no responsibility whatsoever for
|
|
||||||
its use by other parties, and makes no guarantees, expressed or implied,
|
|
||||||
about its quality, reliability, or any other characteristic.
|
|
||||||
|
|
||||||
Disclaimer:
|
|
||||||
This software was developed to promote biometric standards and biometric
|
|
||||||
technology testing for the Federal Government in accordance with the USA
|
|
||||||
PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act.
|
|
||||||
Specific hardware and software products identified in this software were used
|
|
||||||
in order to perform the software development. In no case does such
|
|
||||||
identification imply recommendation or endorsement by the National Institute
|
|
||||||
of Standards and Technology, nor does it imply that the products and equipment
|
|
||||||
identified are necessarily the best available for the purpose.
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
LIBRARY: LFS - NIST Latent Fingerprint System
|
|
||||||
|
|
||||||
FILE: 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);
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
License:
|
|
||||||
This software was developed at the National Institute of Standards and
|
|
||||||
Technology (NIST) by employees of the Federal Government in the course
|
|
||||||
of their official duties. Pursuant to title 17 Section 105 of the
|
|
||||||
United States Code, this software is not subject to copyright protection
|
|
||||||
and is in the public domain. NIST assumes no responsibility whatsoever for
|
|
||||||
its use by other parties, and makes no guarantees, expressed or implied,
|
|
||||||
about its quality, reliability, or any other characteristic.
|
|
||||||
|
|
||||||
Disclaimer:
|
|
||||||
This software was developed to promote biometric standards and biometric
|
|
||||||
technology testing for the Federal Government in accordance with the USA
|
|
||||||
PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act.
|
|
||||||
Specific hardware and software products identified in this software were used
|
|
||||||
in order to perform the software development. In no case does such
|
|
||||||
identification imply recommendation or endorsement by the National Institute
|
|
||||||
of Standards and Technology, nor does it imply that the products and equipment
|
|
||||||
identified are necessarily the best available for the purpose.
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
/************************************************************************/
|
|
||||||
/***********************************************************************
|
|
||||||
LIBRARY: LFS - NIST Latent Fingerprint System
|
|
||||||
|
|
||||||
FILE: 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);
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -36,6 +36,8 @@ identified are necessarily the best available for the purpose.
|
||||||
|
|
||||||
***********************************************************************
|
***********************************************************************
|
||||||
ROUTINES:
|
ROUTINES:
|
||||||
|
chain_code_loop()
|
||||||
|
is_chain_clockwise()
|
||||||
get_loop_list()
|
get_loop_list()
|
||||||
on_loop()
|
on_loop()
|
||||||
on_island_lake()
|
on_island_lake()
|
||||||
|
@ -52,6 +54,155 @@ identified are necessarily the best available for the purpose.
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <lfs.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
|
||||||
|
**************************************************************************/
|
||||||
|
static 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
|
||||||
|
**************************************************************************/
|
||||||
|
static 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);
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
#cat: get_loop_list - Takes a list of minutia points and determines which
|
#cat: get_loop_list - Takes a list of minutia points and determines which
|
||||||
|
|
|
@ -73,6 +73,7 @@ identified are necessarily the best available for the purpose.
|
||||||
adjust_high_curvature_minutia()
|
adjust_high_curvature_minutia()
|
||||||
adjust_high_curvature_minutia_V2()
|
adjust_high_curvature_minutia_V2()
|
||||||
get_low_curvature_direction()
|
get_low_curvature_direction()
|
||||||
|
lfs2nist_minutia_XYT()
|
||||||
|
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
||||||
|
@ -80,6 +81,8 @@ identified are necessarily the best available for the purpose.
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <lfs.h>
|
#include <lfs.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
#cat: alloc_minutiae - Allocates and initializes a minutia list based on the
|
#cat: alloc_minutiae - Allocates and initializes a minutia list based on the
|
||||||
|
@ -3461,3 +3464,48 @@ int get_low_curvature_direction(const int scan_dir, const int appearing,
|
||||||
return(idir);
|
return(idir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,6 @@ identified are necessarily the best available for the purpose.
|
||||||
combined_minutia_quality()
|
combined_minutia_quality()
|
||||||
grayscale_reliability()
|
grayscale_reliability()
|
||||||
get_neighborhood_stats()
|
get_neighborhood_stats()
|
||||||
reliability_fr_quality_map()
|
|
||||||
|
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
||||||
|
@ -173,6 +172,120 @@ int gen_quality_map(int **oqmap, int *direction_map, int *low_contrast_map,
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
************************************************************************
|
||||||
|
#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
|
||||||
|
************************************************************************/
|
||||||
|
static 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: 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
|
||||||
|
************************************************************************/
|
||||||
|
static 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: combined_minutia_quality - Combines quality measures derived from
|
#cat: combined_minutia_quality - Combines quality measures derived from
|
||||||
|
@ -277,191 +390,4 @@ int combined_minutia_quality(MINUTIAE *minutiae,
|
||||||
/* Return normally. */
|
/* Return normally. */
|
||||||
return(0);
|
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);
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -52,135 +52,156 @@ identified are necessarily the best available for the purpose.
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
#cat: count_minutiae_ridges - Takes a list of minutiae, and for each one,
|
#cat: insert_neighbor - Takes a minutia index and its squared distance to a
|
||||||
#cat: determines its closest neighbors and counts the number
|
#cat: primary minutia point, and inserts them in the specified
|
||||||
#cat: of interveining ridges between the minutia point and
|
#cat: position of their respective lists, shifting previously
|
||||||
#cat: each of its neighbors.
|
#cat: stored values down and off the lists as necessary.
|
||||||
|
|
||||||
Input:
|
Input:
|
||||||
minutiae - list of minutiae
|
pos - postions where values are to be inserted in lists
|
||||||
bdata - binary image data (0==while & 1==black)
|
nbr_index - index of minutia being inserted
|
||||||
iw - width (in pixels) of image
|
nbr_dist2 - squared distance of minutia to its primary point
|
||||||
ih - height (in pixels) of image
|
nbr_list - current list of nearest neighbor minutia indices
|
||||||
lfsparms - parameters and thresholds for controlling LFS
|
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:
|
Output:
|
||||||
minutiae - list of minutiae augmented with neighbors and ridge counts
|
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:
|
Return Code:
|
||||||
Zero - successful completion
|
Zero - successful completion
|
||||||
Negative - system error
|
Negative - system error
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
int count_minutiae_ridges(MINUTIAE *minutiae,
|
static int insert_neighbor(const int pos, const int nbr_index, const double nbr_dist2,
|
||||||
unsigned char *bdata, const int iw, const int ih,
|
int *nbr_list, double *nbr_sqr_dists,
|
||||||
const LFSPARMS *lfsparms)
|
int *nnbrs, const int max_nbrs)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
print2log("\nFINDING NBRS AND COUNTING RIDGES:\n");
|
/* If the desired insertion position is beyond one passed the last */
|
||||||
|
/* neighbor in the lists OR greater than equal to the maximum ... */
|
||||||
/* Sort minutia points on x then y (column-oriented). */
|
/* NOTE: pos is zero-oriented while nnbrs and max_nbrs are 1-oriented. */
|
||||||
if((ret = sort_minutiae_x_y(minutiae, iw, ih))){
|
if((pos > *nnbrs) ||
|
||||||
return(ret);
|
(pos >= max_nbrs)){
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR : insert_neighbor : insertion point exceeds lists\n");
|
||||||
|
return(-480);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove any duplicate minutia points from the list. */
|
/* If the neighbor lists are NOT full ... */
|
||||||
if((ret = rm_dup_minutiae(minutiae))){
|
if(*nnbrs < max_nbrs){
|
||||||
return(ret);
|
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Foreach remaining sorted minutia in list ... */
|
/* While we havn't reached the desired insertion point ... */
|
||||||
for(i = 0; i < minutiae->num-1; i++){
|
while(i >= pos){
|
||||||
/* Located neighbors and count number of ridges in between. */
|
/* Shift the current neighbor down the list 1 positon. */
|
||||||
/* NOTE: neighbor and ridge count results are stored in */
|
nbr_list[i+1] = nbr_list[i];
|
||||||
/* minutiae->list[i]. */
|
nbr_sqr_dists[i+1] = nbr_sqr_dists[i];
|
||||||
if((ret = count_minutia_ridges(i, minutiae, bdata, iw, ih, lfsparms))){
|
i--;
|
||||||
return(ret);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 normally. */
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
#cat: count_minutia_ridges - Takes a minutia, and determines its closest
|
#cat: update_nbr_dists - Takes the current list of neighbors along with a
|
||||||
#cat: neighbors and counts the number of interveining ridges
|
#cat: primary minutia and a potential new neighbor, and
|
||||||
#cat: between the minutia point and each of its neighbors.
|
#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:
|
Input:
|
||||||
minutia - input minutia
|
nbr_list - current list of nearest neighbor minutia indices
|
||||||
bdata - binary image data (0==while & 1==black)
|
nbr_sqr_dists - corresponding squared euclidean distance of each
|
||||||
iw - width (in pixels) of image
|
neighbor to the primary minutia point
|
||||||
ih - height (in pixels) of image
|
nnbrs - number of neighbors currently in the list
|
||||||
lfsparms - parameters and thresholds for controlling LFS
|
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:
|
Output:
|
||||||
minutiae - minutia augmented with neighbors and ridge counts
|
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:
|
Return Code:
|
||||||
Zero - successful completion
|
Zero - successful completion
|
||||||
Negative - system error
|
Negative - system error
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
int count_minutia_ridges(const int first, MINUTIAE *minutiae,
|
static int update_nbr_dists(int *nbr_list, double *nbr_sqr_dists,
|
||||||
unsigned char *bdata, const int iw, const int ih,
|
int *nnbrs, const int max_nbrs,
|
||||||
const LFSPARMS *lfsparms)
|
const int first, const int second, MINUTIAE *minutiae)
|
||||||
{
|
{
|
||||||
int i, ret, *nbr_list, *nbr_nridges, nnbrs;
|
double dist2;
|
||||||
|
MINUTIA *minutia1, *minutia2;
|
||||||
|
int pos, last_nbr;
|
||||||
|
|
||||||
/* Find up to the maximum number of qualifying neighbors. */
|
/* Compute position of maximum last neighbor stored. */
|
||||||
if((ret = find_neighbors(&nbr_list, &nnbrs, lfsparms->max_nbrs,
|
last_nbr = max_nbrs - 1;
|
||||||
first, minutiae))){
|
|
||||||
free(nbr_list);
|
|
||||||
return(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
print2log("NBRS FOUND: %d,%d = %d\n", minutiae->list[first]->x,
|
/* Assigne temporary minutia pointers. */
|
||||||
minutiae->list[first]->y, nnbrs);
|
minutia1 = minutiae->list[first];
|
||||||
|
minutia2 = minutiae->list[second];
|
||||||
|
|
||||||
/* If no neighors found ... */
|
/* Compute squared euclidean distance between minutia pair. */
|
||||||
if(nnbrs == 0){
|
dist2 = squared_distance(minutia1->x, minutia1->y,
|
||||||
/* Then no list returned and no ridges to count. */
|
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);
|
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);
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
|
@ -203,7 +224,7 @@ int count_minutia_ridges(const int first, MINUTIAE *minutiae,
|
||||||
Zero - successful completion
|
Zero - successful completion
|
||||||
Negative - system error
|
Negative - system error
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs,
|
static int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs,
|
||||||
const int first, MINUTIAE *minutiae)
|
const int first, MINUTIAE *minutiae)
|
||||||
{
|
{
|
||||||
int ret, second, last_nbr;
|
int ret, second, last_nbr;
|
||||||
|
@ -291,160 +312,6 @@ int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs,
|
||||||
return(0);
|
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: sort_neighbors - Takes a list of primary minutia and its neighboring
|
||||||
|
@ -464,7 +331,7 @@ int insert_neighbor(const int pos, const int nbr_index, const double nbr_dist2,
|
||||||
Zero - successful completion
|
Zero - successful completion
|
||||||
Negative - system error
|
Negative - system error
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
int sort_neighbors(int *nbr_list, const int nnbrs, const int first,
|
static int sort_neighbors(int *nbr_list, const int nnbrs, const int first,
|
||||||
MINUTIAE *minutiae)
|
MINUTIAE *minutiae)
|
||||||
{
|
{
|
||||||
double *join_thetas, theta;
|
double *join_thetas, theta;
|
||||||
|
@ -505,6 +372,174 @@ int sort_neighbors(int *nbr_list, const int nnbrs, const int first,
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#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
|
||||||
|
**************************************************************************/
|
||||||
|
static 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
|
||||||
|
**************************************************************************/
|
||||||
|
static 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);
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
#cat: ridge_count - Takes a pair of minutiae, and counts the number of
|
#cat: ridge_count - Takes a pair of minutiae, and counts the number of
|
||||||
|
@ -523,7 +558,7 @@ int sort_neighbors(int *nbr_list, const int nnbrs, const int first,
|
||||||
Zero or Positive - number of ridges counted
|
Zero or Positive - number of ridges counted
|
||||||
Negative - system error
|
Negative - system error
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
int ridge_count(const int first, const int second, MINUTIAE *minutiae,
|
static int ridge_count(const int first, const int second, MINUTIAE *minutiae,
|
||||||
unsigned char *bdata, const int iw, const int ih,
|
unsigned char *bdata, const int iw, const int ih,
|
||||||
const LFSPARMS *lfsparms)
|
const LFSPARMS *lfsparms)
|
||||||
{
|
{
|
||||||
|
@ -664,168 +699,134 @@ int ridge_count(const int first, const int second, MINUTIAE *minutiae,
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
#cat: find_transition - Takes a pixel trajectory and a starting index, and
|
#cat: count_minutia_ridges - Takes a minutia, and determines its closest
|
||||||
#cat: searches forward along the trajectory until the specified
|
#cat: neighbors and counts the number of interveining ridges
|
||||||
#cat: adjacent pixel pair is found, returning the index where
|
#cat: between the minutia point and each of its neighbors.
|
||||||
#cat: the pair was found (the index of the second pixel).
|
|
||||||
|
|
||||||
Input:
|
Input:
|
||||||
iptr - pointer to starting pixel index into trajectory
|
minutia - input minutia
|
||||||
pix1 - first pixel value in transition pair
|
bdata - binary image data (0==while & 1==black)
|
||||||
pix2 - second pixel value in transition pair
|
iw - width (in pixels) of image
|
||||||
xlist - x-pixel coords of line trajectory
|
ih - height (in pixels) of image
|
||||||
ylist - y-pixel coords of line trajectory
|
lfsparms - parameters and thresholds for controlling LFS
|
||||||
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:
|
Output:
|
||||||
iptr - points to location where 2nd pixel in pair is found
|
minutiae - minutia augmented with neighbors and ridge counts
|
||||||
Return Code:
|
Return Code:
|
||||||
TRUE - pixel pair transition found
|
Zero - successful completion
|
||||||
FALSE - pixel pair transition not found
|
Negative - system error
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
int find_transition(int *iptr, const int pix1, const int pix2,
|
static int count_minutia_ridges(const int first, MINUTIAE *minutiae,
|
||||||
const int *xlist, const int *ylist, const int num,
|
unsigned char *bdata, const int iw, const int ih,
|
||||||
unsigned char *bdata, const int iw, const int ih)
|
const LFSPARMS *lfsparms)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, ret, *nbr_list, *nbr_nridges, nnbrs;
|
||||||
|
|
||||||
/* Set previous index to starting position. */
|
/* Find up to the maximum number of qualifying neighbors. */
|
||||||
i = *iptr;
|
if((ret = find_neighbors(&nbr_list, &nnbrs, lfsparms->max_nbrs,
|
||||||
/* Bump previous index by 1 to get next index. */
|
first, minutiae))){
|
||||||
j = i+1;
|
free(nbr_list);
|
||||||
|
return(ret);
|
||||||
/* 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 */
|
print2log("NBRS FOUND: %d,%d = %d\n", minutiae->list[first]->x,
|
||||||
/* the desired transition, so set the position pointer to the end */
|
minutiae->list[first]->y, nnbrs);
|
||||||
/* of the trajector, and return FALSE. */
|
|
||||||
*iptr = num;
|
/* If no neighors found ... */
|
||||||
return(FALSE);
|
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: validate_ridge_crossing - Takes a pair of points, a ridge start
|
#cat: count_minutiae_ridges - Takes a list of minutiae, and for each one,
|
||||||
#cat: transition and a ridge end transition, and walks the
|
#cat: determines its closest neighbors and counts the number
|
||||||
#cat: ridge contour from thre ridge end points a specified
|
#cat: of interveining ridges between the minutia point and
|
||||||
#cat: number of steps, looking for the ridge start point.
|
#cat: each of its neighbors.
|
||||||
#cat: If found, then transitions determined not to be a valid
|
|
||||||
#cat: ridge crossing.
|
|
||||||
|
|
||||||
Input:
|
Input:
|
||||||
ridge_start - index into line trajectory of ridge start transition
|
minutiae - list of minutiae
|
||||||
ridge_end - index into line trajectory of ridge end transition
|
bdata - binary image data (0==while & 1==black)
|
||||||
xlist - x-pixel coords of line trajectory
|
iw - width (in pixels) of image
|
||||||
ylist - y-pixel coords of line trajectory
|
ih - height (in pixels) of image
|
||||||
num - number of coords in line trajectory
|
lfsparms - parameters and thresholds for controlling LFS
|
||||||
bdata - binary image data (0==while & 1==black)
|
Output:
|
||||||
iw - width (in pixels) of image
|
minutiae - list of minutiae augmented with neighbors and ridge counts
|
||||||
ih - height (in pixels) of image
|
|
||||||
max_ridge_steps - number of steps taken in search in both
|
|
||||||
scan directions
|
|
||||||
Return Code:
|
Return Code:
|
||||||
TRUE - ridge crossing VALID
|
Zero - successful completion
|
||||||
FALSE - ridge corssing INVALID
|
Negative - system error
|
||||||
Negative - system error
|
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
int validate_ridge_crossing(const int ridge_start, const int ridge_end,
|
int count_minutiae_ridges(MINUTIAE *minutiae,
|
||||||
const int *xlist, const int *ylist, const int num,
|
unsigned char *bdata, const int iw, const int ih,
|
||||||
unsigned char *bdata, const int iw, const int ih,
|
const LFSPARMS *lfsparms)
|
||||||
const int max_ridge_steps)
|
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int feat_x, feat_y, edge_x, edge_y;
|
int i;
|
||||||
int *contour_x, *contour_y, *contour_ex, *contour_ey, ncontour;
|
|
||||||
|
|
||||||
/* Assign edge pixel pair for contour trace. */
|
print2log("\nFINDING NBRS AND COUNTING RIDGES:\n");
|
||||||
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. */
|
/* Sort minutia points on x then y (column-oriented). */
|
||||||
fix_edge_pixel_pair(&feat_x, &feat_y, &edge_x, &edge_y,
|
if((ret = sort_minutiae_x_y(minutiae, iw, ih))){
|
||||||
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);
|
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. */
|
|
||||||
|
/* Remove any duplicate minutia points from the list. */
|
||||||
/* If we get here, then we failed to validate a ridge crossing. */
|
if((ret = rm_dup_minutiae(minutiae))){
|
||||||
return(FALSE);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,133 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
License:
|
|
||||||
This software was developed at the National Institute of Standards and
|
|
||||||
Technology (NIST) by employees of the Federal Government in the course
|
|
||||||
of their official duties. Pursuant to title 17 Section 105 of the
|
|
||||||
United States Code, this software is not subject to copyright protection
|
|
||||||
and is in the public domain. NIST assumes no responsibility whatsoever for
|
|
||||||
its use by other parties, and makes no guarantees, expressed or implied,
|
|
||||||
about its quality, reliability, or any other characteristic.
|
|
||||||
|
|
||||||
Disclaimer:
|
|
||||||
This software was developed to promote biometric standards and biometric
|
|
||||||
technology testing for the Federal Government in accordance with the USA
|
|
||||||
PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act.
|
|
||||||
Specific hardware and software products identified in this software were used
|
|
||||||
in order to perform the software development. In no case does such
|
|
||||||
identification imply recommendation or endorsement by the National Institute
|
|
||||||
of Standards and Technology, nor does it imply that the products and equipment
|
|
||||||
identified are necessarily the best available for the purpose.
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
LIBRARY: LFS - NIST Latent Fingerprint System
|
|
||||||
|
|
||||||
FILE: 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