Algorithm transparency

Algorithm transparency in SourceAFIS is an API that lets applications capture all intermediate data structures that are created during feature extraction and matching, including images in various stages of filtering, extracted minutiae and ridges, pairing tree constructed by matcher, and score breakdown. Learning basics of how the algorithm works is recommended before using transparency API.

Why?

The simple API exposed by SourceAFIS is generally an advantage, because the job of SourceAFIS is to abstract away details of fingerprint matching. There are however occasions when seeing what the algorithm is doing is beneficial. Specifically, algorithm transparency can be used to:

Transparency data is also used internally to ensure consistency of language ports of SourceAFIS and to perform basic sanity checks in unit tests.

Algorithm transparency is rare in commercial matchers, becasue it weakens intellectual property protection. SourceAFIS, being fully opensource, doesn't need to hide anything from you. Algorithm transparency is its unique advantage.

Standard API data

Transparency data does not include data that is available in some other way. Specifically, it excludes the original fingerprint image, source string during deserialization, source byte array during ISO 19794-2 template import, the resulting template (which is documented elsewhere), and score.

Full log

The simplest way to obtain transparency data is to ask SourceAFIS for a transparency ZIP file. The following example logs data from feature extraction, matcher initialization, and a single match.

FingerprintTemplate candidate = ...;
byte[] probeImage = ...;

try (
    OutputStream stream = new FileOutputStream("transparency.zip");
    FingerprintTransparency transparency = FingerprintTransparency.zip(stream)
) {
    FingerprintTemplate probe = new FingerprintTemplate()
        .transparency(transparency)
        .dpi(500)
        .create(probeImage);
    new FingerprintMatcher()
        .transparency(transparency)
        .index(probe)
        .match(candidate);
}

See: FingerprintTransparency.zip() (Java)

This will create file transparency.zip populated by numerous JSON and binary data files. You can customize what gets logged by adding or removing method calls inside the try block.

Zip contents

List of files in the generated transparency.zip is shown below. Files named pairing and score appear multiple times, each containing different minutia pairing. Some of these repeats have been omitted from the list. Click on any file group to learn about its format.

001-decoded-image.json
002-decoded-image.dat
003-scaled-image.json
004-scaled-image.dat
005-block-map.json
006-histogram.json
007-histogram.dat
008-smoothed-histogram.json
009-smoothed-histogram.dat
010-clipped-contrast.json
011-clipped-contrast.dat
012-absolute-contrast-mask.json
013-absolute-contrast-mask.dat
014-relative-contrast-mask.json
015-relative-contrast-mask.dat
016-combined-mask.json
017-combined-mask.dat
018-filtered-mask.json
019-filtered-mask.dat
020-equalized-image.json
021-equalized-image.dat
022-pixelwise-orientation.json
023-pixelwise-orientation.dat
024-block-orientation.json
025-block-orientation.dat
026-smoothed-orientation.json
027-smoothed-orientation.dat
028-parallel-smoothing.json
029-parallel-smoothing.dat
030-orthogonal-smoothing.json
031-orthogonal-smoothing.dat
032-binarized-image.json
033-binarized-image.dat
034-filtered-binary-image.json
035-filtered-binary-image.dat
036-pixel-mask.json
037-pixel-mask.dat
038-inner-mask.json
039-inner-mask.dat
040-ridges-binarized-skeleton.json
041-ridges-binarized-skeleton.dat
042-ridges-thinned-skeleton.json
043-ridges-thinned-skeleton.dat
044-ridges-traced-skeleton.json
045-ridges-traced-skeleton.dat
046-ridges-removed-dots.json
047-ridges-removed-dots.dat
048-ridges-removed-pores.json
049-ridges-removed-pores.dat
050-ridges-removed-gaps.json
051-ridges-removed-gaps.dat
052-ridges-removed-tails.json
053-ridges-removed-tails.dat
054-ridges-removed-fragments.json
055-ridges-removed-fragments.dat
056-valleys-binarized-skeleton.json
057-valleys-binarized-skeleton.dat
058-valleys-thinned-skeleton.json
059-valleys-thinned-skeleton.dat
060-valleys-traced-skeleton.json
061-valleys-traced-skeleton.dat
062-valleys-removed-dots.json
063-valleys-removed-dots.dat
064-valleys-removed-pores.json
065-valleys-removed-pores.dat
066-valleys-removed-gaps.json
067-valleys-removed-gaps.dat
068-valleys-removed-tails.json
069-valleys-removed-tails.dat
070-valleys-removed-fragments.json
071-valleys-removed-fragments.dat
072-skeleton-minutiae.json
073-inner-minutiae.json
074-removed-minutia-clouds.json
075-top-minutiae.json
076-shuffled-minutiae.json
077-edge-table.json
078-edge-hash.dat
079-root-pairs.json
080-pairing.json
081-score.json
082-pairing.json
083-score.json
... skipped 96 files ...
180-pairing.json
181-score.json
182-pairing.json
183-score.json
184-best-match.json

