mirror of
https://github.com/deepinsight/insightface.git
synced 2026-08-21 03:47:56 +00:00
656 lines
22 KiB
C++
Executable File
656 lines
22 KiB
C++
Executable File
|
|
#ifndef TRACKING_LIB_UTILS_H
|
|
#define TRACKING_LIB_UTILS_H
|
|
|
|
//#include "face_attribute.h"
|
|
#include <cmath>
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#else
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
namespace inspire {
|
|
|
|
inline bool IsDirectory(const std::string& path) {
|
|
#ifdef _WIN32
|
|
DWORD dwAttrib = GetFileAttributes(path.c_str());
|
|
return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
|
#else
|
|
struct stat st;
|
|
if (stat(path.c_str(), &st) == 0) {
|
|
return S_ISDIR(st.st_mode);
|
|
} else {
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
inline void EstimateHeadPose(const std::vector<cv::Point2f> ¤t_shape,
|
|
cv::Vec3f &eav) {
|
|
// head pose estimation by linear regression.
|
|
static int HeadPosePointIndexs[] = {94, 59, 27, 20, 69, 45, 50};
|
|
int *estimateHeadPosePointIndexs = HeadPosePointIndexs;
|
|
static float estimateHeadPose2dArray[] = {
|
|
0.139791, 27.4028, 7.02636, -2.48207, 9.59384, 6.03758, 1.27402,
|
|
10.4795, 6.20801, 1.17406, 29.1886, 1.67768, 0.306761, -103.832,
|
|
5.66238, 4.78663, 17.8726, -15.3623, -5.20016, 9.29488, -11.2495,
|
|
-25.1704, 10.8649, -29.4877, -5.62572, 9.0871, -12.0982, -5.19707,
|
|
-8.25251, 13.3965, -23.6643, -13.1348, 29.4322, 67.239, 0.666896,
|
|
1.84304, -2.83223, 4.56333, -15.885, -4.74948, -3.79454, 12.7986,
|
|
-16.1, 1.47175, 4.03941};
|
|
|
|
cv::Mat estimateHeadPoseMat =
|
|
cv::Mat(15, 3, CV_32FC1, estimateHeadPose2dArray);
|
|
if (current_shape.empty())
|
|
return;
|
|
static const int samplePdim = 7;
|
|
float miny = 10000000000.0f;
|
|
float maxy = 0.0f;
|
|
float sumx = 0.0f;
|
|
float sumy = 0.0f;
|
|
for (int i = 0; i < samplePdim; i++) {
|
|
sumx += current_shape[i].x;
|
|
float y = current_shape[i].y;
|
|
sumy += y;
|
|
if (miny > y)
|
|
miny = y;
|
|
if (maxy < y)
|
|
maxy = y;
|
|
}
|
|
float dist = maxy - miny;
|
|
sumx = sumx / samplePdim;
|
|
sumy = sumy / samplePdim;
|
|
static cv::Mat tmp(1, 2 * samplePdim + 1, CV_32FC1);
|
|
for (int i = 0; i < samplePdim; i++) {
|
|
tmp.at<float>(i) =
|
|
(current_shape[estimateHeadPosePointIndexs[i]].x - sumx) / dist;
|
|
tmp.at<float>(i + samplePdim) =
|
|
(current_shape[estimateHeadPosePointIndexs[i]].y - sumy) / dist;
|
|
}
|
|
tmp.at<float>(2 * samplePdim) = 1.0f;
|
|
cv::Mat predict = tmp * estimateHeadPoseMat;
|
|
eav[0] = predict.at<float>(0);
|
|
eav[1] = predict.at<float>(1);
|
|
eav[2] = predict.at<float>(2);
|
|
}
|
|
|
|
inline void MinRect(const std::vector<cv::Point2f> &landmarks, int length,
|
|
float *rect) {
|
|
rect[0] = landmarks[0].x;
|
|
rect[1] = landmarks[0].y;
|
|
rect[2] = landmarks[0].x;
|
|
rect[3] = landmarks[0].y;
|
|
for (int i = 0; i < length; i++) {
|
|
if (rect[0] > landmarks[i].x)
|
|
rect[0] = landmarks[i].x;
|
|
else if (rect[2] < landmarks[i].x)
|
|
rect[2] = landmarks[i].x;
|
|
|
|
if (rect[1] > landmarks[i].y)
|
|
rect[1] = landmarks[i].y;
|
|
else if (rect[3] < landmarks[i].y)
|
|
rect[3] = landmarks[i].y;
|
|
}
|
|
}
|
|
|
|
inline float PointDistance(const cv::Point2f &a, const cv::Point2f &b) {
|
|
float norm = (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
|
|
return sqrt(norm);
|
|
}
|
|
|
|
inline cv::Point2f MeanPoint(const std::vector<cv::Point2f> &points) {
|
|
assert(points.size() > 0);
|
|
cv::Point2f mean;
|
|
for (const auto &p: points)
|
|
mean += p;
|
|
mean /= static_cast<int>(points.size());
|
|
return mean;
|
|
}
|
|
|
|
inline void BestFitRect(const std::vector<cv::Point2f> &pre_landmarks, int size,
|
|
std::vector<cv::Point2f> &src_fit) {
|
|
src_fit.resize(pre_landmarks.size());
|
|
std::vector<float> mean_shape_box = {56, 56, 92, 102};
|
|
float rect[4];
|
|
MinRect(pre_landmarks, size, rect);
|
|
float points_height = rect[3] - rect[1];
|
|
float points_centerx = (rect[0] + rect[2]) / 2;
|
|
float points_centery = (rect[1] + rect[3]) / 2;
|
|
float meanshape_centerx = mean_shape_box[0];
|
|
float meanshape_centery = mean_shape_box[1];
|
|
float scaleHeight = mean_shape_box[3] / points_height;
|
|
float scale = scaleHeight;
|
|
for (int i = 0; i < size; i++) {
|
|
src_fit[i].x =
|
|
pre_landmarks[i].x * scale - points_centerx * scale + meanshape_centerx;
|
|
src_fit[i].y =
|
|
pre_landmarks[i].y * scale - points_centery * scale + meanshape_centery;
|
|
}
|
|
}
|
|
|
|
inline void
|
|
SimilarityTransformEstimate(const std::vector<cv::Point2f> &src_points,
|
|
const std::vector<cv::Point2f> &dst_points,
|
|
cv::Mat &matrix) {
|
|
|
|
assert(matrix.rows == 2);
|
|
assert(matrix.cols == 3);
|
|
// matrix.create(2,3,CV_64F);
|
|
assert(src_points.size() == dst_points.size());
|
|
cv::Point2f src_mean = MeanPoint(src_points);
|
|
cv::Point2f dst_mean = MeanPoint(dst_points);
|
|
// matrix.resize(6);
|
|
float src_norm2 = 0.f;
|
|
float sum_a = 0.f;
|
|
float sum_b = 0.f;
|
|
|
|
for (int i = 0; i < src_points.size(); i++) {
|
|
cv::Point2f src_d = src_points[i] - src_mean;
|
|
cv::Point2f dst_d = dst_points[i] - dst_mean;
|
|
|
|
src_norm2 += src_d.x * src_d.x + src_d.y * src_d.y;
|
|
sum_a += src_d.x * dst_d.x + src_d.y * dst_d.y;
|
|
sum_b += src_d.x * dst_d.y - src_d.y * dst_d.x;
|
|
}
|
|
|
|
if (std::fabs(src_norm2) < std::numeric_limits<float>::epsilon()) {
|
|
float a = 1.f;
|
|
float b = 0.f;
|
|
float tx = dst_mean.x - src_mean.x;
|
|
float ty = dst_mean.y - src_mean.y;
|
|
matrix.at<double>(0, 0) = a;
|
|
matrix.at<double>(0, 1) = -b;
|
|
matrix.at<double>(0, 2) = tx;
|
|
matrix.at<double>(1, 0) = b;
|
|
matrix.at<double>(1, 1) = a;
|
|
matrix.at<double>(1, 2) = ty;
|
|
} else {
|
|
float a = sum_a / src_norm2;
|
|
float b = sum_b / src_norm2;
|
|
float tx = dst_mean.x - (a * src_mean.x - b * src_mean.y);
|
|
float ty = dst_mean.y - (b * src_mean.x + a * src_mean.y);
|
|
matrix.at<double>(0, 0) = a;
|
|
matrix.at<double>(0, 1) = -b;
|
|
matrix.at<double>(0, 2) = tx;
|
|
matrix.at<double>(1, 0) = b;
|
|
matrix.at<double>(1, 1) = a;
|
|
matrix.at<double>(1, 2) = ty;
|
|
}
|
|
}
|
|
|
|
inline void
|
|
SimilarityTransformEstimate(const std::vector<cv::Point2f> &src_points,
|
|
const std::vector<cv::Point2f> &dst_points,
|
|
std::vector<float> &matrix) {
|
|
assert(src_points.size() == dst_points.size());
|
|
cv::Point2f src_mean = MeanPoint(src_points);
|
|
cv::Point2f dst_mean = MeanPoint(dst_points);
|
|
matrix.resize(6);
|
|
float src_norm2 = 0.f;
|
|
float sum_a = 0.f;
|
|
float sum_b = 0.f;
|
|
|
|
for (int i = 0; i < src_points.size(); i++) {
|
|
cv::Point2f src_d = src_points[i] - src_mean;
|
|
cv::Point2f dst_d = dst_points[i] - dst_mean;
|
|
|
|
src_norm2 += src_d.x * src_d.x + src_d.y * src_d.y;
|
|
sum_a += src_d.x * dst_d.x + src_d.y * dst_d.y;
|
|
sum_b += src_d.x * dst_d.y - src_d.y * dst_d.x;
|
|
}
|
|
|
|
if (std::fabs(src_norm2) < std::numeric_limits<float>::epsilon()) {
|
|
float a = 1.f;
|
|
float b = 0.f;
|
|
float tx = dst_mean.x - src_mean.x;
|
|
float ty = dst_mean.y - src_mean.y;
|
|
matrix[0] = a;
|
|
matrix[1] = -b;
|
|
matrix[2] = tx;
|
|
matrix[3] = b;
|
|
matrix[4] = a;
|
|
matrix[5] = ty;
|
|
} else {
|
|
float a = sum_a / src_norm2;
|
|
float b = sum_b / src_norm2;
|
|
float tx = dst_mean.x - (a * src_mean.x - b * src_mean.y);
|
|
float ty = dst_mean.y - (b * src_mean.x + a * src_mean.y);
|
|
matrix[0] = a;
|
|
matrix[1] = -b;
|
|
matrix[2] = tx;
|
|
matrix[3] = b;
|
|
matrix[4] = a;
|
|
matrix[5] = ty;
|
|
}
|
|
}
|
|
|
|
inline cv::Mat GetRectSquareAffine(cv::Rect rect, float win_size = 112) {
|
|
assert(rect.height == rect.width);
|
|
std::vector<cv::Point2f> dst_pts = {
|
|
{0, 0},
|
|
{win_size, 0},
|
|
{win_size, win_size}};
|
|
float x1 = static_cast<float>(rect.x);
|
|
float y1 = static_cast<float>(rect.y);
|
|
float x2 = static_cast<float>(rect.x + rect.width);
|
|
float y2 = static_cast<float>(rect.y + rect.height);
|
|
std::vector<cv::Point2f> src_pts = {{x1, y1},
|
|
{x2, y1},
|
|
{x2, y2}};
|
|
cv::Mat m = cv::getAffineTransform(src_pts, dst_pts);
|
|
return m;
|
|
}
|
|
|
|
inline cv::Mat SquareToSquare(cv::Rect src, cv::Rect dst,
|
|
float win_size = 112) {
|
|
float src_x1 = static_cast<float>(src.x);
|
|
float src_y1 = static_cast<float>(src.y);
|
|
float src_x2 = static_cast<float>(src.x + src.width);
|
|
float src_y2 = static_cast<float>(src.y + src.height);
|
|
|
|
float dst_x1 = static_cast<float>(dst.x);
|
|
float dst_y1 = static_cast<float>(dst.y);
|
|
float dst_x2 = static_cast<float>(dst.x + dst.width);
|
|
float dst_y2 = static_cast<float>(dst.y + dst.height);
|
|
|
|
std::vector<cv::Point2f> src_pts = {
|
|
{src_x1, src_y1},
|
|
{src_x2, src_y1},
|
|
{src_x2, src_y2}};
|
|
std::vector<cv::Point2f> dst_pts = {
|
|
{dst_x1, dst_y1},
|
|
{dst_x2, dst_y1},
|
|
{dst_x2, dst_y2}};
|
|
cv::Mat m = cv::getAffineTransform(src_pts, dst_pts);
|
|
return m;
|
|
}
|
|
|
|
inline std::vector<cv::Point2f>
|
|
ApplyTransformToPoints(const std::vector<cv::Point2f> &points,
|
|
const cv::Mat &matrix) {
|
|
assert(matrix.rows == 2);
|
|
assert(matrix.cols == 3);
|
|
double m00 = matrix.at<double>(0, 0);
|
|
double m01 = matrix.at<double>(0, 1);
|
|
double m02 = matrix.at<double>(0, 2);
|
|
double m10 = matrix.at<double>(1, 0);
|
|
double m11 = matrix.at<double>(1, 1);
|
|
double m12 = matrix.at<double>(1, 2);
|
|
std::vector<cv::Point2f> out_points(points.size());
|
|
assert(out_points.size() == points.size());
|
|
for (int j = 0; j < points.size(); j++) {
|
|
out_points[j].x = points[j].x * m00 + points[j].y * m01 + m02;
|
|
out_points[j].y = points[j].x * m10 + points[j].y * m11 + m12;
|
|
}
|
|
return out_points;
|
|
}
|
|
|
|
inline std::vector<cv::Point2f>
|
|
FixPointsMeanshape(std::vector<cv::Point2f> &points,
|
|
const std::vector<cv::Point2f> &mean_shape) {
|
|
|
|
cv::Rect bbox = cv::boundingRect(points);
|
|
int R = std::max(bbox.height, bbox.width);
|
|
int cx = bbox.x + bbox.width / 2;
|
|
int cy = bbox.y + bbox.height / 2;
|
|
cv::Rect old(cx - R / 2, cy - R / 2, R, R);
|
|
|
|
cv::Rect mean_shape_box = cv::boundingRect(mean_shape);
|
|
int m_R = std::max(mean_shape_box.height, mean_shape_box.width);
|
|
int m_cx = mean_shape_box.x + mean_shape_box.width / 2;
|
|
int m_cy = mean_shape_box.y + mean_shape_box.height / 2;
|
|
cv::Rect _new(m_cx - m_R / 2, m_cy - m_R / 2, m_R, m_R);
|
|
cv::Mat affine = SquareToSquare(old, _new);
|
|
std::vector<cv::Point2f> new_pts = ApplyTransformToPoints(points, affine);
|
|
return new_pts;
|
|
}
|
|
|
|
inline std::vector<cv::Point2f> FixPoints(std::vector<cv::Point2f> &points) {
|
|
// RotPoints(points, -2);
|
|
cv::Rect bbox = cv::boundingRect(points);
|
|
int R = std::max(bbox.height, bbox.width);
|
|
int cx = bbox.x + bbox.width / 2;
|
|
int cy = bbox.y + bbox.height / 2;
|
|
cv::Rect old(cx - R / 2, cy - R / 2, R, R);
|
|
int margin = 0;
|
|
int zx = 0;
|
|
int zy = 5;
|
|
int new_x1 = zx + margin;
|
|
int new_y1 = zy + margin;
|
|
int new_x2 = 112 + zx - margin;
|
|
int new_y2 = 112 + zy - margin;
|
|
cv::Rect _new(new_x1, new_y1, new_x2 - new_x1, new_y2 - new_y1);
|
|
cv::Mat affine = SquareToSquare(old, _new);
|
|
std::vector<cv::Point2f> new_pts = ApplyTransformToPoints(points, affine);
|
|
return new_pts;
|
|
}
|
|
|
|
inline cv::Rect ComputeSafeRect(const cv::Rect ®ion, int height, int width) {
|
|
int x1 = region.x;
|
|
int y1 = region.y;
|
|
int x2 = region.x + region.width;
|
|
int y2 = region.y + region.height;
|
|
x1 = std::max(0, x1);
|
|
y1 = std::max(0, y1);
|
|
|
|
x2 = std::min(x2, width - 1);
|
|
y2 = std::min(y2, height - 1);
|
|
cv::Rect safe_rect(x1, y1, x2 - x1, y2 - y1);
|
|
return safe_rect;
|
|
}
|
|
|
|
inline void Transform(const std::vector<cv::Point2f> &pre_landmarks,
|
|
float *src_fit, const float *meanshape, const int size,
|
|
std::vector<float> &rotation,
|
|
std::vector<float> &rotation_inv) {
|
|
std::vector<float> src(size * 2);
|
|
std::vector<float> dst(size * 2);
|
|
|
|
float src_mean_x = 0, src_mean_y = 0, dst_mean_x = 0, dst_mean_y = 0;
|
|
float tx, ty;
|
|
float src_norm = 0, sum_a = 0, sum_b = 0;
|
|
for (int i = 0; i < size; i++) {
|
|
src_mean_x += pre_landmarks[i].x;
|
|
src_mean_y += pre_landmarks[i].y;
|
|
dst_mean_x += src_fit[2 * i];
|
|
dst_mean_y += meanshape[2 * i + 1];
|
|
}
|
|
src_mean_x = src_mean_x / size;
|
|
src_mean_y = src_mean_y / size;
|
|
dst_mean_x = dst_mean_x / size;
|
|
dst_mean_y = dst_mean_y / size * 1.1;
|
|
// dst_mean_y = dst_mean_y / size * 1.1;
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
src[2 * i] = pre_landmarks[i].x - src_mean_x;
|
|
src[2 * i + 1] = pre_landmarks[i].y - src_mean_y;
|
|
src_norm += src[2 * i] * src[2 * i];
|
|
src_norm += src[2 * i + 1] * src[2 * i + 1];
|
|
dst[2 * i] = meanshape[2 * i] - dst_mean_x;
|
|
dst[2 * i + 1] = meanshape[2 * i + 1] - dst_mean_y;
|
|
|
|
sum_a += src[2 * i] * dst[2 * i] + src[2 * i + 1] * dst[2 * i + 1];
|
|
sum_b += src[2 * i] * dst[2 * i + 1] - src[2 * i + 1] * dst[2 * i];
|
|
}
|
|
sum_a = sum_a / src_norm;
|
|
sum_b = sum_b / src_norm;
|
|
|
|
tx = dst_mean_x - sum_a * src_mean_x + sum_b * src_mean_y;
|
|
ty = dst_mean_y - sum_b * src_mean_x - sum_a * src_mean_y;
|
|
|
|
rotation.clear();
|
|
rotation.push_back(sum_a);
|
|
rotation.push_back(-sum_b);
|
|
rotation.push_back(tx);
|
|
rotation.push_back(sum_b);
|
|
rotation.push_back(sum_a);
|
|
rotation.push_back(ty);
|
|
|
|
double m[6];
|
|
m[0] = rotation[0];
|
|
m[1] = rotation[1];
|
|
m[2] = rotation[2];
|
|
m[3] = rotation[3];
|
|
m[4] = rotation[4];
|
|
m[5] = rotation[5];
|
|
|
|
double D = m[0] * m[4] - m[1] * m[3];
|
|
D = D != 0 ? 1. / D : 0;
|
|
double A11 = m[4] * D, A22 = m[0] * D;
|
|
m[0] = A11;
|
|
m[1] *= -D;
|
|
m[3] *= -D;
|
|
m[4] = A22;
|
|
double b1 = -m[0] * m[2] - m[1] * m[5];
|
|
double b2 = -m[3] * m[2] - m[4] * m[5];
|
|
m[2] = b1;
|
|
m[5] = b2;
|
|
|
|
rotation_inv.clear();
|
|
rotation_inv.push_back(m[0]);
|
|
rotation_inv.push_back(m[1]);
|
|
rotation_inv.push_back(m[2]);
|
|
rotation_inv.push_back(m[3]);
|
|
rotation_inv.push_back(m[4]);
|
|
rotation_inv.push_back(m[5]);
|
|
}
|
|
|
|
inline std::vector<cv::Point2f> Rect2Points(const cv::Rect rect) {
|
|
float x1 = static_cast<float>(rect.x);
|
|
float y1 = static_cast<float>(rect.y);
|
|
float x2 = static_cast<float>(rect.x + rect.width);
|
|
float y2 = static_cast<float>(rect.y + rect.height);
|
|
std::vector<cv::Point2f> src_pts = {{x1, y1},
|
|
{x2, y1},
|
|
{x2, y2},
|
|
{x1, y2}};
|
|
return src_pts;
|
|
}
|
|
|
|
inline std::vector<cv::Point2f> Rect2Points(const cv::Rect2f rect) {
|
|
float x1 = rect.x;
|
|
float y1 = rect.y;
|
|
float x2 = rect.x + rect.width;
|
|
float y2 = rect.y + rect.height;
|
|
std::vector<cv::Point2f> src_pts = {{x1, y1},
|
|
{x2, y1},
|
|
{x2, y2},
|
|
{x1, y2}};
|
|
return src_pts;
|
|
}
|
|
|
|
inline cv::Mat ScaleAffineMatrix(const cv::Mat &affine, float scale,
|
|
int origin_width, int origin_height,
|
|
int new_width, int new_height) {
|
|
std::vector<cv::Point2f> origin_pts =
|
|
Rect2Points(cv::Rect(0, 0, origin_width, origin_height));
|
|
cv::Mat affine_inv;
|
|
cv::invertAffineTransform(affine, affine_inv);
|
|
std::vector<cv::Point2f> screen_pts =
|
|
ApplyTransformToPoints(origin_pts, affine_inv);
|
|
cv::Point2f center;
|
|
for (auto &one: screen_pts) {
|
|
center.x += one.x * 0.25f;
|
|
center.y += one.y * 0.25f;
|
|
}
|
|
|
|
screen_pts[0].x = center.x + (screen_pts[0].x - center.x) * scale;
|
|
screen_pts[0].y = center.y + (screen_pts[0].y - center.y) * scale;
|
|
|
|
screen_pts[1].x = center.x + (screen_pts[1].x - center.x) * scale;
|
|
screen_pts[1].y = center.y + (screen_pts[1].y - center.y) * scale;
|
|
|
|
screen_pts[2].x = center.x + (screen_pts[2].x - center.x) * scale;
|
|
screen_pts[2].y = center.y + (screen_pts[2].y - center.y) * scale;
|
|
|
|
screen_pts[3].x = center.x + (screen_pts[3].x - center.x) * scale;
|
|
screen_pts[3].y = center.y + (screen_pts[3].y - center.y) * scale;
|
|
|
|
std::vector<cv::Point2f> new_pts =
|
|
Rect2Points(cv::Rect(0, 0, new_width, new_height));
|
|
screen_pts.pop_back();
|
|
new_pts.pop_back();
|
|
cv::Mat m = cv::getAffineTransform(screen_pts, new_pts);
|
|
return m;
|
|
}
|
|
|
|
template<typename T>
|
|
inline int ArgMax(const std::vector<T> data, int start, int end) {
|
|
int diff = std::max_element(data.begin() + start, data.begin() + end) -
|
|
(data.begin() + start);
|
|
return diff;
|
|
}
|
|
|
|
inline void RotPoints(std::vector<cv::Point2f> &pts, float angle) {
|
|
float angle_rad = angle * 3.1415 / 180;
|
|
float m11 = cos(angle_rad);
|
|
float m12 = -sin(angle_rad);
|
|
float m21 = sin(angle_rad);
|
|
float m22 = cos(angle_rad);
|
|
for (auto &one: pts) {
|
|
one.x = one.x * m11 + one.y * m12;
|
|
one.y = one.x * m21 + one.y * m22;
|
|
}
|
|
}
|
|
|
|
inline cv::Rect flipRectWidth(const cv::Rect &rect, const cv::Size &size) {
|
|
int x1 = rect.x;
|
|
int y1 = rect.y;
|
|
int x2 = rect.x + rect.width;
|
|
int y2 = rect.y + rect.height;
|
|
x1 = size.width - (rect.x + rect.width);
|
|
x2 = size.width - rect.x;
|
|
// __android_log_print(ANDROID_LOG_ERROR, "flip: ", "[[%d, %d], [%d, %d]]",x1, y1, x2, y2);
|
|
|
|
|
|
return cv::Rect(cv::Point2f(x1, y1), cv::Point2f(x2, y2));
|
|
}
|
|
|
|
inline std::vector<cv::Point2f> RotatePoints(const std::vector<cv::Point2f>& points, float degree,
|
|
const cv::Size &image_size) {
|
|
int width = image_size.width;
|
|
int height = image_size.height;
|
|
float radians = degree / 180 * CV_PI;
|
|
int heightNew = int(width * fabs(sin(radians)) + height * fabs(cos(radians)));
|
|
int widthNew = int(height * fabs(sin(radians)) + width * fabs(cos(radians)));
|
|
cv::Mat trans(2, 3, CV_32F);
|
|
trans = cv::getRotationMatrix2D(cv::Point2f(width / 2, height / 2), degree, 1);
|
|
trans.at<double>(0, 2) += (widthNew - width) / 2;
|
|
trans.at<double>(1, 2) += (heightNew - height) / 2;
|
|
float point3_array[points.size()][3];
|
|
for (int i = 0; i < points.size(); ++i) {
|
|
point3_array[i][0] = points[i].x;
|
|
point3_array[i][1] = points[i].y;
|
|
point3_array[i][2] = 1;
|
|
}
|
|
trans.convertTo(trans, CV_32F);
|
|
cv::Mat mat_point3s(points.size(), 3, CV_32F, point3_array);
|
|
// std::cout << mat_point3s << std::endl;
|
|
cv::Mat trans_result = mat_point3s * trans.t();
|
|
return cv::Mat_<cv::Point2f>(trans_result);
|
|
}
|
|
|
|
inline cv::Mat RotateRect(cv::Rect &rect, std::vector<cv::Point2f> &dst,
|
|
cv::Rect &trans_rect, float degree, const cv::Size &image_size) {
|
|
int width = image_size.width;
|
|
int height = image_size.height;
|
|
float radians = degree / 180 * CV_PI;
|
|
int heightNew = int(width * fabs(sin(radians)) + height * fabs(cos(radians)));
|
|
int widthNew = int(height * fabs(sin(radians)) + width * fabs(cos(radians)));
|
|
cv::Mat trans(2, 3, CV_32F);
|
|
trans = cv::getRotationMatrix2D(cv::Point2f(width / 2, height / 2), degree, 1);
|
|
trans.at<double>(0, 2) += (widthNew - width) / 2;
|
|
trans.at<double>(1, 2) += (heightNew - height) / 2;
|
|
float xmin = rect.x;
|
|
float ymin = rect.y;
|
|
float xmax = rect.x + rect.width;
|
|
float ymax = rect.y + rect.height;
|
|
float points[][3] = {{xmin, ymin, 1},
|
|
{xmax, ymin, 1},
|
|
{xmax, ymax, 1},
|
|
{xmin, ymax, 1}};
|
|
trans.convertTo(trans, CV_32F);
|
|
cv::Mat t_points(4, 3, CV_32F, points);
|
|
cv::Mat trans_points = t_points * trans.t();
|
|
dst.clear();
|
|
for (int i = 0; i < 4; ++i) {
|
|
float x = trans_points.at<float>(i, 0);
|
|
float y = trans_points.at<float>(i, 1);
|
|
dst.emplace_back(x, y);
|
|
}
|
|
float min_x = std::numeric_limits<float>::max(), max_x = 0;
|
|
float min_y = std::numeric_limits<float>::max(), max_y = 0;
|
|
for (int i = 0; i < dst.size(); ++i) {
|
|
if (dst[i].x < min_x) {
|
|
min_x = dst[i].x;
|
|
}
|
|
if (dst[i].x > max_x) {
|
|
max_x = dst[i].x;
|
|
}
|
|
if (dst[i].y < min_y) {
|
|
min_y = dst[i].y;
|
|
}
|
|
if (dst[i].y > max_y) {
|
|
max_y = dst[i].y;
|
|
}
|
|
}
|
|
trans_rect = cv::Rect(cv::Point2f(min_x, min_y), cv::Point2f(max_x, max_y));
|
|
// trans_rect = flipRectWidth(trans_rect, cv::Size(widthNew, heightNew));
|
|
return trans;
|
|
}
|
|
|
|
// Structure to hold bounding box coordinates
|
|
struct BoundingBox {
|
|
int left_top_x;
|
|
int left_top_y;
|
|
int right_bottom_x;
|
|
int right_bottom_y;
|
|
};
|
|
|
|
inline cv::Rect GetNewBox(int src_w, int src_h, cv::Rect bbox, float scale) {
|
|
// Convert cv::Rect to BoundingBox
|
|
BoundingBox box;
|
|
box.left_top_x = bbox.x;
|
|
box.left_top_y = bbox.y;
|
|
box.right_bottom_x = bbox.x + bbox.width;
|
|
box.right_bottom_y = bbox.y + bbox.height;
|
|
|
|
// Compute new bounding box
|
|
scale = std::min({static_cast<float>(src_h - 1) / bbox.height, static_cast<float>(src_w - 1) / bbox.width, scale});
|
|
|
|
float new_width = bbox.width * scale;
|
|
float new_height = bbox.height * scale;
|
|
float center_x = bbox.width / 2.0f + bbox.x;
|
|
float center_y = bbox.height / 2.0f + bbox.y;
|
|
|
|
float left_top_x = center_x - new_width / 2.0f;
|
|
float left_top_y = center_y - new_height / 2.0f;
|
|
float right_bottom_x = center_x + new_width / 2.0f;
|
|
float right_bottom_y = center_y + new_height / 2.0f;
|
|
|
|
if (left_top_x < 0) {
|
|
right_bottom_x -= left_top_x;
|
|
left_top_x = 0;
|
|
}
|
|
|
|
if (left_top_y < 0) {
|
|
right_bottom_y -= left_top_y;
|
|
left_top_y = 0;
|
|
}
|
|
|
|
if (right_bottom_x > src_w - 1) {
|
|
left_top_x -= right_bottom_x - src_w + 1;
|
|
right_bottom_x = src_w - 1;
|
|
}
|
|
|
|
if (right_bottom_y > src_h - 1) {
|
|
left_top_y -= right_bottom_y - src_h + 1;
|
|
right_bottom_y = src_h - 1;
|
|
}
|
|
|
|
// Convert back to cv::Rect for output
|
|
cv::Rect new_bbox(static_cast<int>(left_top_x), static_cast<int>(left_top_y),
|
|
static_cast<int>(right_bottom_x - left_top_x), static_cast<int>(right_bottom_y - left_top_y));
|
|
return new_bbox;
|
|
}
|
|
|
|
|
|
template<typename T>
|
|
inline bool isShortestSideGreaterThan(const cv::Rect_<T>& rect, T value, float scale) {
|
|
// Find the shortest edge
|
|
T shortestSide = std::min(rect.width / scale, rect.height / scale);
|
|
// Determines whether the shortest edge is greater than the given value
|
|
return shortestSide > value;
|
|
}
|
|
|
|
} // namespace inspire
|
|
|
|
#endif
|