Source (KPN++ pipeline nodes, ArcFace embedders, SCRFD/YuNet detectors, gallery builder), build scripts, and eval artifacts. - external/KPN as a git submodule (gitea.tourolle.paris/dtourolle/KPN) - ONNX models tracked via Git LFS (models/*.onnx) - generated outputs, TensorRT engines, reference repos, and media ignored
40 lines
1.5 KiB
C++
40 lines
1.5 KiB
C++
#pragma once
|
||
#include "face_utils.hpp"
|
||
|
||
#include <iostream>
|
||
|
||
// ── FaceAlignerFunc ───────────────────────────────────────────────────────────
|
||
// KPN node: applies a 5-point similarity transform to each detected face,
|
||
// producing a 112×112 BGR crop suitable for ArcFace inference.
|
||
//
|
||
// Alignment uses cv::estimateAffinePartial2D (RANSAC) to fit the detected
|
||
// landmarks to ArcFace canonical positions. Degenerate detections (where the
|
||
// affine fit fails) are silently dropped from the output vectors.
|
||
|
||
struct FaceAlignerFunc {
|
||
static constexpr std::string_view label() { return "face_aligner"; }
|
||
|
||
AlignedSceneFrame operator()(SceneFrame sf) {
|
||
if (sf.source.eof || sf.faces.empty())
|
||
return {std::move(sf.source), {}, {}};
|
||
|
||
std::vector<DetectedFace> good_faces;
|
||
std::vector<cv::Mat> crops;
|
||
good_faces.reserve(sf.faces.size());
|
||
crops.reserve(sf.faces.size());
|
||
|
||
for (auto& face : sf.faces) {
|
||
cv::Mat crop = align_face(sf.source.image, face.landmarks);
|
||
if (crop.empty()) {
|
||
std::cerr << "[face_aligner] degenerate detection skipped\n";
|
||
continue;
|
||
}
|
||
good_faces.push_back(face);
|
||
crops.push_back(std::move(crop));
|
||
}
|
||
|
||
return {std::move(sf.source), std::move(good_faces), std::move(crops)};
|
||
}
|
||
|
||
};
|