SmartFace Embedded Toolkit  4.2.1
Loading...
Searching...
No Matches
example_palm_identify.cpp
Go to the documentation of this file.
1
5#include "sfe_toolkit/sfe_core.h"
6#include "sfe_toolkit/sfe_palm.h"
7#include <regex>
8#include <vector>
9
10#include <iomanip>
11#include <sstream>
12
13#include "annotate.hpp"
14#include "solvers.h"
15#include "utils.hpp"
16#include <unordered_map>
17
18std::string image_match = "assets/palm/palm_id1_r1.jpg";
19std::string image_probe = "assets/palm/palm_id1_r2.jpg";
20std::string image_non_match = "assets/palm/palm_id2_l1.jpg";
21
23std::string solver_palm_detect = SOLVER_PALM_DETECT;
24std::string solver_palm_extraction = SOLVER_PALM_EXTRACTION;
25
26// NOTE: Using the same solver for landmarks as for detection, this is intentional.
27std::string solver_palm_landmarks = SOLVER_PALM_DETECT;
28
29const auto SOLVER_PARAMETERS = std::vector<SFESolverParameter>{};
30
32
34 SFESolver &detector_solver, SFESolver &landmarks_solver, SFESolver &extraction_solver) {
35
36 SFEImage image{};
37 DEFER(sfeImageFree(image));
38 SFEError error{};
39 { // STAGE 1: Load image
40 // Load image data from file
41 auto image_data = utils::readFile(image_path);
42
43 // Decode image from data
44 error = sfeImageDecode(image_data.data(), image_data.size(), &image);
45 utils::checkError(error);
46 }
47
49 SFEDetection detected_palm = {};
50 { // STAGE 2: Detect palm in the image
51
52 // Detect palm in the image
53 float detection_threshold = 0.1f;
54 size_t detected_count = 1;
55 error = sfeDetect(detector_solver, image, detection_threshold,
56 &detected_palm, &detected_count);
57 utils::checkError(error);
58
59 if (detected_count > 0 && detected_palm.confidence < 0.5) {
60 throw std::runtime_error("No palm detected in the probe image.");
61 }
62
63 std::cout << "Found palm in the image. Extracting template..." << std::endl;
64 }
66
68 SFEPalmLandmarks landmarks = {};
69 { // STAGE 3: Extract palm landmarks
70 // Extract palm landmarks (hand position, orientation, keypoints)
71 // These are required for template extraction
72 error = sfePalmLandmarks(landmarks_solver, image, &detected_palm, &landmarks);
73 utils::checkError(error);
74 }
76
78 SFEPalmTemplate palm_template;
79 { // STAGE 4: Extract probe palm template
80 // Use template extraction solver to create new palm template
81 // Requires palm landmarks from previous step
82 error = sfePalmTemplateExtract(extraction_solver, image, &landmarks,
83 &palm_template);
84 utils::checkError(error);
85 }
87 return palm_template;
88}
89
90void printHelp() {
91 std::cout << "Help: Usage of the program." << std::endl;
92 std::cout << "Options:" << std::endl;
93 std::cout << "-h: Display help." << std::endl;
94 std::cout << "-p: Probe image file." << std::endl;
95 std::cout << "-g: Matching image file. Our \"palm database\"." << std::endl;
96 std::cout << "-d: Path to detector solver." << std::endl;
97 std::cout << "-l: Path to landmarks solver." << std::endl;
98 std::cout << "-e: Path to template extraction solver." << std::endl;
99 std::cout << "-t: Detection threshold. <0,1>" << std::endl;
100 std::cout << "-i: Identification threshold. <0,1>" << std::endl;
101}
102
104int main(int argc, char *argv[]) {
105
106 { // STAGE 0: Parse command line arguments
107 // Map to store argument values
108 std::unordered_map<std::string, std::string> args;
109
110 // Parse command line arguments
111 for (int i = 1; i < argc; ++i) {
112 std::string arg = argv[i];
113 if (arg[0] == '-') {
114 if (arg == "-h") {
115 printHelp();
116 return 0;
117 }
118 // Check if there's a next argument and it isn't another option
119 if (i + 1 < argc && argv[i + 1][0] != '-') {
120 args[arg] = argv[++i];
121 } else {
122 std::cerr << "Option " << arg << " requires a value." << std::endl;
123 return 1;
124 }
125 } else {
126 std::cerr << "Unknown option: " << arg << std::endl;
127 return 1;
128 }
129 }
130
131 // Assign values to variables based on parsed arguments
132 if (args.count("-p"))
133 image_probe = args["-p"];
134 if (args.count("-g"))
135 image_match = args["-g"];
136 if (args.count("-d"))
137 solver_palm_detect = args["-d"];
138 if (args.count("-l"))
139 solver_palm_landmarks = args["-l"];
140 if (args.count("-e"))
141 solver_palm_extraction = args["-e"];
142 if (args.count("-i"))
143 identification_threshold = std::stof(args["-i"]);
144
145 utils::printFormatted("EXAMPLE PARAMETERS");
146 // Print resource names
147 std::cout << "Probe image: " << image_probe << std::endl;
148 std::cout << "Matching image: " << image_match << std::endl;
149
150 // Print solver names
151 std::cout << "Palm detection solver: " << solver_palm_detect << std::endl;
152 std::cout << "Palm landmarks solver: " << solver_palm_landmarks << std::endl;
153 std::cout << "Palm extraction solver: " << solver_palm_extraction << std::endl;
154
155 // Print other options
156 std::cout << "Identification threshold: " << identification_threshold
157 << std::endl;
158 }
159
160 utils::printToolkitInfo();
161
162 SFEError error{};
163 SFESolver detector_solver{};
164 DEFER(sfeSolverFree(detector_solver));
165 SFESolver landmarks_solver{};
166 DEFER(sfeSolverFree(landmarks_solver));
167 SFESolver extraction_solver{};
168 DEFER(sfeSolverFree(extraction_solver));
169 { // STAGE 1.1: loading solvers
170 utils::printFormatted("LOADING SOLVERS");
171 // Initialize Palm detection solver
172 error = sfeSolverCreate(
174 SOLVER_PARAMETERS.size(), &detector_solver);
175 utils::checkError(error);
176 // Initialize Palm landmarks solver (using same solver as detection)
177 error = sfeSolverCreate(
179 SOLVER_PARAMETERS.size(), &landmarks_solver);
180 utils::checkError(error);
181 // Initialize Palm extraction solver
182 error = sfeSolverCreate(
184 SOLVER_PARAMETERS.size(), &extraction_solver);
185 utils::checkError(error);
186 }
187
188 SFEPalmTemplate probe_palm_template;
189 { // STAGE 1: Extract probe palm template
190 utils::printFormatted("PROBE TEMPLATE EXTRACTION");
191
192 probe_palm_template = extract_template(image_probe, detector_solver, landmarks_solver, extraction_solver);
193 }
194
195 { // STAGE 1.1: (optional) Print template attributes
196 utils::printFormatted("PROBE TEMPLATE ATTRIBUTES");
197
199 SFEPalmTemplateVersion version = {};
200 error = sfePalmTemplateVersion(&probe_palm_template, &version);
201 utils::checkError(error);
202
203 std::cout << "Version of the probe template: " << version.major << '.'
204 << version.minor << '.' << version.patch << std::endl;
206 }
207
208 size_t gallery_size = 10;
209 std::vector<SFEPalmTemplate> palm_template_gallery(gallery_size);
210 { // STAGE 2: Create palm templates gallery
211 utils::printFormatted("PALM GALLERY EXTRACTION");
212
213 auto matching_palm_template =
214 extract_template(image_match, detector_solver, landmarks_solver, extraction_solver);
215
216 auto non_matching_palm_template =
217 extract_template(image_non_match, detector_solver, landmarks_solver, extraction_solver);
218
219 // Fill the gallery with non-matching templates for demonstration purposes
220 for (size_t i = 0; i < gallery_size; i++) {
221 palm_template_gallery[i] = non_matching_palm_template;
222 }
223
224 // Add matching template to the gallery at index 5
225 palm_template_gallery[5] = matching_palm_template;
226 }
227
229 size_t candidate_count = 1;
230 std::vector<SFETemplateIdentificationCandidate> identification_results(
231 candidate_count);
232 { // STAGE 3: Identify the probe template
233 utils::printFormatted("1:N IDENTIFICATION");
234
236 &probe_palm_template, palm_template_gallery.data(),
237 palm_template_gallery.size(), identification_threshold,
238 identification_results.data(), &candidate_count, 4);
239 utils::checkError(error);
240
241 if (candidate_count == 0) {
242 std::cout << "No candidates found above identification threshold "
243 << identification_threshold << std::endl;
244 return 0;
245 }
246
247 std::cout << "Found " << identification_results.size()
248 << " candidates above identification threshold "
249 << identification_threshold << std::endl;
250 for (auto &result : identification_results)
251 std::cout << "Template index: #" << result.index
252 << ", score: " << result.score << std::endl;
253 }
255
257 { // STAGE 4: 1:1 matching with top candidate to showcase 1:1 matching
258 utils::printFormatted("1:1 MATCHING");
259
260 if (identification_results.size() == 0) {
261 std::cout << "No candidates found above identification threshold "
262 << identification_threshold << std::endl;
263 return 0;
264 }
265
266 // Since it's sorted vector by score, the best candidate is the first one
267 auto match_palm_template =
268 palm_template_gallery[identification_results[0].index];
269
270 float match_confidence;
271 error = sfePalmTemplateMatch(&probe_palm_template, &match_palm_template,
272 &match_confidence);
273 utils::checkError(error);
274
275 std::cout
276 << "Matching score of probe template with the best template, score: "
277 << match_confidence << std::endl;
278 }
280
281 utils::printFormatted("FINISHED");
282}
void printHelp()
float identification_threshold
std::string image_probe
float detection_threshold
const auto SOLVER_PARAMETERS
SFEIrisTemplate extract_template(std::string image_path, SFESolver &detector_solver, SFESolver &template_solver)
std::string image_match
std::string image_non_match
std::string solver_palm_landmarks
std::string solver_palm_detect
Solvers to use in example, the defaults are filled in by CMake.
std::string solver_palm_extraction
std::string image_path
void sfeSolverFree(SFESolver solver)
Free memory associated with SFESolver.
void * SFESolver
Solver provides an abstract interface over inference models and engines.
Definition sfe_core.h:102
void * SFEError
Error type used to hold optional error message.
Definition sfe_core.h:97
void sfeImageFree(SFEImage image)
Free memory associated with SFEImage.
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 sfePalmLandmarks(SFESolver solver, SFEImageView image, const SFEDetection *detection, SFEPalmLandmarks *out_landmarks)
Calculate palm landmarks from given source image and palm detection.
SFEError sfePalmTemplateMatch(const SFEPalmTemplate *template1, const SFEPalmTemplate *template2, float *out_matching_score)
Match two palm templates.
SFEError sfePalmTemplateExtract(SFESolver solver, SFEImageView image, const SFEPalmLandmarks *landmarks, SFEPalmTemplate *out_palm_template)
Extract template from source image and given palm attributes.
SFEError sfePalmTemplateIdentify(const SFEPalmTemplate *probe_palm_template, const SFEPalmTemplate *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 probe's template best matches with te...
SFEError sfePalmTemplateVersion(const SFEPalmTemplate *palm_template, SFEPalmTemplateVersion *out_palm_template_version)
Get palm template version.
Core detection - tagged union containing all detection types.
float confidence
Detection confidence - range <0,1> (common for all detection types)
Raw owned raster image representation, HWC|BGR order.
Definition sfe_core.h:70
Palm landmarks (keypoints, hand position, orientation, confidence)
Palm template struct.
Definition sfe_palm.h:22
uint8_t data[SFE_PALM_TEMPLATE_SIZE]
Definition sfe_palm.h:23
Palm template version struct.
Definition sfe_palm.h:27
uint8_t patch
Patch template version.
Definition sfe_palm.h:33
uint8_t minor
Minor template version.
Definition sfe_palm.h:31
uint8_t major
Major template version.
Definition sfe_palm.h:29