The library can be used to detect faces from face captures.
Overview
The library can be used to detect faces from face captures. Face capture can contains one or group of people, faces or full body.
Face Detection
SDK can detect faces of various sizes, orientations, facial hair types or ethnicities. Face can be partly occluded by glasses, sunglasses or hat. SDK can operate with many different lighting conditions and image qualities. Face size is defined as a maximum of values of inter eyes centers distance and distance between center of mouth and center point between eyes: face_size = max(distance(left_eye_center, right_eye_center), distance(mouth_center,eyes_center))
Face Size
Image above shows face size visualizations of various distances of inter eyes centers distances (X=distance(left_eye_center,right_eye_center)) and distances between center of mouth and center point between eyes (Y=distance(mouth_center, eyes_center)). The face size is the maximum of these two distances. It can be seen from images (a), (b) and (c) that the face size (red arrow) defined in this way is invariant to pose of the head (yaw, pitch, roll). The face size can be specified in absolute (pixel distance) or relative value (pixel distance) relative to image size (max(image_height, image_width)) and is important parameter for face detection. SDK can detect faces of various size but there is a lower limit of face size. Upper limit on the face size is not defined. The recommended face size is more than 50 pixels. SDK face processing or recognition functions have the most accurate results when this recommendation is fulfilled. Face area is closely related to the face size. It is an area around a face defined by a bounding rectangle with width = 4 x face_size, height = width / 0.75 (according to ISO/IEC 19794-5 standard, section 9.2). The Point which is the geometric center between eyes is positioned in the face area in position X_Pos, Y_Pos, where Y_Pos = 0.6f x width, and X_Pos relies on the head yaw rotation. The main reason for this is to have the whole head in the face area no matter what the head rotation is.
Face Area
Image above shows face area visualizations of face areas (green boxes) for face in various positions. The face size is defined by distance shown as the red arrow. There are shown different positions of face area according to the face yaw rotation in (a),(b) and (c). Positions of the eyes centers in the face areas are the same in the Y direction (Y_Pos) but changes in the X direction (X_Pos1, X_Pos2, X_Pos3). Width and Height is the same in all three cases. The face area size relative to image area size can specify sizes of faces that should be detected.
Face
If image above has resolution of 730x470 pixels (image_area_size = 730 x 470 = 343100) and face_size is 70 pixels (face_area_width = 70 x 4 = 280, face_area_height = face_area_width / 0.75 = 373, face_area_size = 104440), then relative image size is relative_image_size = 104440 / 343100 = 0.304 (30.4%). Face area is marked with green box and face size with red arrow. Sometimes, when faces are close to image boundaries, their face areas can get out of the image boundaries. Some application may want to find these faces (and filter them out). Due to this reason each face has attribute related to face area visible in image (FaceRelativeAreaInImage).
Face area visible in image.
In the image above relative values are (a) 0.30, (b) 0.5, (c) 1
SDK can detect faces of various rotations. However various face detection modes imply different ranges of detectable faces
Possible face rotations (defined as in DIN9300)
Prior to further processing each face in FaceCapture MUST be detected via FaceDetector. SDK provides following detection modes:
- fast
The fastest face detector in combination with the fastest face validators and facial features detectors are used when fast mode is used.
Some faces that are partially occluded faces or faces with sunglasses may be missed. However the speed performance of the face detection is much better as when other modes are used.
- Required Solvers
Total size of solvers is 559 kB.
References face-detector-fast.solver, face-detector-eye-validation.solver, face-detector-landmarks-fast.solver
- accurate_server
- Note
- Not supported in this variant of Enrollment SDK.
Using of different modes can adjust trade-off between speed and accuracy of face detection. Face detection accuracy has two meaning:
- ratio between false accepted faces and false rejected faces.
- precision of facial keypoints detection.
Face Detection
Face
-
c++
auto img =
Image::Decode(BinaryFile::ReadAll(
"assets/face.png"));
auto cfg = FaceDetector::Config{};
FaceDetector fd(cfg);
auto face = fc->DetectWith(fd)[0];
auto cropCfg = FaceCropConfiguration();
auto croppedFace = face->Crop(cropCfg);
if (not croppedFace->IsCropRegionInsideImage())
{
auto resizedCrop = face->Crop(cropCfg);
auto resizedCropRegion =
fc->Draw(resizedCrop->GetCropRectangle(), Shapes::InnoBlue);
resizedCropRegion->SaveAs("output/face_crop_box_resized.png");
}
-
java
Image img = Image.
Decode(BinaryFile.ReadAll(
"assets/face.png"));
FaceCapture capture = new FaceCapture(img);
FaceDetector.Config cfg = FaceDetector.Config.
Default();
FaceDetector detector = new FaceDetector(cfg);
FaceCropConfiguration cropCfg = new FaceCropConfiguration();
CroppedFace croppedFace = face.
Crop(cropCfg);
CroppedFace resizedCrop = face.
Crop(cropCfg);
Image resizedCropRegion = capture.
Draw(
resizedCropRegion.
SaveAs(
"output/face_crop_box_resized.png");
}
-
csharp
Image img = Image.
Decode(BinaryFile.ReadAll(
"assets/face.png"));
FaceCapture capture = new FaceCapture(img);
FaceDetector detector = new FaceDetector();
FaceCropConfiguration cropCfg = new FaceCropConfiguration();
CroppedFace croppedFace = face.
Crop(cropCfg);
{
CroppedFace resizedCrop = face.
Crop(cropCfg);
Image resizedCropRegion =
resizedCropRegion.
SaveAs(
"output/face_crop_box_resized.png");
}
The output of example
Face with crop region outside of image
Face with shrunken crop
Face Detection with various crops
Once a face is detected, a Face object is provided. It is possible to set various crop methods via Face::Crop() method.
-
c++
auto img =
Image::Decode(BinaryFile::ReadAll(
"assets/face.png"));
auto cfg = FaceDetector::Config{};
FaceDetector fd(cfg);
auto face = fc->DetectWith(fd)[0];
FaceCropConfiguration cropCfg;
auto full = face->Crop(cropCfg)->GetFaceCapture();
auto fullNotAligned = face->Crop(cropCfg)->GetFaceCapture();
auto token = face->Crop(cropCfg)->GetFaceCapture();
auto tokenNotFrontal = face->Crop(cropCfg)->GetFaceCapture();
-
java
Image img = Image.
Decode(BinaryFile.ReadAll(
"assets/face.png"));
FaceCapture capture = new FaceCapture(img);
FaceDetector detector = new FaceDetector();
FaceCropConfiguration cropCfg = new FaceCropConfiguration();
FaceCapture full = face.
Crop(cropCfg).GetFaceCapture();
FaceCapture fullNotAligned = face.
Crop(cropCfg).GetFaceCapture();
FaceCapture token = face.
Crop(cropCfg).GetFaceCapture();
FaceCapture tokenNotFrontal = face.
Crop(cropCfg).GetFaceCapture();
-
csharp
var img = Image.
Decode(BinaryFile.ReadAll(
"assets/face.png"));
var capture = new FaceCapture(img);
var detector = new FaceDetector();
var face = capture.DetectWith(detector)[0];
var cropCfg = new FaceCropConfiguration();
cropCfg.SetCropBackground(Colors.InnoBlue);
var full = face.Crop(cropCfg).GetFaceCapture();
cropCfg.SetCropMethod(
FaceCrop.FULL_NOT_ALIGNED);
var fullNotAligned = face.Crop(cropCfg).GetFaceCapture();
var token = face.Crop(cropCfg).GetFaceCapture();
cropCfg.SetCropMethod(
FaceCrop.TOKEN_NOT_FRONTAL);
var tokenNotFrontal = face.Crop(cropCfg).GetFaceCapture();
The output of example
Face with FULL crop configuration
Face with FULL_NOT_ALIGNED crop
Face with TOKEN crop
Face with TOKEN_NOT_FRONTAL crop
Faces Detection
It is possible to detect multiple faces (up to 16) in FaceCapture.
Faces
The faces are detected with function FaceCapture::DetectWith.
-
c++
auto img =
Image::Decode(BinaryFile::ReadAll(
"assets/faces.png"));
FaceDetector fd;
auto faces = fc->DetectWith(fd);
unsigned int index = 0;
for (const auto& face : faces)
{
const std::string name = "output/face_" + std::to_string(index++) + ".png";
face->Crop({})->GetFaceCapture()->image->SaveAs(name);
}
auto boundingBoxes = fc->Draw(faces, Shapes::InnoBlue);
boundingBoxes->SaveAs("output/faces_bounding_boxes.png");
-
java
Image img = Image.
Decode(BinaryFile.ReadAll(
"assets/faces.png"));
FaceCapture capture = new FaceCapture(img);
FaceDetector detector = new FaceDetector();
int index = 0;
for (Face face : faces) {
face.
Crop(
new FaceCropConfiguration())
.GetFaceCapture()
.getImage()
.SaveAs("output/face_" + index + ".png");
index++;
}
Image boundingBoxes = capture.
Draw(faces, Shapes.InnoBlue);
boundingBoxes.
SaveAs(
"output/faces_bounding_boxes.png");
-
csharp
Image img = Image.
Decode(BinaryFile.ReadAll(
"assets/faces.png"));
FaceCapture capture = new FaceCapture(img);
FaceDetector detector = new FaceDetector();
int index = 0;
foreach (Face face in faces)
{
face.
Crop(
new FaceCropConfiguration())
.GetFaceCapture()
.image.SaveAs("output/face_" + index + ".png");
index++;
}
Image boundingBoxes = capture.
Draw(faces, Shapes.InnoBlue);
boundingBoxes.
SaveAs(
"output/faces_bounding_boxes.png");
The output of example are detected faces
Detect Faces
and unique faces
Detected face 1
Detected face 2
Detected face 3
Detected face 4
Extraction
We provide Internal Innovatrics template for Face. The main goal is to create template for further processing e.g. 1:1 Verification.
-
c++
auto img =
Image::Decode(BinaryFile::ReadAll(
"assets/face.png"));
FaceDetector fd;
auto face = fc->DetectWith(fd)[0];
auto faceTemplate = face->Extract(cfg);
BinaryFile::WriteAll("output/face.ics", faceTemplate->data);
std::cout << " Template Version: " << faceTemplate->GetVersion() << std::endl;
-
java
Image img = Image.
Decode(BinaryFile.ReadAll(
"assets/face.png"));
FaceCapture fc = new FaceCapture(img);
FaceDetector fd = new FaceDetector();
FaceExtractorConfig cfg = FaceExtractorConfig.
Default();
ExtractedFace faceTemplate = face.
Extract(cfg);
BinaryFile.WriteAll("output/face.ics", faceTemplate.getData());
System.out.println(
" Template Version: " + faceTemplate.
GetVersion());
-
csharp
Image img = Image.Decode(BinaryFile.ReadAll("assets/face.png"));
FaceCapture fc = new FaceCapture(img);
FaceDetector fd = new FaceDetector();
FaceExtractorConfig cfg = FaceExtractorConfig.
Default();
ExtractedFace faceTemplate = face.
Extract(cfg);
BinaryFile.WriteAll(
"output/face.ics", faceTemplate.
data);
System.Console.WriteLine(
" Template Version: " + faceTemplate.
GetVersion());
1 to 1 Verification
We provide verification of face templates. The main goal is to calculate Similarity Score for given probe and gallery templates. The examples uses same image for probe and gallery
Face
-
c++
auto img =
Image::Decode(BinaryFile::ReadAll(
"assets/face.png"));
FaceDetector fd;
auto face = fc->DetectWith(fd)[0];
auto probe = face->Extract();
auto gallery = face->Extract();
auto score = probe->SimilarWith(*gallery);
std::cout << " Match Score: " << score << std::endl;
-
java
Image img = Image.
Decode(BinaryFile.ReadAll(
"assets/face.png"));
FaceCapture fc = new FaceCapture(img);
FaceDetector fd = new FaceDetector();
ExtractedFace probe = face.
Extract();
ExtractedFace gallery = face.
Extract();
System.out.println(" Match Score: " + score);
-
csharp
Image img = Image.
Decode(BinaryFile.ReadAll(
"assets/face.png"));
FaceCapture fc = new FaceCapture(img);
FaceDetector fd = new FaceDetector();
ExtractedFace probe = face.
Extract();
ExtractedFace gallery = face.
Extract();
System.Console.WriteLine(" Match Score: " + score);
Face Segmentation
It is possible to distinguish face and background once face is detected.
-
c++
auto img =
Image::Decode(BinaryFile::ReadAll(
"assets/face.png"));
const FaceDetector::Config cfg;
FaceDetector fd(cfg);
auto face = fc->DetectWith(fd)[0];
auto cropCfg = FaceCropConfiguration();
auto croppedFace = face->Crop(cropCfg);
auto maskImage = croppedFace->FaceAreaMask();
auto faceSegmentColor = croppedFace->FaceAreaSegment(Colors::InnoBlue.color);
auto faceSegmentTransparent = croppedFace->FaceAreaSegment();
maskImage->SaveAs("output/face_seg_mask.png");
faceSegmentColor->SaveAs("output/face_seg_color.png");
faceSegmentTransparent->SaveAs("output/face_seg_transparent.png");
-
java
Image img = Image.
Decode(BinaryFile.ReadAll(
"assets/face.png"));
FaceCapture capture = new FaceCapture(img);
FaceDetector detector = new FaceDetector();
FaceCropConfiguration cropCfg = new FaceCropConfiguration();
CroppedFace croppedFace = face.
Crop(cropCfg);
Image faceSegmentColor = croppedFace.
FaceAreaSegment(Colors.InnoBlue.getColor());
maskImage.
SaveAs(
"output/face_seg_mask.png");
faceSegmentColor.
SaveAs(
"output/face_seg_color.png");
faceSegmentTransparent.
SaveAs(
"output/face_seg_transparent.png");
-
csharp
Image img = Image.Decode(BinaryFile.ReadAll("assets/face.png"));
FaceCapture capture = new FaceCapture(img);
FaceDetector detector = new FaceDetector();
FaceCropConfiguration cropCfg = new FaceCropConfiguration();
CroppedFace croppedFace = face.
Crop(cropCfg);
Image faceSegmentColor = croppedFace.
FaceAreaSegment(Colors.InnoBlue.color);
maskImage.
SaveAs(
"output/face_seg_mask.png");
faceSegmentColor.
SaveAs(
"output/face_seg_color.png");
faceSegmentTransparent.
SaveAs(
"output/face_seg_transparent.png");
The output of example
Face with colored background
Masked Face
Face with transparent background
Face Attributes
ICAO and face image quality
The International Civil Aviation Organization (ICAO) defines global requirements for facial images used in machine-readable travel documents (MRTDs) in ICAO Doc 9303. These requirements describe how a compliant face image must be captured and presented: frontal pose, neutral expression, proper illumination, uniform background, correct head size and positioning. Compliant images ensure easy use for ID document personalization and good performance in both human verification and computer automated facial recognition.
These ICAO requirements are technically implemented and formalized in:
- ISO/IEC 39794-5 — Face image data format and capture requirements
- ISO/IEC 19794-5 — Legacy face image specifications
- ISO/IEC 29794-5 — Face image quality assessment
ISO/IEC 19794-5 defines four face image types: Basic (record format only), Frontal (with Full Frontal and Token Frontal subtypes), and specifies scene requirements (pose, expression, lighting, background, etc.), photographic requirements (exposure, focus, face position, head size), digital requirements (color profile, resolution, geometry), and format requirements (encoding, compression).
ISO/IEC 29794-5 defines a canonical face image as a face image conformant to an external standard or specification of a reference face image in most civil identity and travel document applications this corresponds to the ISO/IEC 39794-5 portrait specification, which reflects ICAO Doc 9303. [8]
Implementations and rationale
Enrollment provides two implementations for assessing face image quality against ICAO/ISO requirements:
- Innovatrics — proprietary implementation that checks mandatory and best-practice requirements of ICAO Doc 9303 and ISO/IEC 19794-5 for the full frontal face image type, with a rich set of individual attributes.
- OFIQ (Open Face Image Quality) — Implementation recognized by ISO/IEC 29794-5 as the reference for computing face image quality it outputs a unified quality score and standardized quality components.
When compliance with the standard or interchange with other systems is required, prefer OFIQ, as it is officially recognized by ISO/IEC 29794-5. The Innovatrics implementation is well-suited when fine-grained control over individual attributes or integration with other SDK features is needed.
Innovatrics implementation
The SDK (Innovatrics propietary implementation) is able to check all mandatory requirements and best practice recommendations of the ICAO Document 9303 specification and the ISO/IEC 19794-5 standard for the interoperable full frontal face image type, and of other relevant international standards (e.g. ANSI/INCITS 385-2004).
Once face is detected and Face object is provided, it is possible to get Face attributes.
-
Sharpness - Sharpness attribute used to measure the sharpness level of an area of the detected face in the original face capture. See Face::Sharpness for more details.
-
Brightness - Brightness attribute used to measure the brightness level of an area of the detected face in the original face capture. See Face::Brightness for more details.
-
Contrast - Contrast attribute used to measure the contrast level of an area of the detected face in the original face capture. See Face::Contrast for more details.
-
Unique Intensity Levels - Unique Intensity Levels attribute used to measure whether an area of the detected face in the original face capture has an appropriate number of unique intensity levels. See Face::UniqueIntensityLevels for more details.
-
Shadow - Shadow attribute used to evaluate whether an area of the detected face in the original face capture is affected by shadows. See Face::Shadow for more details.
-
Nose Shadow - Nose Shadow attribute for evaluating whether eyes or a nose don't cast sharp shadows. See Face::NoseShadow for more details.
-
Specularity - Specularity attribute used to evaluate the presence of spotlights in an area of the detected face in the original face capture. See Face::Specularity for more details.
-
Right Red Eye - Attribute for evaluating whether red-eye effect is not present on right eye. See Face::RightRedEye for more details.
-
Left Red Eye - Attribute for evaluating whether red-eye effect is not present on left eye. See Face::LeftRedEye for more details.
-
Eye Distance - Attribute used to measure the distance between the eyes in pixels for the detected face in the original face capture. See Face::EyeDistance for more details.
-
Roll Angle - Attribute representing the head rotation angle around the Z-axis of the detected face in the original face capture, relative to the camera reference frame, as per DIN 9300. See Face::RollAngle for more details.
-
Pitch Angle - Attribute representing the head rotation angle around the X-axis of the detected face in the original face capture, relative to the camera reference frame, as per DIN 9300. See Face::PitchAngle for more details.
-
Yaw Angle - Attribute representing the head rotation angle around the Y-axis of the detected face in the original face capture, relative to the camera reference frame, as per DIN 9300. See Face::YawAngle for more details.
-
Face Size - Attribute representing face size - the maximum of eye distance and eye-mouth distance. See Face::FaceSize for more details.
-
Face Relative Area - Attribute representing the area of the detected face in the original face capture relative to the size of the original face capture. See Face::FaceRelativeArea for more details.
-
Face Relative Area In Image - Attribute representing the visible area of the detected face in the original face capture relative to the total face area. See Face::FaceRelativeAreaInImage for more details.
-
Width To Height Ratio Of Image - Attribute representing width to height aspect ratio of the original face capture. See Face::WidthHeightRatio for more details.
-
Tinted Glasses - Attribute for evaluating tinted glasses presence. See Face::TintedGlasses for more details.
-
Gender - Attribute for evaluating gender of subject. See Face::Gender for more details.
-
Eye Gaze - Eye Gaze attribute used to evaluate whether the gaze direction of the detected face in the original face capture is frontal. See Face::EyeGaze for more details.
-
Right Eye Status - Attribute for evaluating right eye status. See Face::RightEyeStatus for more details.
-
Left Eye Status - Attribute for evaluating left eye status. See Face::LeftEyeStatus for more details.
-
Glass Status - Attribute for evaluating glasses presence. See Face::GlassStatus for more details.
-
Heavy Frame - Attribute for evaluating whether glasses with heavy frames are not present. See Face::HeavyFrame for more details.
-
Mouth Status - Attribute for evaluating mouth status. See Face::MouthStatus for more details.
-
Background Uniformity - Attribute used to measure background uniformity in the close area around the detected face in the original face capture. See Face::BackgroundUniformity for more details.
-
Age - Attribute for evaluating age of subject using the face. See Face::Age for more details.
-
c++
std::cout << " Sharpness: " << face->Sharpness() << std::endl;
std::cout << " Brightness: " << face->Brightness() << std::endl;
std::cout << " Contrast: " << face->Contrast() << std::endl;
std::cout << " Unique Intensity Levels: " << face->UniqueIntensityLevels()
<< std::endl;
std::cout << " Shadow: " << face->Shadow() << std::endl;
std::cout << " Nose Shadow: " << face->NoseShadow() << std::endl;
std::cout << " Specularity: " << face->Specularity() << std::endl;
std::cout << " Right Red Eye: " << face->RightRedEye() << std::endl;
std::cout << " Left Red Eye: " << face->LeftRedEye() << std::endl;
std::cout << " Eye Distance: " << face->EyeDistance() << std::endl;
std::cout << " Roll Angle: " << face->RollAngle() << std::endl;
std::cout << " Pitch Angle: " << face->PitchAngle() << std::endl;
std::cout << " Yaw Angle: " << face->YawAngle() << std::endl;
std::cout << " Face Size: " << face->FaceSize() << std::endl;
std::cout << " Face Relative Area: " << face->FaceRelativeArea() << std::endl;
std::cout << " Face Relative Area In Image: " << face->FaceRelativeAreaInImage()
<< std::endl;
std::cout << " Eye Gaze: " << face->EyeGaze() << std::endl;
std::cout << " Right Eye Status: " << face->RightEyeStatus() << std::endl;
std::cout << " Left Eye Status: " << face->LeftEyeStatus() << std::endl;
std::cout << " Glass Status: " << face->GlassStatus() << std::endl;
std::cout << " Heavy Frame: " << face->HeavyFrame() << std::endl;
std::cout << " Mouth Status: " << face->MouthStatus() << std::endl;
std::cout << " Background Uniformity: " << face->BackgroundUniformity(5)
<< std::endl;
std::cout << " Age: " << face->Age() << std::endl;
std::cout << " Gender: " << face->Gender() << std::endl;
std::cout << " Tinted Glasses: " << face->TintedGlasses() << std::endl;
-
java
Face face = faces.get(0);
System.out.println(
" Sharpness: " + face.
Sharpness());
System.out.println(
" Brightness: " + face.
Brightness());
System.out.println(
" Contrast: " + face.
Contrast());
System.out.println(
" Shadow: " + face.
Shadow());
System.out.println(
" Nose Shadow: " + face.
NoseShadow());
System.out.println(
" Specularity: " + face.
Specularity());
System.out.println(
" Right Red Eye: " + face.
RightRedEye());
System.out.println(
" Left Red Eye: " + face.
LeftRedEye());
System.out.println(
" Eye Distance: " + face.
EyeDistance());
System.out.println(
" Roll Angle: " + face.
RollAngle());
System.out.println(
" Pitch Angle: " + face.
PitchAngle());
System.out.println(
" Yaw Angle: " + face.
YawAngle());
System.out.println(
" Face Size: " + face.
FaceSize());
System.out.println(
System.out.println(
" Eye Gaze: " + face.
EyeGaze());
System.out.println(
" Glass Status: " + face.
GlassStatus());
System.out.println(
" Heavy Frame: " + face.
HeavyFrame());
System.out.println(
" Mouth Status: " + face.
MouthStatus());
System.out.println(
System.out.println(
" Age: " + face.
Age());
System.out.println(
" Gender: " + face.
Gender());
-
csharp
Face face = faces[0];
System.Console.WriteLine(
" Sharpness: " + face.
Sharpness());
System.Console.WriteLine(
" Brightness: " + face.
Brightness());
System.Console.WriteLine(
" Contrast: " + face.
Contrast());
System.Console.WriteLine(" Unique Intensity Levels: " +
System.Console.WriteLine(
" Shadow: " + face.
Shadow());
System.Console.WriteLine(
" Nose Shadow: " + face.
NoseShadow());
System.Console.WriteLine(
" Specularity: " + face.
Specularity());
System.Console.WriteLine(
" Right Red Eye: " + face.
RightRedEye());
System.Console.WriteLine(
" Left Red Eye: " + face.
LeftRedEye());
System.Console.WriteLine(
" Eye Distance: " + face.
EyeDistance());
System.Console.WriteLine(
" Roll Angle: " + face.
RollAngle());
System.Console.WriteLine(
" Pitch Angle: " + face.
PitchAngle());
System.Console.WriteLine(
" Yaw Angle: " + face.
YawAngle());
System.Console.WriteLine(
" Face Size: " + face.
FaceSize());
System.Console.WriteLine(" Face Relative Area In Image: " +
System.Console.WriteLine(
" Eye Gaze: " + face.
EyeGaze());
System.Console.WriteLine(
" Right Eye Status: " + face.
RightEyeStatus());
System.Console.WriteLine(
" Left Eye Status: " + face.
LeftEyeStatus());
System.Console.WriteLine(
" Glass Status: " + face.
GlassStatus());
System.Console.WriteLine(
" Heavy Frame: " + face.
HeavyFrame());
System.Console.WriteLine(
" Mouth Status: " + face.
MouthStatus());
System.Console.WriteLine(" Background Uniformity: " +
System.Console.WriteLine(
" Age: " + face.
Age());
System.Console.WriteLine(
" Gender: " + face.
Gender());
System.Console.WriteLine(
" Tinted Glasses: " + face.
TintedGlasses());
OFIQ implementation
ISO/IEC 29794-5 recognizes OFIQ (Open Face Image Quality) as the reference implementation for computing face image quality. [8]
OFIQ computes [8] :
- A Unified Quality Score (QS) in the range 0–100
- Individual quality components, including:
- Head pose (yaw, pitch, roll)
- Head size and image margins
- Inter-eye distance
- Eye visibility and occlusion
- Mouth closed / expression neutrality
- Sharpness and focus
- Illumination uniformity
- Background uniformity
- Exposure control
- Natural colour
- Compression artefacts
The unified quality score predicts the expected recognition performance of a face image under the assumption that it will be compared against a canonical ISO/ICAO-compliant portrait image. When face images are being collected from many biometric capture subjects, the unified quality score and quality components can be aggregated to summarize the effectiveness of the collection (e.g. mean or proportion with low or high value), to reveal site-specific problems or population effects, or as a response variable in A-B tests or trend analysis. [8] Higher scores indicate stronger conformance to ISO/ICAO portrait requirements and higher expected face recognition performance.
-
c++
auto image =
Image::Decode(BinaryFile::ReadAll(
"assets/face.png"));
auto bbImage = faceCapture->Draw(ofiq->GetBoundingBox(), Shapes::InnoBlue);
bbImage->SaveAs("output/ofiq_bounding_box.png");
std::cout << " Sharpness: " << static_cast<int>(ofiq->GetSharpness())
<< std::endl;
std::cout << " UnifiedQualityScore: "
<< static_cast<int>(ofiq->GetUnifiedQualityScore()) << std::endl;
std::cout << " BackgroundUniformity: "
<< static_cast<int>(ofiq->GetBackgroundUniformity()) << std::endl;
-
java
Image img = Image.
Decode(BinaryFile.ReadAll(
"assets/face.png"));
FaceCapture faceCapture = new FaceCapture(img, new FaceAttributes());
OFIQFace ofiq = OFIQFace.
Create(faceCapture);
bbImage.
SaveAs(
"output/ofiq_bounding_box.png");
-
csharp
Image image = Image.
Decode(BinaryFile.ReadAll(
"assets/face.png"));
FaceCapture faceCapture = new FaceCapture(image, new FaceAttributes());
OFIQFace ofiq = OFIQFace.
Create(faceCapture);
bbImage.
SaveAs(
"output/ofiq_bounding_box.png");
System.Console.WriteLine(
" Sharpness: {0}", ofiq.
GetSharpness());
System.Console.WriteLine(" UnifiedQualityScore: {0}",
System.Console.WriteLine(" BackgroundUniformity: {0}",
The detected face by OFIQFace from example
OFIQ face
Keypoints
The Face allows also retrieval of facial keypoints.
-
c++
auto keypoints = face->GetKeypoints();
DotsShape dots;
dots.Add(keypoints->RightEyeOuterCorner());
dots.Add(keypoints->RightEyeCentre());
dots.Add(keypoints->RightEyeInnerCorner());
dots.Add(keypoints->LeftEyeInnerCorner());
dots.Add(keypoints->LeftEyeCentre());
dots.Add(keypoints->LeftEyeOuterCorner());
dots.Add(keypoints->NoseRoot());
dots.Add(keypoints->NoseRightBottom());
dots.Add(keypoints->NoseTip());
dots.Add(keypoints->NoseLeftBottom());
dots.Add(keypoints->NoseBottom());
dots.Add(keypoints->MouthRightCorner());
dots.Add(keypoints->MouthCenter());
dots.Add(keypoints->MouthLeftCorner());
dots.Add(keypoints->MouthUpperEdge());
dots.Add(keypoints->MouthLowerEdge());
dots.Add(keypoints->RightEyebrowOuterEnd());
dots.Add(keypoints->RightEyebrowInnerEnd());
dots.Add(keypoints->LeftEyebrowInnerEnd());
dots.Add(keypoints->LeftEyebrowOuterEnd());
dots.Add(keypoints->RightEdge());
dots.Add(keypoints->ChinTip());
dots.Add(keypoints->LeftEdge());
auto keypointImg = keypoints->GetImage()->DrawShape(dots);
keypointImg->SaveAs("output/keypoints.png");
-
java
Face face = faces.get(0);
DotsShape dots = new DotsShape();
Image keypointImg = keypoints.
GetImage().DrawShape(dots);
keypointImg.
SaveAs(
"output/keypoints.png");
-
csharp
var face = faces[0];
var dots = new DotsShape();
dots.Add(keypoints.RightEyeOuterCorner());
dots.Add(keypoints.RightEyeCentre());
dots.Add(keypoints.RightEyeInnerCorner());
dots.Add(keypoints.LeftEyeInnerCorner());
dots.Add(keypoints.LeftEyeCentre());
dots.Add(keypoints.LeftEyeOuterCorner());
dots.Add(keypoints.NoseRoot());
dots.Add(keypoints.NoseRightBottom());
dots.Add(keypoints.NoseTip());
dots.Add(keypoints.NoseLeftBottom());
dots.Add(keypoints.NoseBottom());
dots.Add(keypoints.MouthRightCorner());
dots.Add(keypoints.MouthCenter());
dots.Add(keypoints.MouthLeftCorner());
dots.Add(keypoints.MouthUpperEdge());
dots.Add(keypoints.MouthLowerEdge());
dots.Add(keypoints.RightEyebrowOuterEnd());
dots.Add(keypoints.RightEyebrowInnerEnd());
dots.Add(keypoints.LeftEyebrowInnerEnd());
dots.Add(keypoints.LeftEyebrowOuterEnd());
dots.Add(keypoints.RightEdge());
dots.Add(keypoints.ChinTip());
dots.Add(keypoints.LeftEdge());
var keypointImg = keypoints.GetImage().DrawShape(dots);
keypointImg.SaveAs("output/keypoints.png");
Face keypoints
Face Passive Liveness
- Note
- Access to the passive liveness feature requires explicit permission in the license to enable face passive liveness.
We are providing following passive liveness calculations:
- fast - Passive liveness mode with best performance available but worse accuracy as ACCURATE mode.
The Face::PassiveLivenessMode::FAST operates with higher speed but lower accuracy, whereas the Face::PassiveLivenessMode::ACCURATE is slower but provides increased accuracy, irrespective of the chosen FaceDetector::Config.
-
c++
auto img =
Image::Decode(BinaryFile::ReadAll(
"assets/liveness_face.png"));
FaceDetector fd;
auto face = capture->DetectWith(fd)[0];
std::cout << " Fast PL: " << plf << std::endl;
std::cout << " Accurate PL: " << pla << std::endl;
-
java
Image img = Image.
Decode(BinaryFile.ReadAll(
"assets/liveness_face.png"));
FaceCapture capture = new FaceCapture(img);
FaceDetector fd = new FaceDetector();
System.out.println(" Fast PL: "
System.out.println(" Accurate PL: "
-
csharp
Image img = Image.
Decode(BinaryFile.ReadAll(
"assets/liveness_face.png"));
FaceCapture capture = new FaceCapture(img);
FaceDetector fd = new FaceDetector();
System.Console.WriteLine(" Fast PL: " +
System.Console.WriteLine(" Accurate PL: " +
- Passive Liveness Scores, Error Rates and Accuracy
- APCER: Attack presentation images that are classified as bona-fide presentations are false accepts. The percentual rate of such error on a given dataset and given threshold represents the Attack Presentation Classification Error Rate (APCER, formerly FAR).
- BPCER: Bona-fide presentation images that are classified as attacks are false rejects. The percentual rate of such error on a given dataset and given threshold represents the Bona-fide Presentation Classification Error Rate (BPCER, formerly FRR).
Example:
Imagine a dataset of 10,000 bona-fide presentation photos (real faces) and 1,000 attack presentation photos, where measurements were made. Threshold of 89.5, which is at working point of 1% APCER results in 3.7% BPCER. That means there are 10 attack presentation photos marked as bona-fide (false accepts) and 370 bona-fide photos are marked as attacks (false rejects).
Fast Passive Liveness Thresholds
| Use case type | Threshold | Performance |
| Convenience (minimum rejected attempts) | 80.0 | 2.75% APCER @ 1 % BPCER |
| Balanced (equal error rate) | 83.2 | 1.76% both APCER & BPCER |
| Security (minimum accepted frauds) | 86.2 | 3.62% BPCER @ 1% APCER |
Face Attributes Reliability
In some cases the meaningfulness of attribute value relies on values of other attributes. We provide following reliability checks
-
c++
ICAOReliability icao;
auto failedAttributes = icao.
Validate(face);
for (const auto& a : failedAttributes)
{
std::cout << " Value " << a.value << " of " << a.id << " is not in range ["
<< a.min << ", " << a.max << "]" << std::endl;
}
-
java
ICAOReliability icao = new ICAOReliability();
for (FailedFaceAttribute a : icao.
Validate(face)) {
System.out.println(" Value " + a.getValue() + " of " + a.getId()
+ " is not in range [" + a.getMin() + ", " + a.getMax()
+ "]");
}
-
csharp
ICAOReliability icao = new ICAOReliability();
foreach (FailedFaceAttribute a
in icao.
Validate(face))
{
System.Console.WriteLine(
" Value " + a.
value +
" of " + a.
id +
" is not in range [" + a.
min +
", " + a.
max +
"]");
}
Best practices for use of Face Images
We provide following best practice checks
- ISOFullFrontalImageValidator - Check if usage of Full Frontal Images on travel documents will follow best practices, as described in Section B.3.2 Best practices for use of Full Frontal Images on travel documents [6].
-
c++
ISOFullFrontalImageValidator icaoFullFrontal;
auto failedAttributes = icaoFullFrontal.
Validate(face);
for (const auto& a : failedAttributes)
{
std::cout << " Value " << a.value << " of " << a.id << " is not in range ["
<< a.min << ", " << a.max << "]" << std::endl;
}
-
java
ISOFullFrontalImageValidator icaoFullFrontal = new ISOFullFrontalImageValidator();
for (FailedFaceAttribute a : icaoFullFrontal.
Validate(face)) {
System.out.println(" Value " + a.getValue() + " of " + a.getId()
+ " is not in range [" + a.getMin() + ", " + a.getMax()
+ "]");
}
-
csharp
ISOFullFrontalImageValidator icaoFullFrontal = new ISOFullFrontalImageValidator();
foreach (FailedFaceAttribute a
in icaoFullFrontal.
Validate(face))
{
System.Console.WriteLine(
" Value " + a.
value +
" of " + a.
id +
" is not in range [" + a.
min +
", " + a.
max +
"]");
}
ISO Conversion
ISO Image
It is possible to convert Face to ISO image compliant with ISO 19794-5:2011 and back from image to FaceCapture.
-
c++
auto image =
Image::Decode(BinaryFile::ReadAll(
"assets/faces.png"));
FaceAttributes fa;
FaceDetector faceDetector;
auto face = faceCapture->DetectWith(faceDetector)[0];
std::cout << " Conversion Face to ISO image" << std::endl;
auto encoder = PngImageEncoder();
auto isoImage = face->ToIsoImage(encoder);
std::cout << " Conversion ISO to Face image" << std::endl;
auto faceImage = faceCapture->FromIsoImage(isoImage);
-
java
Image img = Image.
Decode(BinaryFile.ReadAll(
"assets/faces.png"));
FaceAttributes fa = new FaceAttributes();
fa.SetCaptureDeviceTechnology(
fa.SetCaptureDeviceVendorID(new FaceCaptureDeviceVendorID(11));
fa.SetCaptureDeviceTypeID(new FaceCaptureDeviceTypeID(7));
FaceCapture faceCapture = new FaceCapture(img, fa);
FaceDetector faceDetector = new FaceDetector();
Face face = faceCapture.
DetectWith(faceDetector).get(0);
System.out.println(" Conversion Face to ISO image");
PngImageEncoder encoder = new PngImageEncoder();
System.out.println(" Conversion ISO to Face image");
-
csharp
Image image = Image.
Decode(BinaryFile.ReadAll(
"assets/faces.png"));
FaceAttributes fa = new FaceAttributes();
FaceCapture faceCapture = new FaceCapture(image, fa);
FaceDetector faceDetector = new FaceDetector();
var face = faceCapture.
DetectWith(faceDetector)[0];
System.Console.WriteLine(" Conversion Face to ISO image");
var encoder = new PngImageEncoder();
var isoImage = face.ToIsoImage(encoder);
System.Console.WriteLine(" Conversion ISO to Face image");
var faceImage = FaceCapture.FromIsoImage(isoImage);