This repository consists of 3 modules:
- A fingerprint pre-processing chain based on image filtering algorithms
- An algorithm for extracting fingerprint’s features, which are called “minutiae”
- A one-to-one fingerprint matching algorithm.
The dataset used in this repository consists of 500 fingerprint images, each has the resolution of
The first module of this repository transforms a fingerprint image into its skeleton, using Gabor Filter and Morphology Skeletonization. Here are some of its results:
The implemented pipeline is based on this article. The following images show the steps in order, as well as the result of each step:
In order to make the benchmark result accurate and reliable, the program is single-thread. The fingerprints will be processed one after another. There is no paralleled process.
- Processed 500 images: 56.599s
- Average time per image: 0.1132s
- Images per second: 8.83 img/s
The Gabor Filter is not fully optimized. In fact, 80.35% of the runtime is spent on a single step in the pipeline.
Documentation for this module will be composed later.
This module proposes a simple feature extraction algorithm. It takes a skeleton image of a fingerprint, then returns the terminations and bifurcations. It also comes with a little noise elimination, which increases the accuracy of the matching module.
Algorithm: Improving Fingerprint Verification Using Minutiae Triplets.
To read more about the matching benchmark, see _doc/
This benchmark uses the same dataset as the one in the Pre-processing section. The program is then challenged:
- Given
$N$ fingerprints. For each fingerprint, find another one that is of a same finger. - Because the project aims at fingerprint recognition, not fingerprint grouping, each comparison must be one-to-one. Thus, for this dataset, there are
$500 \times 499$ comparisons expected.
Again, the program is single-thread, which ensures the average time for each comparison is accurate and reliable. Each comparison is performed one after another. There is no paralleled process.
481 out of 500 given fingerprints successfully found an accurate match. That makes the accuracy of 96.2%, or 3.8% mismatch rate. Here are some of the matches:
- Executed
$500 \times 499 = 249500$ comparisons:$37.738$ s - Average
$0.1512 \times 10^{-3}$ s, or$0.1512$ ms per comparison - Speed:
$6611.37$ comparisons/s
Which sucks, tbh.
Because I haven't made a cli yet, just edit Program.cs
for the time being.
For example:
// create a new Util.PreprocessingMultithread.Processor object
Processor proc = new();
// load a fingerprint image
Image<Gray, byte> src = new("fingerprint-image.png");
// process it
proc.Process(src);
// export the fingerprint's skeleton
CvInvoke.Imwrite("skeleton.png", MatConverter.Bool2Img(proc.SkeletonMat));
// export the fingerprint's minutiae
proc.PrepareForExtraction();
MinutiaeExtractor.ExtractAndExport("data-1.inp", proc.SkeletonMat, proc.SegmentMsk);
// load fingerprint's data & match them
Fingerprint probe = new("data-1.inp");
Fingerprint candidate = new("data-2.inp");
Console.WriteLine(Matcher.Match(probe, candidate)); // can be visualized via Matcher.DebugMatch(probe, candidate, probeMatchResult, candidateMatchResult)
If you're really into the source code, here's the hierarchy:
./Algorithm
: Algorithms for general purposes../DataStructure
: Data Structures for general purposes../MatTool
: Classes that handle operations on matrices. Providing 2D Forward Loops, mathematic operators on matrices, matrix converters and more../Util
: Classes that are specialized in processing Fingerprint and Fingerprint only. Currently includes:./Util/Comparator
: Compare fingerprints./Util/FeaturesExtractor
: Extract minutiae from skeleton images./Util/Preprocessing
: Pre-process the input images into ridges' skeleton
./_doc
: Document files
Regardless, this project's implementations and the algorithms behind them are absolutely incomprehensible to anyone without documentation (except me, ofc). Therefore, I'll try to write as many docs as I can to explain my code, I promise.