#pragma once #include "config.hpp" #include "inference/face_detector.hpp" #include #include #include // ── 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(faces.size()) > max_faces_) faces.resize(max_faces_); return {std::move(f), std::move(faces)}; } private: std::unique_ptr detector_; int max_faces_{10}; float min_face_px_{40.f}; };