The library for applicant enrollment. The main purpose is to process images of print, iris, face modalities in various formats and create Applicant object suitable for further processing. The library provides following features to create Applicant:
Some features of library can be extended/adapted to user needs via implementation of provided interfaces of features. All available interfaces that can be used to customize are described in Extending SDK.
The processor MUST support the AVX2 instruction set.
The system architecture MUST be x86_64 (64-bit) or x86 (32-bit).
Note
In the case of x86 (32-bit) architecture, the Iris, Face and Print Embedding functionalities are NOT supported.
Android
The Android version MUST be 5.0 or higher, which corresponds to API level 21.
Installation
We provide isolated installation. All necessary shared libraries are installed with Enrollment SDK. The libraries are available only for Enrollment SDK and do not influence other SDKs. Also other SDKs do not influence Enrollment SDK installation.
We provide more variants of Enrollment SDK. Only one variant can be installed on device/PC. It is ensured by installation process.
Reducing installation size
The Enrollment SDK installation package includes large binary files *.solver, *.nnkitsolver that can be removed if they are not in use. For more details, refer to section Solvers.
Linux
Isolated installation
We use rpath to isolate Enrollment SDK.
The RPM installation uses ldconfig to add installed library into cache that is used by the run-time linker, ld.so or ld-linux.so.
Variant
On Linux package name is different between SDK variants. The variant is part of package name. In rpm specification file all variants provide the same name on which they all conflict. It ensures that only one variant can be installed in system. The maintainer MUST manually uninstall previous variant when he/she needs to install other one. The same variant can be updated without problem.
Let assume that maintainer already installed Enrollment SDK in DEV variant with command
yum install innovatrics-enrollment-sdk-dev
and he/she needs to install other variant, general one
yum install innovatrics-enrollment-sdk
then yum will report error
Error: innovatrics-enrollment-sdk conflicts with innovatrics-enrollment-sdk-dev-7.0.3-1.el7.x86_64
Error: innovatrics-enrollment-sdk-dev conflicts with innovatrics-enrollment-sdk-7.0.3-1.el7.x86_64
to fix error maintainer MUST remove previous variant manually
Then installation bin folder is added to PATH environment variable for x86_64 build. The x86 does not modify the PATH variable to not influence x86_64 windows applications. The x86_64 installation creates also INNO_ENROLLMENT_HOME variable and sets its value to installation folder. The x86 installation creates INNO_ENROLLMENT_32_HOME variable and sets its value to installation folder.
Variant
On Widows all variants have same GUID. Windows installer will ensure that only one installation is presented on system.
Initialization
The Enrollment SDK initialization can be
automatic
manual
Once automatic initialization is applied then manual initialization is not possible. Automatic initialization is done on library load when all prerequisites are fulfilled
solvers (neural network models) exist at iface/models next to the loaded library; see Solvers for package layout and discovery
To suppress automatic initialization even if all prerequisites are satisfied set INNO_ENROLLMENT_SDK_MANUAL_INITIALIZATION to one of these case-insensitive values: 1, true, on, manual, enable, enabled before your application starts.
It is uncommon for all prerequisites to be fulfilled at application startup on Android. However, if this is your use case, you can suppress automatic initialization by calling:
A valid reason to disable automatic initialization is to gain full control over when the Enrollment SDK is initialized. This allows you to provide a custom configuration instead of relying on the default configuration used during automatic initialization.
By default, the Enrollment SDK initializes itself automatically when the shared library is loaded.
If you need to control OpenCV or ONNX Runtime thread counts before the SDK loads its models, suppress auto-init and explicitly initialize the SDK with a custom configuration. Automatic initialization may not be suitable when some prerequisites are unavailable at startup or when full control over the SDK configuration is required. In such cases, initialize the SDK explicitly using either Initialize(std::vector<uint8_t> license, std::string modelsPath) or Initialize(const InitializerConfig& config). The initialization functions can only be called once during the lifetime of the process. The Enrollment SDK also provides the helper functions DefaultModelsDirectory() and FindLicenseFile(), which can be used to populate the default paths in the initialization configuration.
For Java-specific initialization requirements (loading native libraries before any SDK call), see the initialization section of the Java binding documentation.
c++
constauto cfg = inno::InitializerConfigBuilder()
.SetLicensePath(inno::FindLicenseFile())
.SetModelsPath(inno::DefaultModelsDirectory())
.SetFaceIrisOpencvThreads(4)
.SetFaceIrisOrtIntraThreads(4)
.SetFaceIrisOrtInterThreads(1)
.Build();
inno::Initialize(cfg);
// SDK is now fully initialised with the requested thread counts.
// Proceed with normal face / iris / fingerprint operations.
java
EnrollmentInitializer.LoadNativeLibrary(
()
-> new InitializerConfigBuilder()
.SetLicensePath(enrollment.FindLicenseFile())
.SetModelsPath(
enrollment.DefaultModelsDirectory())
.SetFaceIrisOpencvThreads(4)
.SetFaceIrisOrtIntraThreads(4)
.SetFaceIrisOrtInterThreads(1)
.Build());
// SDK is now fully initialized with the requested thread counts.
// Proceed with normal face / iris / fingerprint operations.
csharp
using (var builder = new InitializerConfigBuilder())
// SDK is now fully initialised with the requested thread counts.
// Proceed with normal face / iris / fingerprint operations.
Licensing
The license file iengine.lic prerequisite must be added into one of following directories to be possible to initialize SDK on load time:
Linux
Per Application: current working directory
Per User:~/.innovatrics/
Per System:/etc/innovatrics/
Windows
Per Application: current working directory
Per User:%LOCALAPPDATA%/Innovatrics/
Per System:C:/ProgramData/Innovatrics/
The search follows this priority:
Application directory
User directory
System directory
Otherwise user MUST provide content of license via function Initialize(). The HWID for generating license can be obtained by SDK function HardwareID().
Dongle license
If you are using dongle-based licensing, you will receive a license file that is paired with one or more dongles.
The dongle must be connected before starting the application or calling the Initialize() function. It must remain connected throughout the entire runtime of the application.
var printImg = Image.Decode(BinaryFile.ReadAll("assets/finger.png"));
var print = new Print(printImg, PrintPosition.LEFT_INDEX);
var extractor = new ICSExtractor();
var extractedPrint = extractor.Extract(print);
var faceImg = Image.Decode(BinaryFile.ReadAll("assets/faces.png"));
var faceCapture = new FaceCapture(faceImg);
var faceDetector = new FaceDetector();
var face = faceCapture.DetectWith(faceDetector)[0];
var extractedFace = face.Extract();
var irisImg = Image.Decode(BinaryFile.ReadAll("assets/eye_L.png"));
var irisCapture = new IrisCapture(irisImg, IrisPosition.LEFT_EYE);
var irisDetector = new IrisDetector();
var irisSegment = irisCapture.DetectWith(irisDetector);
var extractedIris = irisSegment.iris.Extract();
var probe = new Applicant();
probe.AddPrint(extractedPrint);
probe.AddFace(extractedFace);
probe.AddIris(extractedIris);
var gallery = new Applicant();
gallery.AddPrint(extractedPrint);
gallery.AddFace(extractedFace);
gallery.AddIris(extractedIris);
var matcher = new ModalitiesVerifyMatcher();
var scores = probe.SimilarWith(gallery, matcher);
System.Console.WriteLine(" prints " + scores.GetPrintScore() + ", faces " +
scores.GetFaceScore() + ", irises " +
scores.GetIrisScore());
Store,Load Applicant biometrics representations
Any type of biometric representation does not contains images or other attributes of applicant such as qualities.
Note
It is recommend also to store images for Applicant to be possible to re-extract biometric data when better extractors (by means of speed/accuracy) will be provided.
Modalities ICS Template
It is possible to convert Applicant to ModalitiesICSTemplate. It contains all modalities templates gathered during Applicant enrollment. It can be stored and loaded to be able to use biometric representation of enrolled applicant for print verification or for getting information about minutiae in the future.
Note
ICS Template does not contains even position of fingers/irises templates and it is not possible to use it for multi verification. It is recommend to save position together with template. Or you can use ModalitiesTemplate.
new ModalitiesICSTemplate(BinaryFile.ReadAll("output/applicant.ics"));
Modalities Template
It is possible to convert Applicant to ModalitiesTemplate. It can be stored and loaded to be able to use enrolled applicants biometric representation for any sdk operations including Identification. It contains all modalities templates gathered during Applicant enrollment. The differences against Modalities ICS Template are:
It contains also positions of fingers/irises templates.
The extraction is transformation of biometric sample into template suitable for further processing e.g. Verification, Identification. The library provides extraction for
The table below lists the enrollment SDK versions and their corresponding template versions. Use this table to determine template compatibility for Verification and Identification according to the rules described in Template Compatibility Rules.
Enrollment SDK versions up to and including 27.4.1
Face templates generated in different modes (Fast / Balanced / Accurate) are not mutually compatible. Templates can be used for verification and identification only if they have the same template version.
Enrollment SDK version 27.5.0 and later
Face templates generated in Fast / Balanced / Accurate modes are mutually compatible and can be used interchangeably for verification and identification.
Although each mode produces a different template version number, these templates belong to the same compatibility group and can be matched together.
This compatibility remains valid across different enrollment SDK versions, as long as they produce templates belonging to the same compatibility group.
If a future enrollment SDK version introduces a new compatibility group, templates from that group are mutually compatible with each other, but not compatible with templates from previous compatibility groups.
Print Templates
Print modality templates can be used for verification or identification only if they have the same template version. No cross-version compatibility is supported for print templates.
Verification
1 to 1 Verification
The library compares biometric samples of each modality and calculates their similarity scores. The result of verification is similarity score. The library provides verification for
print - print templates on same biometric position in probe and gallery are compared with each other. The provided score is average of maximal score per biometric position. A template can have also unknown position e.g when it was loaded with no biometric position info. The unknown position is treated as special biometric position. When the probe template has unknown position it is compared with all gallery templates. When the gallery template has unknown position then each probe template with any position is compared against this template.
face - each probe face template is compared with each gallery face template. The maximal score of all scores is provided.
iris - the calculation is same as print calculation.
The number of references in any IndexedModalitiesGallery is limited by license. You can have more created galleries in your code. The number limits overall references in all galleries.
Adding data to the gallery can be faster in higher-level language bindings and consumes less memory, as only the essential identification data is stored compared to ModalitiesGallery. However, the user must maintain a mapping between their reference representation and the identifier provided to IndexedModalitiesGallery::Add().
// Create type that holds all necessary information for consolidation.
var consolidationCandidates = new ModalitiesGallery.ModalitiesCandidates(
printCandidates, new List<ModalitiesGalleryReference>(),
new List<ModalitiesGalleryReference>(), probe);
// Consolidate
var candidates = ModalitiesGallery.Consolidate(consolidationCandidates, 2);
// Print result
foreach (ModalitiesGallery.Candidate c in candidates)
{
System.Console.WriteLine(" Id is " + c.GetCandidate().GetIndex() +
" score is [" + c.GetScore().GetPrintScore() +
", " + c.GetScore().GetFaceScore() + ", " +
c.GetScore().GetIrisScore() + "]");
}
ModalitiesGallery
Note
The number of references in any ModalitiesGallery is limited by license. You can have more created galleries in your code. The number limits overall references in all galleries.
The ModalitiesGallery stores ModalitiesGalleryReference objects for later identification. Adding data to this gallery in higher-level language bindings is less efficient than in IndexedModalitiesGallery. This inefficiency arises because it creates objects derived from C++ interfaces while also maintaining references to the original high-level language objects.
These high-level language references are necessary because objects returned from the C++ implementation lose their original type information. To address this, the gallery remaps types based on the ID from ModalitiesGalleryReference. However, this approach consumes more memory, as it stores both the identification related data and a reference to the user object.
Despite the increased memory usage, this gallery is more convenient to use as IndexedModalitiesGallery. Since the entire user object is stored within the gallery, users do not need to manually map objects to their identifiers in their code or reload ModalitiesTemplate for consolidation. However, users should be mindful of their object size. The object itself is not required for IdentifyModalities, only the Index and ModalitiesTemplate provided by ModalitiesGalleryReference are used. The relevant identification data is copied from ModalitiesTemplate.
var maxCandidates = 2U; // size of result set of candidates
var result = gallery.Identify(johnTemplate, maxCandidates);
// Output identification results.
foreach (ModalitiesGallery.Candidate c in result)
{
var user = c.GetCandidate() as UserType;
System.Console.WriteLine(" Name is " + user.name + " score is [" +
c.GetScore().GetPrintScore() + ", " +
c.GetScore().GetFaceScore() + ", " +
c.GetScore().GetIrisScore() + "]");
}
Similarity Score
Due to variations in positioning, deformations, lighting conditions, sensor characteristics, and biometric-specific factors such as facial expressions, eye occlusion, finger humidity, or random noise, it is impossible for two biometric samples of the same person, acquired in different sessions, to match exactly. To address this, a matching algorithm calculates a global similarity score between two biometric samples. This similarity score is then compared to a predefined similarity threshold. If the similarity score exceeds the threshold, the system considers the two samples to be from the same individual. However, biometric systems are not perfect, and matching results can sometimes be incorrect. The two primary system errors are measured in terms of:
FAR (False Acceptance Rate) - The frequency of fraudulent accesses due to impostors claiming a false identity
FRR (False Rejection Rate) - The frequency of rejections relative to people who should be correctly verified
FAR and FRR depend on the similarity threshold, which is set to obtain the desired security level. FAR and FRR are strictly related to each other. More precisely, FRR is an increasing function of the similarity threshold and FAR is a decreasing function of the similarity threshold. If the similarity threshold setting is increased to make it harder for impostors to gain access (lower FAR), some authorized people may find it harder to gain access (higher FRR).
FAR/FRR
The range of returned similarity scores is from 0 (no similarity) to 1000 (highest similarity) for print and iris modality templates, and from 0 to 100 for face templates (see Modality Similarity Score). The correspondence between biometric templates is generally indicated by similarity scores greater than a default similarity threshold, which varies by modality (e.g., 40 for prints, which roughly corresponds to FAR = 10^-4). For more information, please refer to FAR and Threshold (see False Acceptance Rate).
Modality Similarity Score
Each biometric modality has its own similarity score scale and progression characteristics:
Score is 0-1000 where 1000 represents most similar templates.
The correspondence between print templates is generally reflected by similarity scores greater than default similarity threshold (40). For more information please refer to FAR and Threshold (see False Acceptance Rate). Default similarity threshold value (40) roughly corresponds to FAR=10^-4. Depending on the type of scanner, the size of print images, the size of the database and the desired security level of your application, you may need to select a different threshold.
Score is 0-1000 where 1000 represents most similar templates.
Scores in range <0, 60> are computed based on FAR analysis. Scores above this range are approximated with linear slope to 1000. Therefore very similar irises can have matching score near maximal 1000.
Score is 0-100 where 100 represents most similar templates.
When the matching score is higher then certain score threshold then the face images belongs to the same person with high probability. The matching score range is <0, 100>. Its values can be interpreted as follows:
Low values of the score, i.e. range <0, 60>, are normalized using FAR values and this formula score_L=-10*log(FAR). It means that score 30 is related to FAR=1:1000=10^-3, score 50 is related to FAR=1:100000=10^-5 (evaluated on our large testing non-matching pairs dataset).
High values of the score, i.e. range <80, 100>, are normalized using FRR values and this formula score_H=100/3*(FRR + 2). It means that score 80 is related to FRR=0.4, score 90 is related to FRR=0.7 (evaluated on our large testing matching pairs dataset).
Scores values in range (60, 80) are weighted average of score_L and score_H. This normalization help the users to select the score threshold according their needs. If it is too low e.g. score threshold is 30, then the chance of false accepted non-matching faces is quite high (FAR=10^-3). When it is too high e.g. score threshold is 90, then the chance of false rejected matching faces is quite high (FRR=0.7). For face recognition following recommendations are given:
minimum face size - inter eye-pupils distance at least 40 pix
optimal face size - inter eye-pupils distance at least 100 pix
optimal image - sharp, contrast, frontal facial image with standard lighting conditions
the more similar are conditions when the matched faces are captured the higher is the matching accuracy
complex robust feature extraction invariant to partial faces occlusions / poor lighting / blurriness / etc is done. So, no further preprocessing is necessary.
False Acceptance Rate (FAR) describes probability at which matching algorithm makes false acceptance errors. Similarity scores returned by this library are normalized. More precisely, approximate relationship between similarity score and False Acceptance Rate (sometimes called also False Match Rate) is given by the following formula:
\( similarity score = -10 * \log_{10} (FAR) \)
Please note that the normalization formula is only approximation. Score distribution can vary depending on various factors such as scanner surface area, finger placement, finger quality, finger positions (index fingers tend to give higher scores compared to little fingers, etc..)
Note
False Acceptance Rate (FAR) is one of several accuracy ratings that can be calculated for matching algorithm. False acceptance error is when matching algorithm identifies matching print in database for some probe print even though the two prints do not belong to the same person. FAR depends predominantly on the threshold selected. Increasing threshold reduces FAR, but it can also increase FRR see Similarity Scores. FAR is influenced by quality of the database being searched and quality of the probe print.
False Rejection Rate
FRR describes probability at which matching algorithm makes false rejection errors.
Note
False Rejection Rate (FRR) is one of several accuracy ratings that can be calculated for matching algorithm. False rejection error is when matching algorithm fails to identify a probe user (print, face or iris) in database even though the database contains user with biometric data (print, face or iris) of the same person. FRR primarily depends on quality of the database being searched and quality of probe biometric data. FRR is somewhat influenced by threshold. Decreasing threshold reduces FRR, but it can increase FAR significantly.
Similarity Threshold
Similarity threshold defines minimum similarity score that is considered a match.
Note
While similarity score provides degree of certainty information that is in line with probabilistic algorithms of biometrics, most applications eventually have to decide whether particular similarity score means a match or not. Similarity threshold is used to divide the similarity spectrum into matching and non-matching range. Default threshold setting is suitable for most applications. You can adjust the threshold to control FAR and FRR. There is an approximate mapping between FAR and threshold (see False Acceptance Rate).
Quality
The library provides fingerprint/iris/face qualities for evaluation of a image whether is suitable for further processing.
The SDK can use provided server to execute its functionality. To use server you need to run server enrolment_server endpoint e.g. enrollment_server 127.0.0.1:50051. Then it is necessary to use server executor in appropriate classes or setup global executor.
Example of usage server executor in class constructor:
c++
auto img = Image::Decode(BinaryFile::ReadAll("assets/face.png"));
The library is has header part and binary part. The interface to binary is "C" due to better compatibility across different compilers. The headers forwards functionality to binary, when we need to hide implementation details. The interface between headers and binary can be
functions
primitive data types and its pointers
plain old structures with pragma pack 1 for compatibility between binary and compiled client code. We do not know what pragma pack is used/available in client compiler. We use 1 that is implemented in each compiler and architecture even if it is not optimal.
We are using C++20 standard. In binary part the pointer to implementation is casted to appropriate objects, and we can work with inheritance. The header part is used only to define API and transform error to exceptions.
The disadvantage is that we need copy data created in binary into vector to use safe containers. Later we can implement something similar to std::span or std::string_view.
C++
We use SWIG tool code generator to convert C++ classes into Java / C# classes.
We can write safe library due to containers, smart pointers and RAII principle.
We use open/closed principle to extend our library with client implementation e.g logging, serialization.
Disadvantage
Creating a library with a C++ interface is not feasible due to complications with the STL, #pragma pack directives, and various other issues. Therefore, we use a "C" interface for the library.
The C wrapper MUST be implemented when we will need some other language as Java / C#
It is not possible to use multiple interface inheritance, because swig implements interfaces as usual implementation classes due to director feature. Then Ruby and C# are not able to inherit multiple implementation classes.
It is not possible to create nested classes, because SWIG does not support it for Ruby
Quality
To achieve better quality we use
clang-format for formatting code
clang-tidy for static analysis
clang sanitizers for dynamic analysis
address sanitizer for detecting memory leaks and overflows
memory sanitizer for detecting use of unutilized memory
thread sanitizer for detecting race conditions
undefined sanitizer for detecting undefined behavior
valgrind for unit, integration tests, and c++ example application
ABI compliance checker to know impact of our changes regarding to previous SDK versions.
unit tests with Google test framework
warnings are set to the strictest level and treated as error
CI pipeline for various architectures
accurate documentation generated by doxygen
C++ because of automatic memory management using smart pointers and RAII idiom
Extending SDK
The SDK can be extended by implementation of provided interfaces. See Extending SDK for list of customizable interfaces.