73 lines
2.5 KiB
C++
73 lines
2.5 KiB
C++
|
|
// Copyright (C) 2018-2024 Intel Corporation
|
||
|
|
// SPDX-License-Identifier: Apache-2.0
|
||
|
|
//
|
||
|
|
|
||
|
|
#include <algorithm>
|
||
|
|
#include <vector>
|
||
|
|
#include <limits>
|
||
|
|
|
||
|
|
#include <opencv2/imgproc.hpp>
|
||
|
|
|
||
|
|
#include "face_reid.hpp"
|
||
|
|
|
||
|
|
static const float h = 112.;
|
||
|
|
static const float w = 96.;
|
||
|
|
// reference landmarks points in the unit square [0,1]x[0,1]
|
||
|
|
static const float ref_landmarks_normalized[] = {
|
||
|
|
30.2946f / w, 51.6963f / h, 65.5318f / w, 51.5014f / h, 48.0252f / w,
|
||
|
|
71.7366f / h, 33.5493f / w, 92.3655f / h, 62.7299f / w, 92.2041f / h};
|
||
|
|
|
||
|
|
cv::Mat GetTransform(cv::Mat* src, cv::Mat* dst) {
|
||
|
|
cv::Mat col_mean_src;
|
||
|
|
reduce(*src, col_mean_src, 0, cv::REDUCE_AVG);
|
||
|
|
for (int i = 0; i < src->rows; i++) {
|
||
|
|
src->row(i) -= col_mean_src;
|
||
|
|
}
|
||
|
|
|
||
|
|
cv::Mat col_mean_dst;
|
||
|
|
reduce(*dst, col_mean_dst, 0, cv::REDUCE_AVG);
|
||
|
|
for (int i = 0; i < dst->rows; i++) {
|
||
|
|
dst->row(i) -= col_mean_dst;
|
||
|
|
}
|
||
|
|
|
||
|
|
cv::Scalar mean, dev_src, dev_dst;
|
||
|
|
cv::meanStdDev(*src, mean, dev_src);
|
||
|
|
dev_src(0) =
|
||
|
|
std::max(static_cast<double>(std::numeric_limits<float>::epsilon()), dev_src(0));
|
||
|
|
*src /= dev_src(0);
|
||
|
|
cv::meanStdDev(*dst, mean, dev_dst);
|
||
|
|
dev_dst(0) =
|
||
|
|
std::max(static_cast<double>(std::numeric_limits<float>::epsilon()), dev_dst(0));
|
||
|
|
*dst /= dev_dst(0);
|
||
|
|
|
||
|
|
cv::Mat w, u, vt;
|
||
|
|
cv::SVD::compute((*src).t() * (*dst), w, u, vt);
|
||
|
|
cv::Mat r = (u * vt).t();
|
||
|
|
cv::Mat m(2, 3, CV_32F);
|
||
|
|
m.colRange(0, 2) = r * (dev_dst(0) / dev_src(0));
|
||
|
|
m.col(2) = (col_mean_dst.t() - m.colRange(0, 2) * col_mean_src.t());
|
||
|
|
return m;
|
||
|
|
}
|
||
|
|
|
||
|
|
void AlignFaces(std::vector<cv::Mat>* face_images, std::vector<cv::Mat>* landmarks_vec) {
|
||
|
|
if (landmarks_vec->size() == 0) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
CV_Assert(face_images->size() == landmarks_vec->size());
|
||
|
|
cv::Mat ref_landmarks = cv::Mat(5, 2, CV_32F);
|
||
|
|
|
||
|
|
for (size_t j = 0; j < face_images->size(); j++) {
|
||
|
|
for (int i = 0; i < ref_landmarks.rows; i++) {
|
||
|
|
ref_landmarks.at<float>(i, 0) =
|
||
|
|
ref_landmarks_normalized[2 * i] * face_images->at(j).cols;
|
||
|
|
ref_landmarks.at<float>(i, 1) =
|
||
|
|
ref_landmarks_normalized[2 * i + 1] * face_images->at(j).rows;
|
||
|
|
landmarks_vec->at(j).at<float>(i, 0) *= face_images->at(j).cols;
|
||
|
|
landmarks_vec->at(j).at<float>(i, 1) *= face_images->at(j).rows;
|
||
|
|
}
|
||
|
|
cv::Mat m = GetTransform(&ref_landmarks, &landmarks_vec->at(j));
|
||
|
|
cv::warpAffine(face_images->at(j), face_images->at(j), m,
|
||
|
|
face_images->at(j).size(), cv::WARP_INVERSE_MAP);
|
||
|
|
}
|
||
|
|
}
|