Plumerai Familiar Face Identification C++ API¶
This document describes example usage of the C++ API for the Plumerai Familiar Face Identification software for videos on Arm Cortex-A and x86. For the API documentation, see here.
Example usage¶
Below is an example of using the C++ API. It consists of two main loops:
- An example enrollment loop, which runs for a fixed number of frames and computes a face embedding vector to enroll one person in the face library.
- An example main loop, similar to the regular people detection API.
#include <cstdint>
#include <vector>
#include "plumerai/face_identification.h"
int main() {
// Settings, to be changed as needed
constexpr int width = 1600; // camera image width in pixels
constexpr int height = 1200; // camera image height in pixels
constexpr auto image_format = plumerai::ImageFormat::PACKED_RGB888;
// Initialize the `FaceIdentification` object
auto ffid = plumerai::FaceIdentification(height, width);
// ---------------------- Enrollment starting ------------------------------
auto error_code = ffid.start_face_enrollment();
if (error_code != plumerai::ErrorCodeFamiliarFaceID::ENROLLMENT_IN_PROGRESS) {
printf("Error: %s\n", plumerai::error_code_string(error_code));
return 1;
}
// Enroll for 10 frames (just an example, more frames is better)
for (int t = 0; t < 10; ++t) {
// Some example input here, normally this is where camera data is acquired
auto image = std::vector<std::uint8_t>(height * width * 3); // 3 for RGB
// Process the frame
std::vector<BoxPrediction> predictions(0);
// If the enrollment frames come from a video source, then use
// `process_frame` instead:
// error_code =
// ffid.process_frame<image_format>(image.data(), predictions, delta_t);
error_code = ffid.single_image<image_format>(image.data(), predictions);
printf("Enrollment status: %d\n", error_code);
}
// Finish enrollment
std::vector<std::int8_t> embedding;
error_code = ffid.finish_face_enrollment(embedding);
if (error_code != plumerai::ErrorCode::SUCCESS) {
printf("Error: %s\n", plumerai::error_code_string(error_code));
return 1;
}
// Add the embedding to the library with face id '1'.
error_code = ffid.add_face_embedding(embedding, 1);
if (error_code != plumerai::ErrorCode::SUCCESS) {
printf("Error: %s\n", plumerai::error_code_string(error_code));
return 1;
}
// ---------------------- Enrollment finished ------------------------------
// Loop over frames in a video stream (example: 10 frames)
for (int t = 0; t < 10; ++t) {
// Some example input here, normally this is where camera data is acquired
auto image = std::vector<std::uint8_t>(height * width * 3); // 3 for RGB
// The time between two video frames in seconds
// In this example we assume a constant frame rate of 30 fps, but variable
// rates are supported.
const float delta_t = 1.f / 30.f;
// Process the frame
std::vector<BoxPrediction> predictions(0);
error_code =
ffid.process_frame<image_format>(image.data(), predictions, delta_t);
if (error_code != plumerai::ErrorCode::SUCCESS) {
printf("Error: %s\n", plumerai::error_code_string(error_code));
return 1;
}
// Display the results to stdout
for (auto &p : predictions) {
if (p.confidence < 0.8f) { continue; } // only high-confidence boxes
if (p.class_id != CLASS_PERSON) { continue; }
printf(
"Box #%d of class %d and face id %d with confidence %.2f @ (x,y) -> "
"(%.2f,%.2f) till (%.2f,%.2f)\n",
p.id, p.class_id, ffid.get_face_id(p), p.confidence, p.x_min, p.y_min,
p.x_max, p.y_max);
}
if (predictions.size() == 0) {
printf("No bounding boxes found in this frame\n");
}
}
return 0;
}