This tutorial will guide you through basics of SourceAFIS. It doesn't provide full source code listing - look into sample application bundled in the distribution for complete compilable sources. Focus here is on SourceAFIS-specific topics. General information about fingerprint matching is available from external sources linked from this tutorial.
To work with fingerprint images, one needs to obtain them somehow. SourceAFIS has no built-in methods to capture fingerprints. Capture is generally done with specialized livescan fingerprint readers. Fingerprint reader is accessed through image acquisition SDK that can be obtained from device manufacturer. Make sure your fingerprint reader allows you to retrieve fingerprint image, not some vendor-specific template. Other capture methods are possible, for example scanning ink fingerprints or taking latent prints from crime scene. Whatever the method, you end up with a fingerprint image in some standard format (e.g. BMP, JPEG) or with raw grayscale image. All common image formats can be used in SourceAFIS.
Before using SourceAFIS functionality, you have to do a few simple setup steps. First, download latest SourceAFIS release from SourceForge download area and install it. Open your application in your preferred development environment (Visual Studio or MonoDevelop) and add SourceAFIS.dll to references for your application. Open source file where you want to call SourceAFIS methods and add using directive for SourceAFIS.Simple namespace:
Create new AfisEngine object and store it somewhere so that it can be accessed by all code in your application. It is OK to create multiple AfisEngine objects, but for the sake of simplicity and some extra performance, it is recommended to keep only one AfisEngine in a static variable like this:
static AfisEngine Afis = new AfisEngine();
Once you have working setup of SourceAFIS and some captured fingerprints, it is time to import them into SourceAFIS. The following example creates three Fingerprint objects using properties AsBitmapSource, AsBitmap, and Image to handle different image formats:
// using .NET 3.0 (WPF) bitmap Fingerprint fp1 = new Fingerprint(); fp1.AsBitmapSource = new BitmapImage(new Uri(pathToImage, UriKind.RelativeOrAbsolute)); // using .NET 2.0 (WinForms) bitmap Fingerprint fp2 = new Fingerprint(); fp2.AsBitmap = new Bitmap(Bitmap.FromFile(pathToImage)); // using raw grayscale image (see API docs for format description) Fingerprint fp3 = new Fingerprint(); fp3.Image = myRawImage;
SourceAFIS supports multiple fingerprints per person. If you need only one fingerprint for now, just wrap it in Person object like this:
Person person = new Person(); person.Fingerprints.Add(fp);
SourceAFIS doesn't match fingerprint images directly. It extracts minutiae from the fingerprint image and stores them in fingerprint template that is much smaller and much faster to match than the original image. Here's how to execute the extraction process:
The extracted template is left in Template property of the Fingerprint object. Template extraction is quite time-consuming, taking about 150 milliseconds per fingerprint. It is therefore wise to perform it only once after fingerprint capture and save the template or the whole Fingerprint/Person object in database along with fingerprint image.
By now, you have captured fingerprint image, extracted fingerprint template, and created Person object with single Fingerprint in it. This process is repeated for all incoming fingerprints. Now that we have all the templates, how do we match them? Easy, just pass two Person objects to AfisEngine.Verify like this:
float score = Afis.Verify(person1, person2); bool match = (score > 0);
This method performs one-to-one (or 1:1 or just verification) matching and returns similarity score between the two fingerprints. If the returned similarity score is zero, the fingerprints are distinct. If the score is above zero, the two fingerprints match and similarity score reflects accuracy of the match.
- FAR (false accept rate), also called FMR (false match rate) or false positive rate, that measures frequency of false accepts.
- FRR (false reject rate), also called FNMR (false non-match rate) or false negative rate, that measures frequency of false rejects.
SourceAFIS allows you to choose application-specific compromise between FAR and FRR by setting AfisEngine.Threshold to appropriate matching threshold. This instructs AfisEngine.Verify to return zero whenever similarity score drops below AfisEngine.Threshold. Higher threshold keeps FAR low. Lower threshold keeps FRR low.
At certain balance threshold, FAR and FRR are equal and they constitute EER (equal error rate). The easiest way to approximate EER is to perform some tests with pairs of matching and non-matching fingerprints, observe typical matching and typical non-matching score, and set threshold somewhere in the middle. You can then proceed to shift the threshold higher or lower depending on preference for FAR or FRR.
Note that SourceAFIS cannot provide standard threshold, because EER occurs at different thresholds depending on fingerprint characteristics like fingerprint reader type, population sampled, and enrollment policy used. More generally speaking, ROC curve (plot of FAR and FRR as a function of threshold) is different for every test database used to benchmark SourceAFIS. Nevertheless SourceAFIS does have default value for AfisEngine.Threshold that should work for prototypes and for initial testing of your application.
Now that you have done some simple one-to-one verification, it is time to try one-to-many (1:N) identification. In order to search whole database of fingerprints, put all Person objects (candidates) into an enumerable collection and pass this collection to AfisEngine.Identify along with probe Person to look up:
Person matchingCandidate = Afis.Identify(probePerson, allCandidates).FirstOrDefault(); bool match = (matchingCandidate != null);
This is functionally equivalent to the following LINQ query, except that AfisEngine.Identify is much faster:
Person matchingCandidate = (from candidate in allCandidates let score = Afis.Verify(probePerson, candidate) where score >= Afis.Threshold orderby score descending select candidate).FirstOrDefault(); bool match = (matchingCandidate != null);
AfisEngine.Identify returns candidate from the array that matches the probe. If all candidates are below AfisEngine.Threshold, AfisEngine.Identify returns null. If there are multiple candidates matching above threshold, AfisEngine.Identify returns the one with highest similarity score.
In order to deploy application that uses SourceAFIS, you need to distribute only one file: SourceAFIS.dll. Install SourceAFIS.dll in the same folder where you install your application's executable. SourceAFIS has no dependencies short of .NET Framework. SourceAFIS doesn't use any system functionality nor unsafe code. It should therefore work in secure environments like ASP.NET or Silverlight.
Although we have used single fingerprint per person in this tutorial, SourceAFIS supports multi-finger matching for better accuracy. Just add more Fingerprint objects into every Person object and pass such Person objects to Verify or Identify. You can use Fingerprint.Finger property to restrict matching to compatible fingerprint pairs. You can also set AfisEngine.MinMatches to control the process of combining scores from individual fingerprints.
SourceAFIS lets you work with sensors of varying DPI by setting AfisEngine.Dpi.
Person and Fingerprint classes support serialization in binary streams and in XML. You can also serialize individual templates by accessing properties Fingerprint.Template and Fingerprint.AsXmlTemplate for binary and XML encoding respectively. Both classes support inheritance, so that you can add (and serialize) your own fields/properties. SourceAFIS supports export/import of ISO/IEC 19794-2:2005 templates using Fingerprint.AsIsoTemplate property.
See the sample bundled in SourceAFIS distribution for runnable application that uses SourceAFIS. Consult API reference for details on SourceAFIS features. If you still have questions, post them in SourceAFIS forums.