5#include "sfe_toolkit/sfe_core.h"
6#include "sfe_toolkit/sfe_face.h"
13#include "annotate.hpp"
16#include <unordered_map>
45 size_t &recommended_width,
46 size_t &recommended_height) {
55 std::smatch width_height;
57 std::regex(
".*w([0-9]+)h([0-9]+).*"))) {
58 recommended_width = std::stoi(width_height[1]);
59 recommended_height = std::stoi(width_height[2]);
70 SFEFaceDetectionAccuracyType::SFE_FACE_DETECT_ACCURACY_TYPE_ACCURATE,
72 utils::checkError(error);
73 recommended_width = input_size.width;
74 recommended_height = input_size.height;
79 std::cout <<
"Help: Usage of the program." << std::endl;
80 std::cout <<
"Options:" << std::endl;
81 std::cout <<
"-h: Display help." << std::endl;
82 std::cout <<
"-p: Probe image file." << std::endl;
83 std::cout <<
"-g: Gallery folder." << std::endl;
84 std::cout <<
"-d: Path to detector solver." << std::endl;
85 std::cout <<
"-l: Path to landmarks solver." << std::endl;
86 std::cout <<
"-e: Path to extraction solver." << std::endl;
87 std::cout <<
"-t: Detection threshold. <0,1>" << std::endl;
88 std::cout <<
"-i: Identification threshold. <0,1>" << std::endl;
89 std::cout <<
"-m: Minimal face size in pixels to detect." << std::endl;
90 std::cout <<
"-x: Max face size in pixels to detect." << std::endl;
100 size_t recommended_width{};
101 size_t recommended_height{};
113 error =
sfeImageResize(image, recommended_width, recommended_height,
115 utils::checkError(error);
118 size_t detection_count = 1;
123 &detected_face, &detection_count);
124 utils::checkError(error);
126 if (detection_count == 0) {
127 std::ostringstream oss;
128 oss <<
"Error: No face detected in the image ";
129 throw std::runtime_error(oss.str());
131 }
else if (detection_count > 1) {
132 std::ostringstream oss;
133 oss <<
"Error: Found " << detection_count
134 <<
" faces. Please provide an image with only one face.";
136 throw std::runtime_error(oss.str());
139 std::cout <<
"Detected face in the image." << std::endl;
144int main(
int argc,
char *argv[]) {
148 std::unordered_map<std::string, std::string> args;
151 for (
int i = 1; i < argc; ++i) {
152 std::string arg = argv[i];
159 if (i + 1 < argc && argv[i + 1][0] !=
'-') {
160 args[arg] = argv[++i];
162 std::cerr <<
"Option " << arg <<
" requires a value." << std::endl;
166 std::cerr <<
"Unknown option: " << arg << std::endl;
172 if (args.count(
"-p"))
174 if (args.count(
"-g"))
176 if (args.count(
"-d"))
178 if (args.count(
"-l"))
180 if (args.count(
"-e"))
182 if (args.count(
"-t"))
184 if (args.count(
"-i"))
186 if (args.count(
"-m"))
188 if (args.count(
"-x"))
191 utils::printFormatted(
"EXAMPLE PARAMETERS");
193 std::cout <<
"Probe image: " <<
image_probe << std::endl;
194 std::cout <<
"Gallery image: " <<
image_gallery << std::endl;
203 std::cout <<
"Min face size [px]: " <<
face_size_min << std::endl;
204 std::cout <<
"Max face size [px]: " <<
face_size_max << std::endl;
210 utils::printToolkitInfo();
221 utils::printFormatted(
"LOADING SOLVERS");
226 utils::checkError(error);
232 utils::checkError(error);
238 utils::checkError(error);
243 utils::printFormatted(
"PROBE TEMPLATE EXTRACTION");
252 error =
sfeImageDecode(image_data.data(), image_data.size(), &image);
253 utils::checkError(error);
259 detectFace(image, detector_solver, detected_face);
268 utils::checkError(error);
276 landmarks.data(), &probe_face_template);
277 utils::checkError(error);
282 utils::printFormatted(
"PROBE TEMPLATE ATTRIBUTES");
287 utils::checkError(error);
290 std::cout <<
"Version of the probe template: " << version.
version_major
291 <<
'.' << version_minor << std::endl;
297 std::vector<uint8_t> buf(1024);
298 size_t size = buf.size();
300 if (error && size > buf.size()) {
305 utils::checkError(error);
309 utils::checkError(error);
311 float roundtrip_score = 0.f;
314 utils::checkError(error);
315 std::cout <<
"Export/import round-trip match score: " << roundtrip_score
321 std::vector<std::string> image_paths{};
326 for (
auto folder_name : folder_names) {
330 auto image_names = utils::getFiles(gallery_folder);
333 for (
auto image_name : image_names) {
335 auto image_path = gallery_folder + image_name;
342 std::vector<SFEFaceTemplate> gallery_face_templates(image_paths.size());
343 std::vector<SFEDetection> detected_faces(image_paths.size());
344 std::vector<std::array<SFEFaceLandmarks, SFE_FACE_LANDMARK_COUNT>> landmarks(
348 utils::printFormatted(
"GALLERY TEMPLATE EXTRACTION");
350 for (
size_t i = 0; i < image_paths.size(); i++) {
351 std::cout <<
"Processing image #" << i <<
", path: " << image_paths[i]
357 auto image_data = utils::readFile(image_paths[i]);
360 error =
sfeImageDecode(image_data.data(), image_data.size(), &image);
361 utils::checkError(error);
366 detectFace(image, detector_solver, detected_faces[i]);
373 landmarks[i].data());
374 utils::checkError(error);
380 template_solver, image, &detected_faces[i], landmarks[i].data(),
381 &gallery_face_templates[i]);
382 utils::checkError(error);
383 std::cout <<
"Extracted face template." << std::endl;
385 std::cout << std::endl;
390 size_t candidate_count = 1;
391 int best_candidate_index = -1;
392 std::vector<SFETemplateIdentificationCandidate> identification_results(
395 utils::printFormatted(
"1:N IDENTIFICATION");
398 &probe_face_template, gallery_face_templates.
data(),
400 identification_results.data(), &candidate_count, 4);
401 utils::checkError(error);
405 identification_results.resize(candidate_count);
407 std::cout <<
"Found " << identification_results.size()
408 <<
" candidates above identification threshold "
410 for (
auto &result : identification_results)
411 std::cout <<
"Template index: #" << result.index
412 <<
", score: " << result.score << std::endl;
415 best_candidate_index = identification_results[0].index;
422 utils::printFormatted(
"1:1 MATCHING WITH TOP CANDIDATE");
424 if (identification_results.size() == 0) {
425 std::cout <<
"No candidates found above identification threshold "
430 auto best_candidate_template = gallery_face_templates[best_candidate_index];
432 float match_confidence;
435 utils::checkError(error);
437 std::cout <<
"Matching score of probe template with template index #"
438 << best_candidate_index <<
", score: " << match_confidence
445 utils::printFormatted(
"SAVE FACE CROP AND ANNOTATED IMAGE");
447 auto best_face_index = identification_results[0].index;
453 auto image_data = utils::readFile(image_paths[best_face_index]);
456 error =
sfeImageDecode(image_data.data(), image_data.size(), &image);
457 utils::checkError(error);
466 float face_size_extension = 2.0f;
468 sfeFaceCrop(image, landmarks[best_face_index].data(),
470 utils::checkError(error);
474 <<
"px, height of cropped image: "
480 auto png_file = std::vector<unsigned char>();
483 png_file.resize(size);
485 png_file.data(), &size);
486 utils::checkError(error2);
488 std::cout <<
"Face crop saved as crop_identified_person.png" << std::endl;
489 utils::saveFile(
"crop_identified_person.png", png_file);
494 std::stringstream label;
495 label <<
" D:" << std::fixed << std::setprecision(2)
496 << detected_faces[best_face_index].confidence
497 <<
" M:" << identification_results[0].score;
499 auto color = annotate::RED;
501 annotate::labelBox(image, label.str(),
502 detected_faces[best_candidate_index].bounding_box,
503 annotate::WHITE, color);
506 for (
auto &landmark : landmarks[best_face_index]) {
507 auto x = landmark.x * image.width;
508 auto y = landmark.y * image.height;
509 annotate::circle(image, x, y, 3, annotate::YELLOW);
513 size_t size = image.width * image.height * 3;
514 auto png_file = std::vector<unsigned char>(size);
516 utils::checkError(error);
517 png_file.resize(size);
518 utils::saveFile(
"face_identify.png", png_file);
520 std::cout << std::endl;
521 std::cout <<
"Annotated image saved as face_identify.png" << std::endl;
525 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.
uint8_t data[SFE_FACE_TEMPLATE_SIZE]
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.