Selective logging

ZIP file might be easy to generate and examine by hand, but most use cases for transparency API require programmatic access to data. While you could save the ZIP file and then load parts of it, it is easier and more performant to define your own FingerprintTransparency implementation like in this example.

// extend class FingerprintTransparency and define log() method
class TransparencyContents extends FingerprintTransparency {
    @Override protected void log(String keyword, Map<String, Supplier<ByteBuffer>> data) {
        for (String suffix : data.keySet()) {
            ByteBuffer content = data.get(suffix).get();
            out.printf("%,9d B  %-6s %s\n", content.remaining(), suffix, keyword);
        }
    }
}

FingerprintTemplate candidate = ...;
byte[] probeImage = ...;

// use the newly defined logging class to capture data
TransparencyContents transparency = new TransparencyContents();
FingerprintTemplate probe = new FingerprintTemplate()
    .transparency(transparency)
    .dpi(500)
    .create(probeImage);
new FingerprintMatcher()
    .transparency(transparency)
    .index(probe)
    .match(candidate);

See: FingerprintTransparency.log(String,Map) (Java)

This should result in the following output. You can see the data is more structured. While this example just reports data length, it does load all serialized data into the content variable, ready to be parsed. Data is passed to the logger in the exact order in which file entries appear in the ZIP file above.

1,160,896 B  .dat   decoded-image
      161 B  .json  decoded-image
1,160,896 B  .dat   scaled-image
      161 B  .json  scaled-image
    1,518 B  .json  block-map
  665,600 B  .dat   histogram
      175 B  .json  histogram
          .   .     .
          .   .     .
          .   .     .
   13,514 B  .json  pairing
      590 B  .json  score
       87 B  .json  pairing
      555 B  .json  score
   17,579 B  .json  pairing
      593 B  .json  score
       17 B  .json  best-match

If you don't pull content from the Supplier, it will never get constructed. This lets you access algorithm transparency data with minimal overhead, picking only data you actually need.

Deserialization and ISO template data

Above examples capture the primary workflow of feature extraction and matching. It is also possible to collect transparency data from secondary workflows, specifically template deserialization and ISO 19794-2 template import.

FingerprintTemplate template = ...;
String json = template.toJson();
byte[] isoTemplate = ...;

try (
    OutputStream stream = new FileOutputStream("transparency-deserialized.zip");
    FingerprintTransparency transparency = FingerprintTransparency.zip(stream)
) {
    FingerprintTemplate deserialized = new FingerprintTemplate()
        .transparency(transparency)
        .deserialize(json);
}

try (
    OutputStream stream = new FileOutputStream("transparency-iso.zip");
    FingerprintTransparency transparency = FingerprintTransparency.zip(stream)
) {
    FingerprintTemplate converted = new FingerprintTemplate()
        .transparency(transparency)
        .convert(isoTemplate);
}

The first logging block will produce archive transparency-deserialized.zip with the following contents.

Import of ISO 19794-2 template in the second block will produce archive transparency-iso.zip with the following data.