Files
scene-actor-extraction/src/nodes/face_detector_node.hpp
T

52 lines
1.8 KiB
C++

#pragma once
#include "config.hpp"
#include "inference/face_detector.hpp"
#include <algorithm>
#include <memory>
#include <string>
// ── FaceDetectorFunc ──────────────────────────────────────────────────────────
// KPN node: runs SCRFD-500MF to detect ALL faces in a frame.
//
// The inference backend (ONNX Runtime or raw TensorRT) is selected at compile
// time; this node talks only to IFaceDetector via make_face_detector(cfg).
struct FaceDetectorFunc {
static constexpr std::string_view label() { return "face_detector"; }
explicit FaceDetectorFunc(const Config& cfg)
: detector_(make_face_detector(cfg))
, max_faces_(cfg.max_faces)
, min_face_px_(cfg.min_face_px)
{}
SceneFrame operator()(Frame f) {
if (f.eof) return {std::move(f), {}};
auto faces = detector_->detect(f.image);
// Drop faces below minimum pixel size (too small for reliable ArcFace alignment)
faces.erase(
std::remove_if(faces.begin(), faces.end(), [&](const DetectedFace& d) {
return d.bbox.width < min_face_px_ || d.bbox.height < min_face_px_;
}),
faces.end());
// Sort largest-first so max_faces_ keeps the most informative detections
std::sort(faces.begin(), faces.end(),
[](const DetectedFace& a, const DetectedFace& b) {
return a.bbox.area() > b.bbox.area();
});
if (static_cast<int>(faces.size()) > max_faces_)
faces.resize(max_faces_);
return {std::move(f), std::move(faces)};
}
private:
std::unique_ptr<IFaceDetector> detector_;
int max_faces_{10};
float min_face_px_{40.f};
};