#include "sfe_toolkit/sfe_core.h"
#include "sfe_toolkit/sfe_face.h"
#include <iomanip>
#include <regex>
#include <sstream>
#include <vector>
#include "annotate.hpp"
#include "solvers.h"
#include "utils.hpp"
#include <unordered_map>
std::string
image_probe =
"assets/face/images/obiwan0.png";
size_t &recommended_width,
size_t &recommended_height) {
std::smatch width_height;
std::regex(".*w([0-9]+)h([0-9]+).*"))) {
recommended_width = std::stoi(width_height[1]);
recommended_height = std::stoi(width_height[2]);
} else {
image,
SFEFaceDetectionAccuracyType::SFE_FACE_DETECT_ACCURACY_TYPE_ACCURATE,
utils::checkError(error);
recommended_width = input_size.width;
recommended_height = input_size.height;
};
}
std::cout << "SFEDetection{ " << std::endl;
std::cout <<
" confidence: " << detected_face.
confidence << std::endl;
std::cout << " SFEBoundingBox{ " << std::endl;
std::cout <<
" x: " << detected_face.
bounding_box.
x << std::endl;
std::cout <<
" y: " << detected_face.
bounding_box.
y << std::endl;
std::cout << " }" << std::endl;
std::cout << " } " << std::endl;
std::cout << std::endl;
}
std::cout << "SFEFaceArea{ " << std::endl;
std::cout <<
" size: " << face_area.
size <<
" [px]" << std::endl;
std::cout <<
" area: " << face_area.
area << std::endl;
std::cout <<
" area_in_image: " << face_area.
area_in_image << std::endl;
std::cout << "}" << std::endl;
std::cout << std::endl;
}
std::cout << "SFEFaceHeadPose{" << std::endl;
std::cout <<
" pitch: " << head_pose.
pitch << std::endl;
std::cout <<
" yaw: " << head_pose.
yaw << std::endl;
std::cout <<
" roll: " << head_pose.
roll << std::endl;
std::cout << "} " << std::endl;
std::cout << std::endl;
}
std::cout << "Face size: " << face_size << " [px]" << std::endl;
std::cout << std::endl;
}
std::cout << "Mask confidence: " << mask_confidence << std::endl;
std::cout << std::endl;
}
inline void
std::cout << "SFEFaceQualityAttributes{" << std::endl;
std::cout <<
" sharpness: " << quality_attributes.
sharpness << std::endl;
std::cout <<
" brightness: " << quality_attributes.
brightness << std::endl;
std::cout <<
" contrast: " << quality_attributes.
contrast << std::endl;
std::cout << " unique_intensity_levels: "
std::cout << "} " << std::endl;
std::cout << std::endl;
}
std::cout << "Help: Usage of the program." << std::endl;
std::cout << "Options:" << std::endl;
std::cout << "-h: Display help." << std::endl;
std::cout << "-p: Probe image file." << std::endl;
std::cout << "-d: Path to detector solver." << std::endl;
std::cout << "-l: Path to landmarks solver." << std::endl;
std::cout << "-i: Path to liveness solver." << std::endl;
std::cout << "-t: Face detection threshold. <0,1>" << std::endl;
std::cout << "-m: Minimal face size in pixels to detect." << std::endl;
std::cout << "-x: Max face size in pixels to detect." << std::endl;
}
int main(
int argc,
char *argv[]) {
{
std::unordered_map<std::string, std::string> args;
for (int i = 1; i < argc; ++i) {
std::string arg = argv[i];
if (arg[0] == '-') {
if (arg == "-h") {
return 0;
}
if (i + 1 < argc && argv[i + 1][0] != '-') {
args[arg] = argv[++i];
} else {
std::cerr << "Option " << arg << " requires a value." << std::endl;
return 1;
}
} else {
std::cerr << "Unknown option: " << arg << std::endl;
return 1;
}
}
if (args.count("-p"))
if (args.count("-d"))
if (args.count("-l"))
if (args.count("-i"))
if (args.count("-t"))
if (args.count("-m"))
if (args.count("-x"))
utils::printFormatted("PARAMETERS");
std::cout <<
"Probe image: " <<
image_probe << std::endl;
<< std::endl;
std::cout <<
"Min face size [px]: " <<
face_size_min << std::endl;
std::cout <<
"Max face size [px]: " <<
face_size_max << std::endl;
}
utils::printToolkitInfo();
{
utils::printFormatted("LOADING solvers");
utils::checkError(error);
utils::checkError(error);
utils::checkError(error);
}
{
utils::printFormatted("FACE DETECTION");
utils::checkError(error);
size_t recommended_width{};
size_t recommended_height{};
recommended_height);
&resized_image);
utils::checkError(error);
}
{
size_t detection_count = 1;
&detected_face, &detection_count);
utils::checkError(error);
if (detection_count == 0) {
std::cout << "No face detected in the probe image." << std::endl;
return 0;
} else {
std::cout << "Found " << detection_count
<< " face(s) in the probe image. Using the face with highest "
"confidence."
<< std::endl;
}
}
{
landmarks.data());
utils::checkError(error);
}
{
utils::printFormatted("LIVENESS CHECK");
&liveness);
utils::checkError(error);
}
{
std::cout <<
"Liveness score is " << liveness.
score;
static const float LIVENESS_THRESHOLD = 0.81f;
if (liveness.
score < LIVENESS_THRESHOLD) {
std::cout << " which is below " << LIVENESS_THRESHOLD
<< " threshold. Face is spoof." << std::endl;
} else {
std::cout << " which is above " << LIVENESS_THRESHOLD
<< " threshold. Face is genuine." << std::endl;
}
}
float face_size = 0;
float mask_confidence;
{
utils::printFormatted("FACE ATTRIBUTES");
error =
sfeFaceSize(image, landmarks.data(), &face_size);
utils::checkError(error);
utils::checkError(error);
error =
sfeFaceArea(image, landmarks.data(), &face_area);
utils::checkError(error);
utils::checkError(error);
error =
utils::checkError(error);
}
{
}
{
std::stringstream label;
label << "Face" << std::fixed << std::setprecision(2)
<<
" d:" << detected_face.
confidence <<
" m:" << mask_confidence
<<
" l:" << liveness.
score;
annotate::labelBox(image, label.str(), detected_face.
bounding_box, annotate::WHITE,
annotate::GREEN);
for (auto &landmark : landmarks) {
auto x = landmark.x * image.
width;
auto y = landmark.y * image.
height;
annotate::circle(image, x, y, 3, annotate::YELLOW);
}
auto png_file = std::vector<unsigned char>(size);
utils::checkError(error);
png_file.resize(size);
utils::saveFile("face_liveness.png", png_file);
std::cout << std::endl;
std::cout << "Annotated image saved to face_liveness.png" << std::endl;
}
utils::printFormatted("FINISHED");
}
void getRecommendedImageSize(const std::string &solver_face_detect, SFEImage &image, const size_t face_size_min, const size_t face_size_max, size_t &recommended_width, size_t &recommended_height)
Get recommended image size for face detection.
std::string solver_face_detect
Solvers to use in example, the defaults are filled in by CMake.
float detection_threshold
const auto SOLVER_PARAMETERS
size_t face_size_min
Required size of the face to be detected.
std::string solver_face_landmarks
void printMaskConfidence(float mask_confidence)
std::string solver_face_liveness
void printFaceSize(size_t face_size)
void printFaceHeadPose(SFEFaceHeadPose &head_pose)
void prinFaceAreaInfo(SFEFaceArea &face_area)
void printFaceQualityAttributes(SFEFaceQualityAttributes &quality_attributes)
void printFaceDetectionInfo(SFEDetection &detected_face)
void sfeSolverFree(SFESolver solver)
Free memory associated with SFESolver.
SFEError sfeImageResize(SFEImageView image, size_t width, size_t height, SFEImage *out_image)
Resize image.
void * SFESolver
Solver provides an abstract interface over inference models and engines.
void * SFEError
Error type used to hold optional error message.
void sfeImageFree(SFEImage image)
Free memory associated with SFEImage.
@ SFE_IMAGE_FORMAT_PNG
Portable Network Graphics format.
SFEError sfeImageEncode(SFEImageView image, SFEImageFormat image_format, unsigned char *out_data, size_t *in_out_data_len)
Encode SFEImage into a buffer with specified image_format.
SFEError sfeSolverCreate(const char *solver_file, const SFESolverParameter *solver_parameters, size_t solver_parameters_count, SFESolver *out_solver)
Create new solver from solver file.
SFEError sfeImageDecode(const unsigned char *data, size_t data_len, SFEImage *out_image)
Decode SFEImage from raw image data of various formats. Eg. PNG, JPEG ..
SFEError sfeDetect(SFESolver solver, SFEImageView image, float threshold, SFEDetection *out_detections, size_t *in_out_detection_count)
Detect objects in the source image using unified detection API.
SFEError sfeFaceArea(SFEImageView image, SFEFaceLandmarks face_landmarks[SFE_FACE_LANDMARK_COUNT], SFEFaceArea *out_area)
Get face area.
SFEError sfeFaceSize(SFEImageView image, SFEFaceLandmarks face_landmarks[SFE_FACE_LANDMARK_COUNT], float *face_size)
Get the face size in pixels from the face landmarks and the source image. Face size is defined as a m...
SFEError sfeFaceDetectInputSize(SFEImageView image, SFEFaceDetectionAccuracyType detection_mode, size_t min_face_size, size_t max_face_size, SFEDetectionInputSize *out_input_size)
Calculation of recommended input image width and height according to desired minimal and maximal size...
SFEError sfeFaceMaskConfidence(const SFEFaceLandmarks face_landmarks[SFE_FACE_LANDMARK_COUNT], float *out_mask_confidence)
Get confidence from given landmarks if the face is wearing a face mask.
#define SFE_FACE_LANDMARK_COUNT
SFEError sfeFaceLandmarks(SFESolver solver, SFEImageView image, const SFEDetection *detection, SFEFaceLandmarks out_face_landmarks[SFE_FACE_LANDMARK_COUNT])
Detect 23 landmarks of the face detected in the area of source image marked with detection.
SFEError sfeFaceLivenessPassive(SFESolver solver, SFEImageView image, SFEFaceLandmarks face_landmarks[SFE_FACE_LANDMARK_COUNT], SFEFaceLiveness *out_liveness)
Passive liveness score calculation.
SFEError sfeFaceHeadPose(SFEImageView image, SFEFaceLandmarks face_landmarks[SFE_FACE_LANDMARK_COUNT], SFEFaceHeadPose *out_head_pose)
Calculate angle rotations of head towards camera reference frame from given landmarks.
SFEError sfeFaceQualityAttributes(SFEImageView image, SFEFaceLandmarks face_landmarks[SFE_FACE_LANDMARK_COUNT], SFEFaceQualityAttributes *out_quality_attributes)
Calculate face image quality attributes from given source image and landmarks data.
float y
Y coordinate of the top left corner of the bounding box relative to source image size - range <0,...
float width
Width of the bounding box relative to source image size - range <0,1>
float x
X coordinate of the top left corner of the bounding box relative to source image size - range <0,...
float height
Height of the bounding box relative to source image size - range <0,1>
Core detection - tagged union containing all detection types.
SFEBoundingBox bounding_box
Bounding box (common for all detection types)
float confidence
Detection confidence - range <0,1> (common for all detection types)
float area_in_image
size of face area intersected with the whole image and relative to the whole image; value in range <0...
float area
size of face area relative to the whole image; value in range <0,1>
float size
absolute face size
Face head pose struct containing angle rotations of head.
float yaw
Face attribute representing angle rotation of head towards camera reference frame around Y-axis as pe...
float pitch
Face attribute representing angle rotation of head towards camera reference frame around X-axis as pe...
float roll
Face attribute representing angle rotation of head towards camera reference frame around Z-axis as pe...
float score
Normalized passive liveness score - range <0,1>
Face quality attributes struct.
float unique_intensity_levels
Normalized face attribute for evaluating whether an area of face has appropriate number of unique int...
float sharpness
Normalized face attribute for evaluating whether an area of face image is not blurred....
float brightness
Normalized face attribute for evaluating whether an area of face is correctly exposed....
float contrast
Normalized face attribute for evaluating whether an area of face is contrast enough....
Raw owned raster image representation, HWC|BGR order.
size_t width
Width of the image in pixels.
size_t height
Height of the image in pixels.