A while ago, I posted some pretty pictures of my toe when I figured out the image format used by the Digital Persona and Microsoft fingerprint readers.
While it’s pretty cool to see your fingerprint on-screen, the real question is how do we make use of these prints? We need a way of storing fingerprints, and a way of saying “does this fingerprint equal the one we stored earlier?” From that point, we can implement fingerprint-based login and other things.
There are various open-source projects aiming to do this kind of thing, I made a list of them here. Unfortunately all of them appear to be dead projects and most of them aren’t useful at all, but I’ve made progress with one of them at least: FVS.
There are various different algorithms which can be used to compare fingerprints. I’ll try to describe the method used by FVS: minutiae detection.
A fingerprint is made up of ridges, basically just the curvy lines which you see. Ridges start and finish, and some of them split (bifurcate) into 2 other ridges. The points where ridge endings and bifurcations happen are known as minutiae. We can compare the positions and directions of the minutiae on two fingerprint images to decide whether they are equal. This is certainly throwing a lot of information away, but this method is very widely used in the fingerprint recognition world.
We start with the initial toe-print. I actually cheated by subtracting an image seen by the sensor before I scanned my toe from the toe-print, so what you can see below is slightly enhanced (clearer) than the original image.
The ridges of the fingerprint are visible above in white. The enhancement step involves finding the ridge direction and the ridge frequency. These details can then be used to apply a Gabor filter to the image, which produces a greatly enhanced version:
The above enhancement takes a few seconds on my system. This is OK for prototyping but is too slow for a real fingerprint login system, I hope we can find ways to optimise this. In addition to the Gabor filter, the image was further enhanced by binarization: all pixels are either black or white, no noise.
The ridges are now shown in black on a white background. The next step is to reduce each ridge line to a single pixel in width. This is known as thinning.
The advantage of thinning is that minutiae are now really easy to detect. We take every pixel on the image, and we ignore it if it is not a ridge (i.e. if it is white). For all the ridge pixels, we count the number of adjacent ridge pixels. If there is only one ridge pixel neighbour, we have found a ridge ending. If there are three ridge pixel neighbours, we have found a bifurcation.
FVS includes minutiae detection code based on the above algorithm:
The code isn’t perfect, as it detected many minutiae around the edge of the fingerprint image, where they do not exist. However it should be relatively simple to exclude those as FVS already knows about the edges of the print.
The next challenge is to compare two minutiae sets and decide how similar they are. FVS includes some code to do this, but it just crashes, and I haven’t spent much time debugging it yet. This is a difficult operation: prints of the same finger are never identical: sometimes some minutiae are not visible, they can be spaced slightly differently, and the finger might even be significantly rotated since the last print.
A project called eFinger has built a complete fingerprint recognition database. It uses FVS’s enhancement code, but ships it’s own code for thinning, minutiae detection, and minutiae set comparison. The code is not brilliant (does not consider rotation or anything like that) but should provide a good starting point.