Biometric SDK 是一个开源的指纹识别开发包,可匹配和标识人们的指纹。计算指纹相似度
关键代码:
/*
Biometric SDK
Version 1.3
This file contains functions that manipulate , extract features and match
fingerprint images.
Copyright (C) 2005 Scott Johnston
Email : moleisking@googlemail.com
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace BiometricsSDK.FingerPrint
{
/// <summary>
/// Summary description for CFinger.
/// </summary>
public class CFingerPrint
{
//used for image
//for digital persona with kit
//public int FP_IMAGE_WIDTH = 500;
//public int FP_IMAGE_HEIGHT = 500;
//for verifinger with kit
public int FP_IMAGE_WIDTH = 323;
public int FP_IMAGE_HEIGHT = 352;
//Used by template
//be carefull the size of the array must always be 1 larger than a number divisable by 4
public int FP_TEMPLATE_MAX_SIZE = 601;
//used for matching
//the max distance between to points when comparing two points to count as a match
public int FP_MATCH_POINT_DISTANCE_MOVEMENT = 10;
//the max rotation to use when comparint two points to count as a match
public int FP_MATCH_POINT_ROTATION_MOVEMENT = 10;//10;
//a percentage
public int FP_MATCH_THRESHOLD = 55;
//finger print classifications
//Wirbel class
public const int FP_CLASS_WHORL = 1 ;
//lasso class
public const int FP_CLASS_LEFT_LOOP = 2;
public const int FP_CLASS_RIGHT_LOOP = 3;
public const int FP_CLASS_ARCH = 4;
public const int FP_CLASS_ARCH_TENTED = 5;
//fingerprint template values
private const int FP_TEMPLATE_SIZE = 0;
private const int FP_TEMPLATE_ORIGIN_X = 1;
private const int FP_TEMPLATE_ORIGIN_Y = 2;
private const int FP_TEMPLATE_FEATURE_SIZE = 6;
private const int FP_TEMPLATE_SEARCH_RADIUS = 1;
//fingerprint origin values
//private int FP_ORIGIN_SEARCH_RADIUS = 5;
//holds skeletinized image
public byte [,] P = new byte[500,500];
public CFingerPrint()
{
}
public CFingerPrint(int width , int height )
{
FP_IMAGE_WIDTH = width;
FP_IMAGE_HEIGHT = height;
P = new byte[width,height];
}
public CFingerPrint(int width , int height ,int MatchPointDistanceMovement , int MatchPointRotationMovment , int MatchThreshold )
{
FP_IMAGE_WIDTH = width;
FP_IMAGE_HEIGHT = height;
FP_MATCH_POINT_DISTANCE_MOVEMENT = MatchPointDistanceMovement;
FP_MATCH_POINT_ROTATION_MOVEMENT = MatchPointRotationMovment;
FP_MATCH_THRESHOLD = MatchThreshold;
}
/// <summary>
///
/// </summary>
/// <param name="m_image"></param>
public void setFingerPrintImage(Bitmap m_image)
{
try
{
int h = m_image.Height;//原代码为:FP_IMAGE_HEIGHT,现替换为:h
int w = m_image.Width;//原代码为:FP_IMAGE_WIDTH,现替换为:w
for (int i = 0; i <= w - 1; i++)
{
for (int j = 0; j <= h - 1; j++)
{
if ((m_image.GetPixel(i, j).B <= 127) && (m_image.GetPixel(i, j).R <= 127) && (m_image.GetPixel(i, j).G <= 127))
{
P[i, j] = 1;
}
else
{
P[i, j] = 0;
}
}
}
//set edges to 0
for (int i = 0; i <= w - 1; i++)
{
P[i, 0] = 0;
P[i, h - 1] = 0;
}
for (int j = 0; j <= h - 1; j++)
{
P[0, j] = 0;
P[w - 1, j] = 0;
}
}
catch (Exception ex)
{
throw ex;
}
}
public Bitmap getFingerPrintImage()
{
Bitmap imageBuffer = new Bitmap(FP_IMAGE_WIDTH, FP_IMAGE_HEIGHT);
for (int i = 0; i<= FP_IMAGE_WIDTH - 1;i++)
{
for (int j = 0;j<= FP_IMAGE_HEIGHT - 1;j++)
{
if (P[i, j] == 1)
{
imageBuffer.SetPixel(i, j, Color.Blue);
}
else
{
imageBuffer.SetPixel(i, j, Color.White);
}
}
}
return imageBuffer;
}
public Bitmap getFingerPrintImageDetail()
{
//set finger print image
Bitmap imageBuffer = new Bitmap(FP_IMAGE_WIDTH,FP_IMAGE_HEIGHT );
for (int i = 0; i<= FP_IMAGE_WIDTH - 1;i++)
{
for (int j = 0;j<= FP_IMAGE_HEIGHT - 1;j++)
{
if (P[i,j] == 1)
imageBuffer.SetPixel(i,j,Color.Blue);
else
imageBuffer.SetPixel(i,j,Color.White );
}
}
//get features
double[] m_arr = this.getFingerPrintTemplate();
// int linelength = 5;
//draw points
Pen penBlue = new Pen(Color.Blue, 1);
Pen penRed = new Pen(Color.Red, 1);
Pen penGreen = new Pen(Color.Green, 1);
Pen penGray = new Pen(Color.Gray, 1);
//Graphics gf = Graphics.FromImage(Image.FromHbitmap(m_ImageBuffer.GetHbitmap() ));
Graphics gf = Graphics.FromImage(imageBuffer);
gf.CompositingMode = CompositingMode.SourceOver;
for(int i=7 ; i<=m_arr[0]-1;i=i+6)
{
if(m_arr[i+4]>1)
{
gf.DrawRectangle(penRed,(int)m_arr[i]+(int)m_arr[1]-3,(int)m_arr[i+1]+(int)m_arr[2]-2,5,5);
}
else if(m_arr[i+4]==1)
{
gf.DrawEllipse(penGreen,(int)m_arr[i]+(int)m_arr[1]-3,(int)m_arr[i+1]+(int)m_arr[2]-2,5,5);
}
}//end for
//draws the origin
gf.DrawLine(penGray,(int)m_arr[1]-5,(int)m_arr[2],(int)m_arr[1]+5,(int)m_arr[2]);
gf.DrawLine(penGray,(int)m_arr[1],(int)m_arr[2]-5,(int)m_arr[1],(int)m_arr[2]+5);
return imageBuffer;
}//end getFingerPrintImageDetail()
public void ThinningHilditch()
{
int change = 1;
bool mbool = true;
while (change != 0)
{
change = 0;
for(int i = 2; i <= FP_IMAGE_WIDTH - 2;i++)
{
for(int j = 2; j <= FP_IMAGE_HEIGHT - 2;j++)
{
if (P[i,j] == 1)
{
short c = 0;
//count surrounding 1
//a) Make sure pixel 1, has 2 to 6 (inclusive) neighbors
if (P[i,j+1] == 1) { c++;}
if (P[i+1,j+1] == 1) { c++;}
if (P[i+1,j] == 1) { c++;}
if (P[i+1,j-1] == 1) { c++;}
if (P[i,j-1] == 1) { c++;}
if (P[i-1,j-1] == 1) { c++;}
if (P[i-1,j] == 1) { c++;}
if (P[i-1,j+1] == 1) { c++;}
if ((c >= 2) && (c <= 6 ))
{
c = 0;
//b) starting from 2, go clockwise until 9, and count the
//' number of 0 to 1 transitions. This should be equal to 1.
if ((P[i-1,j+1] == 0) && (P[i,j+1] == 1)) { c++;}
if ((P[i,j+1] == 0) && (P[i+1,j+1] == 1)) { c++;}
if ((P[i+1,j+1] == 0) && (P[i+1,j] == 1)) { c++;}
if ((P[i+1,j] == 0) && (P[i+1,j-1] == 1)) { c++;}
if ((P[i + 1,j-1] == 0) && (P[i,j-1] == 1)) { c++;}
if ((P[i,j-1] == 0) && (P[i-1,j-1] == 1)) { c++;}
if ((P[i-1,j-1] == 0) && (P[i-1,j] == 1)) { c++;}
if ((P[i - 1,j] == 0) && (P[i-1,j+1] == 1)) { c++;}
if (c == 1 )
{
c = 0;
if (mbool == true)
{
//c) 2*4*6=0 (ie either 2,4 ,or 6 is off)
if ((P[i,j+1] * P[i+1,j] * P[i+1,j-1]) == 0 )
{
//d) 4*6*8=0
if ((P[i+1,j] * P[i+1,j-1] * P[i-1,j]) == 0 )
{
P[i,j] = 0;
change++;
}
}
mbool = false;
}
else
{
//c) 2*6*8=0
if ((P[i,j+1] * P[i+1,j-1] * P[i-1,j]) == 0)
{
//d) 2*4*8=0
if ((P[i,j+1] * P[i+1,j] * P[i-1,j]) == 0)
{
P[i,j] = 0;
change++;
}
}
mbool = true;
}
}
}
}
}
}
}//End While
}//end ThinningHilditchAlgorithim
public void ThinningHitAndMiss()
{
/*
* basicly you take all patterns
* 111 X1X
* X1X or x11 so on
* 000 xxX
* if these conditions are true then set the middle 1 to 0
*/
int c = 1;
while (c != 0)
{
c = 0;
for(int i = 1;i<=FP_IMAGE_WIDTH - 1;i++)
{
for(int j = 1;j<=FP_IMAGE_HEIGHT - 1;j++)
{
if ((P[i,j] == 1) && (i != 0) && (j != FP_IMAGE_HEIGHT - 1) && (j != 0) && (i != FP_IMAGE_WIDTH - 1))
{
if ((P[i-1,j-1] == 1) &&( P[i,j-1] == 1) && (P[i+1,j-1] == 1) && (P[i-1,j+1] == 0) && (P[i,j+1] == 0) && (P[i+1,j+1] == 0))
{
P[i,j] = 0; //'1 on bottom
c++;
}
else if ((P[i-1,j+1] == 1) && (P[i,j+1] == 1) && (P[i+1,j+1] == 1) && (P[i-1,j-1] == 0) && (P[i,j-1] == 0) && (P[i+1,j-1] == 0))
{
P[i,j] = 0; //'1 on top
c++;
}
else if ((P[i-1,j] == 1) && (P[i-1,j - 1] == 1) && (P[i-1,j+1] == 1) && (P[i+1,j] == 0) && (P[i+1,j+1] == 0) && (P[i+1,j-1] == 0))
{
P[i,j] = 0; //'1 on left
c++;
}
else if ((P[i+1,j] == 1) && (P[i+1,j-1] == 1) && (P[i+1,j+1] == 1) && (P[i-1,j] == 0) && (P[i-1,j+1] == 0) && (P[i-1,j-1] == 0) )
{
P[i,j] = 0; //'1 on right
c++;
}
else if ((P[i-1,j] == 1) && (P[i,j-1] == 1) && (P[i,j+1] == 0) && (P[i+1,j+1] == 0) && (P[i + 1,j] == 0))
{
//x00
//110
//x1x
P[i,j] = 0; //'1 on Bottem Left
c++;
}
else if ((P[i-1,j] == 1) && (P[i,j+1] == 1) && (P[i,j-1] == 0) && (P[i+1,j-1] == 0) && (P[i+1,j] == 0))
{
//x1x
//110
//x00
P[i,j] = 0; //'1 on Top Left
c++;
}
else if ((P[i,j+1]== 1) && (P[i+1,j] == 1) && (P[i-1,j] == 0) && (P[i-1,j-1] == 0) && (P[i,j-1] == 0))
{
//x1x
//011
//00x
P[i,j] = 0; //'1 on Top Right
c++;
}
else if ((P[i,j-1] == 1) && (P[i+1,j] == 1) && (P[i-1,j] == 0) && (P[i-1,j+1] == 0) && (P[i,j+1] == 0) )
{
//00x
//011
//x1x
P[i,j] = 0; //'1 on Bottom Right
c++;
}
}
}//Next
}//Next
}//End While
}//end ThinningHitAndMiss
public void ChaneLinkAlgorithm(int ChainLinkDistance)
{
//short count1;
for(int i = 1;i<= FP_IMAGE_WIDTH - 1;i++)
{
for (int j = 1 ; j <= FP_IMAGE_HEIGHT - 1;j++)
{
//change second condition when changeing direction
//Horizontal
if ((P[i,j] == 1) && (i != FP_IMAGE_WIDTH - 1) && (i != 0) && (j != FP_IMAGE_HEIGHT - 1) && (j != 0))
{
if (P[i + 1,j] == 0)
{
short countX = 0;
//count Horizontal Hole
while (((i + countX) <= FP_IMAGE_WIDTH - 1) && (countX <= ChainLinkDistance))
{
if (((i + countX + 1) <= FP_IMAGE_WIDTH - 1) && ((countX + 1) <= ChainLinkDistance))
{
if (P[i + countX + 1,j] == 0)
{
countX++;
}
else
{
break;
}
}
else
{
break;
}
}
//Fill hole if it is wide enough
if ((countX != 0) && ((countX + 1) <= ChainLinkDistance))
{
for (int temp = 0; temp<= countX;temp++)
{
P[i+temp,j] = 1;
}
}
}
}
//change second condition when changeing direction
//Vertical
if ((P[i,j] == 1) && (i != FP_IMAGE_WIDTH - 1) && (i != 0) && (j != FP_IMAGE_HEIGHT - 1) && (j != 0))
{
if (P[i,j+1] == 0 )
{
short countY = 0;
//count Horizontal Hole
while (((j + countY) <= FP_IMAGE_HEIGHT-1) && (countY <= ChainLinkDistance))
{
if (((j + countY + 1) <= FP_IMAGE_HEIGHT-1) && ((countY + 1) <= ChainLinkDistance) )
{
//i pu this here bacause it kept on crashing
if (P[i,j + countY + 1] == 0)
{
countY++;
}
else
{
break;
}
}
else
{
break;
}
}
//Fill hole if it is wide enough
if ((countY != 0) && (countY + 1 <= ChainLinkDistance))
{
for(int temp = 0;temp<= countY;temp++)
{
P[i,j + temp] = 1;
}
}
}
}
//change second condition when changeing direction
//Vertical Horizontal
if ((P[i,j] == 1) && (i != FP_IMAGE_WIDTH - 1) && (i != 0) && (j != FP_IMAGE_HEIGHT - 1) && (j != 0))
{
if (P[i + 1,j + 1] == 0)
{
short countYX = 0; //1
//count Horizontal Hole
while ((j + countYX <= FP_IMAGE_HEIGHT-1) && (i + countYX <= FP_IMAGE_WIDTH-1) && (countYX <= ChainLinkDistance))
{
if (((j + countYX + 1) <= FP_IMAGE_HEIGHT-1) && ((i + countYX + 1) <= FP_IMAGE_WIDTH-1) && ((countYX + 1) <= ChainLinkDistance))
if (P[i+countYX+1,j + countYX + 1] == 0)
{
countYX++;
}
else
{
break;
}
else
{
break;
}
}
//Fill hole if it is wide enough
if ((countYX != 0) && (countYX + 1 <= ChainLinkDistance))
{
for(int temp = 0 ; temp <= countYX ; temp++)
{
P[i+temp,j+temp] = 1;
}
}
}
}
}
}
}
/// <summery>
///
/// ################################
/// # Extract Origin #
/// ################################
///
/// In future i want to use the gradients to classifie the finger print into the 5 different
/// catagories which are marked in the FP_CLASS.
///
/// This function still needs to improved and somtimes dosen't find the center of the finger print.
///
/// The principle in finding the centre is simple , just find the greatest change in the gradient
/// bettween two lines and you have your centre.
///
/// To find the classification you have to find the average changes in gradients in the different
/// sectors (if you divided your picture in 4 using the fingerprint centre as the centre).You should
/// then classifie the fingerprint according to this.
///
/// <summery>
private Point getFingerPrintOrigin()
{
Point m_Point = new Point();
double gradcur=0;
double gradprev=0;
double gradchangebig=0;
double gradchange=0;
double graddistancebig=0;
double graddistance=0;
double prevx=0;
double prevy=0;
for(int j =50;j<=FP_IMAGE_HEIGHT-50;j++)
{
for(int i =50;i<=FP_IMAGE_WIDTH-50;i++)
{
if(P[i,j]==1)
{
//count surrounding pixels
int tc=0;
int x1=0;
int y1=0;
int x2=0;
int y2=0;
//find surrounding 1s
for (int m = -1*FP_TEMPLATE_SEARCH_RADIUS;m<=FP_TEMPLATE_SEARCH_RADIUS;m++)
{
for (int n = -1*FP_TEMPLATE_SEARCH_RADIUS;n<=FP_TEMPLATE_SEARCH_RADIUS;n++)
{
if ((m==FP_TEMPLATE_SEARCH_RADIUS)||(m==(-1)*FP_TEMPLATE_SEARCH_RADIUS)||(n==FP_TEMPLATE_SEARCH_RADIUS)||(n==(-1)*FP_TEMPLATE_SEARCH_RADIUS))
{
if(P[i+m,j+n] == 1 )
{
tc++;
if (tc==1)
{
x1=i+m;
y1=j+n;
}
if (tc==2)
{
x2=i+m;
y2=j+n;
}
}//end if
}//end if
}//end for n
} //end for m
//does all the hard work of finding the greatest change in gradient
if(tc==2)
{
if ((x2-x1)>0)
{
gradcur = (y2-y1)/(x2-x1);
//check to see gradient change by at least 270 degrees
if((gradcur>0)&&(gradprev<0))
{
gradchange = Math.Abs(gradcur) + Math.Abs(gradprev) ;
graddistance = Math.Abs(i) - Math.Abs(prevx);
if(gradchangebig<gradchange)
{
if (graddistancebig<graddistance)
{
gradchangebig=gradchange;
graddistancebig=graddistance;
m_Point.X=i;//FP_ORIGIN_X =i;
m_Point.Y=j;//FP_ORIGIN_Y =j;
}
}
break;
}
//reset varibles for new checks
gradprev=gradcur;
gradcur=0;
prevx=i;
prevy=j;
}//(x2-x1)>0
}//end if tc==2
}//end if P[x,y]==1
}//end for i
}//end for j
// JOptionPane.showMessageDialog (null,Integer.toString(FP_ORIGIN_X)+";"+Integer.toString(FP_ORIGIN_Y),"getFingerPrintOrigin",JOptionPane.PLAIN_MESSAGE);
return m_Point;
}
private int getFingerPrintClassification()
{
Point m_Point = this.getFingerPrintOrigin();
double gradcur=0;
//stores total gradient of corners
double gradlt=0;
double gradrt=0;
double gradlb=0;
double gradrb=0;
//counts total of each corner gradient
double cgradlt=0;
double cgradrt=0;
double cgradlb=0;
double cgradrb=0;
for(int j =50;j<=FP_IMAGE_HEIGHT-50;j++)
{
for(int i =50;i<=FP_IMAGE_WIDTH-50;i++)
{
if(P[i,j]==1)
{
//count surrounding pixels
int tc=0;
int x1=0;
int y1=0;
int x2=0;
int y2=0;
//find surrounding 1s
for (int m = -1*FP_TEMPLATE_SEARCH_RADIUS;m<=FP_TEMPLATE_SEARCH_RADIUS;m++)
{
for (int n = -1*FP_TEMPLATE_SEARCH_RADIUS;n<=FP_TEMPLATE_SEARCH_RADIUS;n++)
{
if ((m==FP_TEMPLATE_SEARCH_RADIUS)||(m==(-1)*FP_TEMPLATE_SEARCH_RADIUS)||(n==FP_TEMPLATE_SEARCH_RADIUS)||(n==(-1)*FP_TEMPLATE_SEARCH_RADIUS))
{
if(P[i+m,j+n] == 1 )
{
tc++;
if (tc==1)
{
x1=i+m;
y1=j+n;
}
if (tc==2)
{
x2=i+m;
y2=j+n;
}
}//end if
}//end if
}//end for n
} //end for m
//does all the hard work of finding the greatest change in gradient
if(tc==2)
{
if ((x2-x1)>0)
{
gradcur = (y2-y1)/(x2-x1);
//check to see gradient change by at least 270 degrees
if ((x2<m_Point.X)&&(y2>m_Point.Y))
{
gradlt=gradlt+gradcur;
gradlt++;
}
else if ((x2>m_Point.X)&&(y2>m_Point.Y))
{
gradrt=gradrt+gradcur;
gradrt++;
}
else if ((x2<m_Point.X)&&(y2<m_Point.Y))
{
gradlb=gradlb+gradcur;
gradlb++;
}
else if ((x2>m_Point.X)&&(y2<m_Point.Y))
{
gradrb=gradrb+gradcur;
gradrb++;
}
}//(x2-x1)>0
}//end if tc==2
}//end if P[x,y]==1
}//end for i
}//end for j
//get average gradient for 4 corners
gradlb=gradlb/cgradlb;
gradrb=gradrb/cgradrb;
gradlt=gradlt/cgradlt;
gradrt=gradrt/cgradrt;
//determin classification according to gradient
//needs work
if ((gradlt>0)&&(gradrt>0)&&(gradlb>0)&&(gradrb>0))
{
return FP_CLASS_WHORL;
}
else if ((gradlt>0)&&(gradrt>0)&&(gradlb>0)&&(gradrb>0))
{
return FP_CLASS_LEFT_LOOP;
}
else if ((gradlt>0)&&(gradrt>0)&&(gradlb>0)&&(gradrb>0))
{
return FP_CLASS_RIGHT_LOOP;
}
else if ((gradlt>0)&&(gradrt>0)&&(gradlb>0)&&(gradrb>0))
{
return FP_CLASS_ARCH;
}
else if ((gradlt>0)&&(gradrt>0)&&(gradlb>0)&&(gradrb>0))
{
return FP_CLASS_ARCH_TENTED;
}
else
{
return 1;
}
// JOptionPane.showMessageDialog (null,Integer.toString(FP_ORIGIN_X)+";"+Integer.toString(FP_ORIGIN_Y),"getFingerPrintOrigin",JOptionPane.PLAIN_MESSAGE);
}
/*<summery>
################################
# Extract Template #
################################
The template will have to be formated according to the ISO standards as set out buy
NIST , NIST also has a set of binary pictures to use for examples. This database is used for
determaning the FAR(False Acceptance Rate) and FRR (False Rejection Rate)
First 7 are (elements in array , originx , originy , null , null , null ,null) after that
the format is (x,y,r,degree ,number of ends,resultant degree).The size of the array
is always pre set.
There is also future work that needs to be done on genralization , basicly what this means is
that you take 3 finger templates , then take the features that are common to all three templeate
and you will then come out with a generalized template.This will improve quality of the template.
</summery>*/
public double[] getFingerPrintTemplate()
{
// final int SEARCH_RADIUS = 1;
double x=0;
double y=0;
double r=0;
double d=0;
double[] m_arr = new double[FP_TEMPLATE_MAX_SIZE];
this.ThinningHilditch();
this.ThinningHitAndMiss();
this.ThinningHilditch();
this.ThinningHitAndMiss();
Point origin = this.getFingerPrintOrigin();
m_arr[1]=origin.X;
m_arr[2]=origin.Y;
int c = 7 ;
int previ=0;
int prevj=0;
bool first = true;
//start from 5 units in to avoid detection of edges of finger print and out of bound exceptions
for(int j = 5 ;j<= FP_IMAGE_HEIGHT - 6;j++)
{
first = true;
for( int i =5 ;i<= FP_IMAGE_WIDTH - 6;i++)
{
if ((c<FP_TEMPLATE_MAX_SIZE)&&(P[i,j] == 1) && (i != FP_IMAGE_WIDTH - 1) && (i != 0) && (j != FP_IMAGE_HEIGHT - 1) && (j != 0) )
{
/*
* Must not capture first and last feature because those are the edges of the finger print
* and will provide no value to the template.
*/
if(first == true)
{
first = false;
//cheak to see if previos item in array was aslo end
if( (c>7)&&((m_arr[c-6]+origin.X)==previ)&&((m_arr[c-5]+origin.Y)==prevj) )
{
//delete previos featue
m_arr[c--]=0;
m_arr[c--]=0;
m_arr[c--]=0;
m_arr[c--]=0;
m_arr[c--]=0;
m_arr[c--]=0;
}
}
else
{
int tc = 0;
for (int m = -1*FP_TEMPLATE_SEARCH_RADIUS;m<=FP_TEMPLATE_SEARCH_RADIUS;m++)
{
for (int n = -1*FP_TEMPLATE_SEARCH_RADIUS;n<=FP_TEMPLATE_SEARCH_RADIUS;n++)
{
if ((m==FP_TEMPLATE_SEARCH_RADIUS)||(m==(-1)*FP_TEMPLATE_SEARCH_RADIUS)||(n==FP_TEMPLATE_SEARCH_RADIUS)||(n==(-1)*FP_TEMPLATE_SEARCH_RADIUS))
{
if(P[i+m,j+n] == 1 )
{
tc++;
}//end if
}//end if
}//end for n
} //end for m
//calculate parameters necesary for template
if ((tc==1)||(tc==3))
{
x = i- origin.X;
y = j- origin.Y;
r = Math.Sqrt(x*x + y*y);
if ((x>0)&&(y>0))
{
d =Math.Atan(y/x);
}
else if ((x<0)&&(y>0))
{
d =Math.Atan(y/x) - Math.PI ;
}
else if ((x<0)&&(y<0))
{
d =Math.PI + Math.Atan(y/x);
}
else if ((x>0)&&(y<0))
{
d =2*Math.PI + Math.Atan(y/x);
}
}
//check to see if point already been captured
bool foundx = false;
bool foundy = false;
for (int m=7;m<=c;m=m+6)
{
if(m_arr[m+4]==3)
{
if(Math.Abs(Math.Abs((int)m_arr[m])-Math.Abs(x))<4)
{
foundx=true;
}
if(Math.Abs(Math.Abs((int)m_arr[m+1])-Math.Abs(y))<4)
{
foundy=true;
}
}//end if
}//end for m
//1 surrounding 1s
if ((tc==1) && (c <= FP_TEMPLATE_MAX_SIZE-6) && (x!=0) && (y!=0) && ((foundx==false)||(foundy==false)) )
{
if (P[i-1,j+1] == 1)
{
m_arr[c++] = x;
m_arr[c++] = y;
m_arr[c++] = r;
m_arr[c++] = d;
m_arr[c++] = 1 ;
m_arr[c++] = 135 ;
}
else if (P[i,j+1] == 1)
{
m_arr[c++] = x;
m_arr[c++] = y;
m_arr[c++] = r;
m_arr[c++] = d;
m_arr[c++] = 1 ;
m_arr[c++] =90 ;
}
else if (P[i+1,j+1] == 1)
{
m_arr[c++] = x;
m_arr[c++] = y;
m_arr[c++] = r;
m_arr[c++] = d;
m_arr[c++] = 1 ;
m_arr[c++] =45 ;
}
else if (P[i+1,j] == 1)
{
m_arr[c++] = x;
m_arr[c++] = y;
m_arr[c++] = r;
m_arr[c++] = d;
m_arr[c++] = 1 ;
m_arr[c++] = 0 ;
}
else if (P[i+1,j-1] == 1)
{
m_arr[c++] = x;
m_arr[c++] = y;
m_arr[c++] = r;
m_arr[c++] = d;
m_arr[c++] = 1 ;
m_arr[c++] =315 ;
}
else if (P[i,j-1] == 1)
{
m_arr[c++] = x;
m_arr[c++] = y;
m_arr[c++] = r;
m_arr[c++] = d;
m_arr[c++] = 1 ;
m_arr[c++] = 270 ;
}
else if (P[i-1,j-1] == 1)
{
m_arr[c++] = x;
m_arr[c++] = y;
m_arr[c++] = r;
m_arr[c++] = d;
m_arr[c++] = 1 ;
m_arr[c++] = 225 ;
}
else if (P[i-1, j] == 1 )
{
m_arr[c++] = x;
m_arr[c++] = y;
m_arr[c++] = r;
m_arr[c++] = d;
m_arr[c++] = 1 ;
m_arr[c++] = 180 ;
}
}
else if ((tc>=3)&&(c <= FP_TEMPLATE_MAX_SIZE - 6)&&(x!=0)&&(y!=0)&&((foundx==false)||(foundy==false)) )
{
//3 surrounding 1s
m_arr[c++] = x;
m_arr[c++] = y;
m_arr[c++] = r;
m_arr[c++] = d;
m_arr[c++] = 3;
m_arr[c++] = 0;
}//if tc>=3
}//end if first
previ=i;
prevj=j;
//306;269
if (((i- origin.X)>=(306 - 4))&&((i- origin.Y)>=(269-4)))
{
if (((i- origin.X)<=(306+4))&&((i- origin.Y)<=(269+4)))
{
//JOptionPane.showMessageDialog (null,Double.toString(c)+";"+Integer.toString(i)+";"+Integer.toString(j),"My Point",JOptionPane.PLAIN_MESSAGE);
}
}
}//end if that checks for p[x,y]=1
}//end for
}//end for
//put total size of points collected at 0 in array
m_arr[0]=c;
return m_arr;
}//end getFingerPrintTemplate()
public String ConvertFingerPrintTemplateDoubleToString(double[] finger)
{
String temp="";
for (int i=0;i<=finger.Length-1 ; i++)
{
temp = temp + finger[i].ToString() +";";
}
return temp;
}
public double [] ConvertFingerPrintTemplateStringToDouble(String finger)
{
double[] m_finger = new double[FP_TEMPLATE_MAX_SIZE];
int c=-1;
String m_double = "";
String temp ="";
for (int i=0;i<=finger.Length-1 ; i++)
{
char[] tempch = finger.ToCharArray();
temp = temp[i].ToString();
if (temp==";")
{
m_finger[c++] =Double.Parse(m_double);
}
else
{
m_double = m_double + temp;
}
}
return m_finger;
}
/// <summery>
/// ################################
/// # Matching #
/// ################################
///
/// Something to possably look at are
///
/// Distance = (X1 -X2)^2 + (Y1 - Y2)^2. The Error_Rating , if a image is is to the left or
/// right or even at a angle the distance betwwen matched points will always be the same.
///
/// The matching dose account for rotation , thats what the cos and sin are for.
///
/// In matching you will never get a 100% match uunless they are exactly the same
/// image. 60% is quite good in general ,anything above 55% is considered a match , even
/// in other commercial versions. Remember you comparing twod DIFFERENT images then drawing a conclusion of a match.
///
/// </summery>
//cross-corelation algorithm
public int Match(double[] finger1,double[] finger2 , int threshold , bool fastmatch)
{
//compare matrix with all shifted matrixes
//must do later. must get the size of the array
// JOptionPane.showMessageDialog (null,Double.toString(finger1[0])+";"+Double.toString(finger1[1])+";"+Double.toString(finger2[3]),"Match",JOptionPane.PLAIN_MESSAGE);
double matchcount = 0;
double matchcounttotal = (finger1[0]-6)/6;
double bestmatch =0;
double radian = Math.PI/180;
bool foundpoint;
for (int k = -1*FP_MATCH_POINT_ROTATION_MOVEMENT; k <= FP_MATCH_POINT_ROTATION_MOVEMENT; k++)
{
for (int i =7; i <= finger1[0]-5; i=i+6)
{
foundpoint = false;
for (int j =7; j <= finger2[0]-5; j=j+6)
{
if(foundpoint==false)
{
//compare two points account for rotational , verticle and horizontal shift
int resx=0;
int resy=0;
double x1=0 ;
double y1=0;
double x2=0;
double y2=0;
double r=0;
double d=0;
//find nessasary parameters
r =finger2[j+2];
d = finger2[j+3];
x2=finger1[i];
y2=finger1[i+1];
//do angle shift for x
x1 = r*Math.Cos(d+(k*radian));
resx = Math.Abs((int)x2 + (int)(-1*x1));
//do angle shift for y
y1 = r*Math.Sin(d+(k*radian));
resy = Math.Abs((int)y2 + (int)(-1*y1));
//cheak shift matchs count as match
if((FP_MATCH_POINT_DISTANCE_MOVEMENT > resx) && (FP_MATCH_POINT_DISTANCE_MOVEMENT > resy))
{
//cheak if same kind of feature
if(finger1[i+4] == finger2[j+4])
{
//cheak if feature in same direction
// if(((finger1[i+5]-finger2[j+5])<=46)||((finger1[i+5]==0)&&(finger2[j+5]==315))||((finger1[i+5]==0)&&(finger2[j+5]==45)))
// {
matchcount++;
foundpoint = true;
//break;
// }//cheak if feature in same direction
} //cheak if same kind of feature
}//end if
}//if found
}//end for j
}//end for i
//see if we have a match
if ((((matchcount/matchcounttotal)*100)>=threshold)&& (fastmatch == true))
{
//found match
return (int)((matchcount/matchcounttotal)*100);
}
else
{
//not found match
if(matchcount>bestmatch)
{
bestmatch = matchcount;
}
//reset match counter to 0
matchcount=0;
} //end if
}//end for k
return (int)((bestmatch/matchcounttotal)*100);
}//end Match
}//end class
}//end namespace
源代码下载地址1:http://download.csdn.net/detail/lovegonghui/8996059
源代码下载地址2:http://down.51cto.com/data/2081611