162 lines
6.0 KiB
C++
162 lines
6.0 KiB
C++
#include <opencv2/opencv.hpp>
|
|
#include <vector>
|
|
#include <cmath>
|
|
#include "svp_opencv.h"
|
|
|
|
// 预定义的68个3D模型点 (需补全剩余点)
|
|
const std::vector<cv::Point3f> model_points_68 = {
|
|
{-73.393523f, -29.801432f, -47.667532f},
|
|
{-72.775014f, -10.949766f, -45.909403f},
|
|
{-70.533638f, 7.929818f, -44.84258f},
|
|
{-66.850058f, 26.07428f, -43.141114f},
|
|
{-59.790187f, 42.56439f, -38.635298f},
|
|
{-48.368973f, 56.48108f, -30.750622f},
|
|
{-34.121101f, 67.246992f, -18.456453f},
|
|
{-17.875411f, 75.056892f, -3.609035f},
|
|
{0.098749f, 77.061286f, 0.881698f},
|
|
{17.477031f, 74.758448f, -5.181201f},
|
|
{32.648966f, 66.929021f, -19.176563f},
|
|
{46.372358f, 56.311389f, -30.77057f},
|
|
{57.34348f, 42.419126f, -37.628629f},
|
|
{64.388482f, 25.45588f, -40.886309f},
|
|
{68.212038f, 6.990805f, -42.281449f},
|
|
{70.486405f, -11.666193f, -44.142567f},
|
|
{71.375822f, -30.365191f, -47.140426f},
|
|
{-61.119406f, -49.361602f, -14.254422f},
|
|
{-51.287588f, -58.769795f, -7.268147f},
|
|
{-37.8048f, -61.996155f, -0.442051f},
|
|
{-24.022754f, -61.033399f, 6.606501f},
|
|
{-11.635713f, -56.686759f, 11.967398f},
|
|
{12.056636f, -57.391033f, 12.051204f},
|
|
{25.106256f, -61.902186f, 7.315098f},
|
|
{38.338588f, -62.777713f, 1.022953f},
|
|
{51.191007f, -59.302347f, -5.349435f},
|
|
{60.053851f, -50.190255f, -11.615746f},
|
|
{0.65394f, -42.19379f, 13.380835f},
|
|
{0.804809f, -30.993721f, 21.150853f},
|
|
{0.992204f, -19.944596f, 29.284036f},
|
|
{1.226783f, -8.414541f, 36.94806f},
|
|
{-14.772472f, 2.598255f, 20.132003f},
|
|
{-7.180239f, 4.751589f, 23.536684f},
|
|
{0.55592f, 6.5629f, 25.944448f},
|
|
{8.272499f, 4.661005f, 23.695741f},
|
|
{15.214351f, 2.643046f, 20.858157f},
|
|
{-46.04729f, -37.471411f, -7.037989f},
|
|
{-37.674688f, -42.73051f, -3.021217f},
|
|
{-27.883856f, -42.711517f, -1.353629f},
|
|
{-19.648268f, -36.754742f, 0.111088f},
|
|
{-28.272965f, -35.134493f, 0.147273f},
|
|
{-38.082418f, -34.919043f, -1.476612f},
|
|
{19.265868f, -37.032306f, 0.665746f},
|
|
{27.894191f, -43.342445f, -0.24766f},
|
|
{37.437529f, -43.110822f, -1.696435f},
|
|
{45.170805f, -38.086515f, -4.894163f},
|
|
{38.196454f, -35.532024f, -0.282961f},
|
|
{28.764989f, -35.484289f, 1.172675f},
|
|
{-28.916267f, 28.612716f, 2.24031f},
|
|
{-17.533194f, 22.172187f, 15.934335f},
|
|
{-6.68459f, 19.029051f, 22.611355f},
|
|
{0.381001f, 20.721118f, 23.748437f},
|
|
{8.375443f, 19.03546f, 22.721995f},
|
|
{18.876618f, 22.394109f, 15.610679f},
|
|
{28.794412f, 28.079924f, 3.217393f},
|
|
{19.057574f, 36.298248f, 14.987997f},
|
|
{8.956375f, 39.634575f, 22.554245f},
|
|
{0.381549f, 40.395647f, 23.591626f},
|
|
{-7.428895f, 39.836405f, 22.406106f},
|
|
{-18.160634f, 36.677899f, 15.121907f},
|
|
{-24.37749f, 28.677771f, 4.785684f},
|
|
{-6.897633f, 25.475976f, 20.893742f},
|
|
{0.340663f, 26.014269f, 22.220479f},
|
|
{8.444722f, 25.326198f, 21.02552f},
|
|
{24.474473f, 28.323008f, 5.712776f},
|
|
{8.449166f, 30.596216f, 20.671489f},
|
|
{0.205322f, 31.408738f, 21.90367f},
|
|
{-7.198266f, 30.844876f, 20.328022f}
|
|
};
|
|
|
|
xmedia_s32 svp_opencv_face_orientation(const xmedia_svp_keypoint *landmarks, svp_euler_angles *angles)
|
|
{
|
|
if (landmarks == XMEDIA_NULL || angles == XMEDIA_NULL) {
|
|
printf("svp_opencv_face_orientation param is NULL!\n");
|
|
return XMEDIA_FAILURE;
|
|
}
|
|
|
|
// 转换关键点到图像坐标
|
|
std::vector<cv::Point2f> image_points;
|
|
for (xmedia_u8 i = 0; i < MAX_DETECT_KEYPOINT_NUM; i++) {
|
|
image_points.emplace_back(landmarks[i].x, landmarks[i].y);
|
|
}
|
|
|
|
// 相机内参矩阵
|
|
xmedia_double center_x = 640 / 2;
|
|
xmedia_double center_y = 360 / 2;
|
|
xmedia_double focal_length = center_x / tan(30 * CV_PI / 180);
|
|
cv::Mat camera_matrix = (cv::Mat_<xmedia_double>(3,3) <<
|
|
focal_length, 0, center_x,
|
|
0, focal_length, center_y,
|
|
0, 0, 1);
|
|
|
|
// 畸变系数, 后续需要根据不同sensor设置?
|
|
cv::Mat dist_coeffs = cv::Mat::zeros(4, 1, CV_64F);
|
|
// 初始化猜测
|
|
cv::Mat r_vec = (cv::Mat_<xmedia_double>(3,1) << 0.01891013, 0.08560084, -3.14392813);
|
|
cv::Mat t_vec = (cv::Mat_<xmedia_double>(3,1) << -14.97821226, -10.62040383, -2053.03596872);
|
|
|
|
bool success = cv::solvePnP(
|
|
model_points_68,
|
|
image_points,
|
|
camera_matrix,
|
|
dist_coeffs,
|
|
r_vec,
|
|
t_vec,
|
|
true, // 使用外部猜测
|
|
cv::SOLVEPNP_ITERATIVE
|
|
);
|
|
|
|
if (!success) {
|
|
printf("solvePnP error\n");
|
|
return XMEDIA_FAILURE;
|
|
}
|
|
|
|
// 转换旋转向量为矩阵
|
|
cv::Mat rvec_matrix;
|
|
cv::Rodrigues(r_vec, rvec_matrix);
|
|
|
|
// 构建投影矩阵
|
|
cv::Mat proj_matrix(3, 4, CV_64F);
|
|
cv::hconcat(rvec_matrix, t_vec, proj_matrix);
|
|
|
|
// 分解投影矩阵求欧拉角, 实现旋转矩阵到欧拉角的转换
|
|
xmedia_double sy = std::sqrt(rvec_matrix.at<xmedia_double>(0,0) * rvec_matrix.at<xmedia_double>(0,0) +
|
|
rvec_matrix.at<xmedia_double>(1,0) * rvec_matrix.at<xmedia_double>(1,0));
|
|
|
|
xmedia_double x, y, z;
|
|
if (!(sy < 1e-6)) {
|
|
x = std::atan2(rvec_matrix.at<xmedia_double>(2,1), rvec_matrix.at<xmedia_double>(2,2));
|
|
y = std::atan2(-rvec_matrix.at<xmedia_double>(2,0), sy);
|
|
z = std::atan2(rvec_matrix.at<xmedia_double>(1,0), rvec_matrix.at<xmedia_double>(0,0));
|
|
} else {
|
|
x = std::atan2(-rvec_matrix.at<xmedia_double>(1,2), rvec_matrix.at<xmedia_double>(1,1));
|
|
y = std::atan2(-rvec_matrix.at<xmedia_double>(2,0), sy);
|
|
z = 0;
|
|
}
|
|
|
|
// 原始弧度转角度
|
|
x = x * 180 / CV_PI;
|
|
y = y * 180 / CV_PI;
|
|
z = z * 180 / CV_PI;
|
|
|
|
// 角度范围修正
|
|
angles->pitch = std::asin(std::sin(x * CV_PI / 180)) * 180 / CV_PI;
|
|
angles->roll = -std::asin(std::sin(z * CV_PI / 180)) * 180 / CV_PI;
|
|
angles->yaw = std::asin(std::sin(y * CV_PI / 180)) * 180 / CV_PI;
|
|
|
|
// 确保角度在-90到90度范围内
|
|
angles->pitch = std::max(std::min(angles->pitch, 90.0), -90.0);
|
|
angles->roll = std::max(std::min(angles->roll, 90.0), -90.0);
|
|
angles->yaw = std::max(std::min(angles->yaw, 90.0), -90.0);
|
|
|
|
return XMEDIA_SUCCESS;
|
|
}
|