#include "sfe_toolkit/sfe_core.h"
#include "sfe_toolkit/sfe_face.h"
#include <regex>
#include <vector>
#include <iomanip>
#include <sstream>
#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 << "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 << "-g: Gallery folder." << std::endl;
std::cout << "-d: Path to detector solver." << std::endl;
std::cout << "-l: Path to landmarks solver." << std::endl;
std::cout << "-e: Path to extraction solver." << std::endl;
std::cout << "-t: Detection threshold. <0,1>" << std::endl;
std::cout << "-i: Identification 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;
}
{
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::ostringstream oss;
oss << "Error: No face detected in the image ";
throw std::runtime_error(oss.str());
} else if (detection_count > 1) {
std::ostringstream oss;
oss << "Error: Found " << detection_count
<< " faces. Please provide an image with only one face.";
throw std::runtime_error(oss.str());
}
std::cout << "Detected face in the image." << 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("-g"))
if (args.count("-d"))
if (args.count("-l"))
if (args.count("-e"))
if (args.count("-t"))
if (args.count("-i"))
if (args.count("-m"))
if (args.count("-x"))
utils::printFormatted("EXAMPLE 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;
<< std::endl;
}
utils::printToolkitInfo();
{
utils::printFormatted("LOADING SOLVERS");
utils::checkError(error);
utils::checkError(error);
utils::checkError(error);
}
{
utils::printFormatted("PROBE TEMPLATE EXTRACTION");
{
utils::checkError(error);
}
{
detectFace(image, detector_solver, detected_face);
}
{
landmarks.data());
utils::checkError(error);
}
{
landmarks.data(), &probe_face_template);
utils::checkError(error);
}
{
utils::printFormatted("PROBE TEMPLATE ATTRIBUTES");
utils::checkError(error);
std::cout <<
"Version of the probe template: " << version.
version_major
<< '.' << version_minor << std::endl;
}
{
std::vector<uint8_t> buf(1024);
size_t size = buf.size();
if (error && size > buf.size()) {
buf.resize(size);
size = buf.size();
}
utils::checkError(error);
utils::checkError(error);
float roundtrip_score = 0.f;
&roundtrip_score);
utils::checkError(error);
std::cout << "Export/import round-trip match score: " << roundtrip_score
<< std::endl;
}
}
std::vector<std::string> image_paths{};
{
for (auto folder_name : folder_names) {
auto image_names = utils::getFiles(gallery_folder);
for (auto image_name : image_names) {
}
}
}
std::vector<SFEFaceTemplate> gallery_face_templates(image_paths.size());
std::vector<SFEDetection> detected_faces(image_paths.size());
std::vector<std::array<SFEFaceLandmarks, SFE_FACE_LANDMARK_COUNT>> landmarks(
image_paths.size());
{
utils::printFormatted("GALLERY TEMPLATE EXTRACTION");
for (size_t i = 0; i < image_paths.size(); i++) {
std::cout << "Processing image #" << i << ", path: " << image_paths[i]
<< std::endl;
{
auto image_data = utils::readFile(image_paths[i]);
utils::checkError(error);
}
{
detectFace(image, detector_solver, detected_faces[i]);
}
{
landmarks[i].data());
utils::checkError(error);
}
{
template_solver, image, &detected_faces[i], landmarks[i].data(),
&gallery_face_templates[i]);
utils::checkError(error);
std::cout << "Extracted face template." << std::endl;
}
std::cout << std::endl;
}
}
size_t candidate_count = 1;
int best_candidate_index = -1;
std::vector<SFETemplateIdentificationCandidate> identification_results(
image_paths.size());
{
utils::printFormatted("1:N IDENTIFICATION");
&probe_face_template, gallery_face_templates.data(),
identification_results.data(), &candidate_count, 4);
utils::checkError(error);
identification_results.resize(candidate_count);
std::cout << "Found " << identification_results.size()
<< " candidates above identification threshold "
for (auto &result : identification_results)
std::cout << "Template index: #" << result.index
<< ", score: " << result.score << std::endl;
best_candidate_index = identification_results[0].index;
}
{
utils::printFormatted("1:1 MATCHING WITH TOP CANDIDATE");
if (identification_results.size() == 0) {
std::cout << "No candidates found above identification threshold "
return 0;
}
auto best_candidate_template = gallery_face_templates[best_candidate_index];
float match_confidence;
&match_confidence);
utils::checkError(error);
std::cout << "Matching score of probe template with template index #"
<< best_candidate_index << ", score: " << match_confidence
<< std::endl;
}
{
utils::printFormatted("SAVE FACE CROP AND ANNOTATED IMAGE");
auto best_face_index = identification_results[0].index;
{
auto image_data = utils::readFile(image_paths[best_face_index]);
utils::checkError(error);
}
{
float face_size_extension = 2.0f;
utils::checkError(error);
<< "px, height of cropped image: "
}
{
auto png_file = std::vector<unsigned char>();
size_t size =
png_file.resize(size);
png_file.data(), &size);
utils::checkError(error2);
std::cout << "Face crop saved as crop_identified_person.png" << std::endl;
utils::saveFile("crop_identified_person.png", png_file);
}
{
std::stringstream label;
label << " D:" << std::fixed << std::setprecision(2)
<< detected_faces[best_face_index].confidence
<< " M:" << identification_results[0].score;
auto color = annotate::RED;
annotate::labelBox(image, label.str(),
detected_faces[best_candidate_index].bounding_box,
annotate::WHITE, color);
for (auto &landmark : landmarks[best_face_index]) {
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_identify.png", png_file);
std::cout << std::endl;
std::cout << "Annotated image saved as face_identify.png" << std::endl;
}
}
utils::printFormatted("FINISHED");
}
float identification_threshold
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.
void detectFace(SFEImage &image, SFESolver &detector_solver, SFEDetection &detected_face)
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
std::string solver_face_template
std::string image_gallery
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 sfeFaceTemplateIdentify(SFEFaceTemplate *probe_face_template, SFEFaceTemplate *templates_gallery, size_t gallery_size, float matching_score_threshold, SFETemplateIdentificationCandidate *out_candidates, size_t *in_out_candidates_count, size_t thread_count)
Get an ordered array of SFETemplateIdentificationCandidate from tested template best matches of probe...
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 sfeFaceTemplateMatch(SFEFaceTemplate *template1, SFEFaceTemplate *template2, float *out_matching_score)
Match two face templates.
#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 sfeFaceCrop(SFEImageView image, SFEFaceLandmarks face_landmarks[SFE_FACE_LANDMARK_COUNT], float face_size_extension, float max_face_size, SFEFaceCrop *out_crop)
Crop the face according the given landmarks, the face size extension and the maximal face size....
SFEError sfeFaceTemplateExport(const SFEFaceTemplate *face_template, uint8_t *bytes, size_t *size)
Export face template to bytes that can be shared between Innovatrics components.
SFEError sfeFaceTemplateImport(const uint8_t *bytes, size_t size, SFEFaceTemplate *out_face_template)
Import face template from bytes; format is auto-detected (iface-template protobuf or raw ICF 522-byte...
SFEError sfeFaceTemplateExtract(SFESolver solver, SFEImageView image, const SFEDetection *detection, const SFEFaceLandmarks face_landmarks[SFE_FACE_LANDMARK_COUNT], SFEFaceTemplate *out_face_template)
Extract template from source image and given face landmarks.
SFEError sfeFaceTemplateVersion(SFEFaceTemplate *face_template, SFEFaceTemplateVersion *out_face_template_version)
Get face template version.
Core detection - tagged union containing all detection types.
SFEImage crop_image
Image of face cropped according the crop_box.
float face_size_extension
Defines the size of the crop as an extension of the detection bounding box.
Face template version struct.
uint8_t version_major
major template version
uint8_t version_minor
minor template version
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.