Files
scene-actor-extraction/src/face_utils.hpp
T
2026-06-12 20:57:33 +02:00

59 lines
2.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include "types.hpp"
#include <opencv2/calib3d.hpp>
#include <opencv2/imgproc.hpp>
#include <cmath>
// ── align_face ────────────────────────────────────────────────────────────────
// Produces a 112×112 BGR crop using the ArcFace 5-point similarity transform.
// Returns an empty Mat if the affine fit fails (degenerate detection).
inline cv::Mat align_face(const cv::Mat& img,
const std::array<cv::Point2f, 5>& landmarks) {
std::vector<cv::Point2f> src(landmarks.begin(), landmarks.end());
std::vector<cv::Point2f> dst(5);
for (int i = 0; i < 5; ++i) dst[i] = {kArcFaceRef[i][0], kArcFaceRef[i][1]};
cv::Mat M = cv::estimateAffinePartial2D(src, dst, cv::noArray(), cv::RANSAC, 3.0);
if (M.empty()) return {};
cv::Mat crop;
cv::warpAffine(img, crop, M, {112, 112},
cv::INTER_LINEAR, cv::BORDER_CONSTANT, {0, 0, 0});
return crop;
}
// ── enhance_for_retry ────────────────────────────────────────────────────────
// Used when initial face detection finds nothing. Pads the image by 50%
// (border-replicated, so the detector doesn't see a hard edge) and applies
// CLAHE to boost local contrast, giving the detector a second try.
inline cv::Mat enhance_for_retry(const cv::Mat& img) {
cv::Mat padded;
const int pad_x = img.cols / 4;
const int pad_y = img.rows / 4;
cv::copyMakeBorder(img, padded, pad_y, pad_y, pad_x, pad_x, cv::BORDER_REPLICATE);
cv::Mat lab;
cv::cvtColor(padded, lab, cv::COLOR_BGR2Lab);
std::vector<cv::Mat> channels;
cv::split(lab, channels);
cv::createCLAHE(2.0, cv::Size(8, 8))->apply(channels[0], channels[0]);
cv::merge(channels, lab);
cv::Mat out;
cv::cvtColor(lab, out, cv::COLOR_Lab2BGR);
return out;
}
// ── l2_normalise ──────────────────────────────────────────────────────────────
inline Embedding l2_normalise(const float* row) {
float norm = 0.f;
for (int d = 0; d < 512; ++d) norm += row[d] * row[d];
norm = std::sqrt(norm);
if (norm < 1e-6f) norm = 1e-6f;
Embedding emb;
for (int d = 0; d < 512; ++d) emb[d] = row[d] / norm;
return emb;
}