41b25f28a4
mindtct is mostly as-is for now, with just a couple of bits ripped out.
192 lines
8.2 KiB
C
192 lines
8.2 KiB
C
/*******************************************************************************
|
|
|
|
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);
|
|
}
|