如何在 Dlib C++ 中获取头部姿势估计的 3D 坐标轴
Posted
技术标签:
【中文标题】如何在 Dlib C++ 中获取头部姿势估计的 3D 坐标轴【英文标题】:How to get 3D coordinate Axes of head pose estimation in Dlib C++ 【发布时间】:2016-08-04 02:00:39 【问题描述】:Dlib C++ 可以很好地检测地标和估计面部姿势。但是,如何获得头部姿势的 3D 坐标轴方向 (x,y,z)?
【问题讨论】:
这个问题已经有一个可接受的答案。尽管如此,为了将来参考,还有一篇关于这个主题的精彩博客文章:learnopencv.com/head-pose-estimation-using-opencv-and-dlib 【参考方案1】:我也遇到了同样的问题,不久前,搜索并找到了 1-2 篇有用的博客文章,这个 link 将让您了解所涉及的技术,如果您只需要计算 3D 姿势小数点后你可以跳过 OpenGL 渲染部分,但是如果你想直观地获得反馈,那么你也可以尝试使用 OpenGL,但我建议你作为初学者忽略 OpenGL 部分,所以最小的工作代码 sn- p 从github 页面中提取,看起来像这样:
// Reading image using OpenCV, you may use dlib as well.
cv::Mat img = cv::imread(imagePath);
std::vector<double> rv(3), tv(3);
cv::Mat rvec(rv),tvec(tv);
cv::Vec3d eav;
// Labelling the 3D Points derived from a 3D model of human face.
// You may replace these points as per your custom 3D head model if any
std::vector<cv::Point3f > modelPoints;
modelPoints.push_back(cv::Point3f(2.37427,110.322,21.7776)); // l eye (v 314)
modelPoints.push_back(cv::Point3f(70.0602,109.898,20.8234)); // r eye (v 0)
modelPoints.push_back(cv::Point3f(36.8301,78.3185,52.0345)); //nose (v 1879)
modelPoints.push_back(cv::Point3f(14.8498,51.0115,30.2378)); // l mouth (v 1502)
modelPoints.push_back(cv::Point3f(58.1825,51.0115,29.6224)); // r mouth (v 695)
modelPoints.push_back(cv::Point3f(-61.8886f,127.797,-89.4523f)); // l ear (v 2011)
modelPoints.push_back(cv::Point3f(127.603,126.9,-83.9129f)); // r ear (v 1138)
// labelling the position of corresponding feature points on the input image.
std::vector<cv::Point2f> srcImagePoints = cv::Point2f(442, 442), // left eye
cv::Point2f(529, 426), // right eye
cv::Point2f(501, 479), // nose
cv::Point2f(469, 534), //left lip corner
cv::Point2f(538, 521), // right lip corner
cv::Point2f(349, 457), // left ear
cv::Point2f(578, 415) // right ear;
cv::Mat ip(srcImagePoints);
cv::Mat op = cv::Mat(modelPoints);
cv::Scalar m = mean(cv::Mat(modelPoints));
rvec = cv::Mat(rv);
double _d[9] = 1,0,0,
0,-1,0,
0,0,-1;
Rodrigues(cv::Mat(3,3,CV_64FC1,_d),rvec);
tv[0]=0;tv[1]=0;tv[2]=1;
tvec = cv::Mat(tv);
double max_d = MAX(img.rows,img.cols);
double _cm[9] = max_d, 0, (double)img.cols/2.0,
0 , max_d, (double)img.rows/2.0,
0 , 0, 1.0;
cv::Mat camMatrix = cv::Mat(3,3,CV_64FC1, _cm);
double _dc[] = 0,0,0,0;
solvePnP(op,ip,camMatrix,cv::Mat(1,4,CV_64FC1,_dc),rvec,tvec,false,CV_EPNP);
double rot[9] = 0;
cv::Mat rotM(3,3,CV_64FC1,rot);
Rodrigues(rvec,rotM);
double* _r = rotM.ptr<double>();
printf("rotation mat: \n %.3f %.3f %.3f\n%.3f %.3f %.3f\n%.3f %.3f %.3f\n",
_r[0],_r[1],_r[2],_r[3],_r[4],_r[5],_r[6],_r[7],_r[8]);
printf("trans vec: \n %.3f %.3f %.3f\n",tv[0],tv[1],tv[2]);
double _pm[12] = _r[0],_r[1],_r[2],tv[0],
_r[3],_r[4],_r[5],tv[1],
_r[6],_r[7],_r[8],tv[2];
cv::Mat tmp,tmp1,tmp2,tmp3,tmp4,tmp5;
cv::decomposeProjectionMatrix(cv::Mat(3,4,CV_64FC1,_pm),tmp,tmp1,tmp2,tmp3,tmp4,tmp5,eav);
printf("Face Rotation Angle: %.5f %.5f %.5f\n",eav[0],eav[1],eav[2]);
输出:
**X** **Y** **Z**
Face Rotation Angle: 171.44027 -8.72583 -9.90596
【讨论】:
感谢您的帮助,今晚我将尝试此代码:D 我正在尝试您的解决方案,但我停留在从 dlib 在链接中提供的 3d 模型中获取点的眼睛、鼻子等位置的步骤:sourceforge.net/projects/dclib/files/dlib/v18.10/…。 .dat 文件非常通用。我试图更改文件扩展名以便从一些 3D 软件中读取它,但没有用。你有什么建议吗? 你不必重写那些3D点,你只需要相应地更新srcImagePoints
。
您好,我正在尝试您的解决方案,正如您所说,我应该将相应的点放入模型中以将它们映射到 3d 模型。但是给定的 shape_predictor_68_face_landmarks.dat 文件如何标记这些点?其中有 68 个,但我们当然需要将正确的放入 srcImagePoints 中。我试图寻找某种文档,但没有发现任何有用的东西,有什么建议吗?
@ZdaR:我正在尝试这个解决方案,它似乎有效。我想通过一个“原始姿势”来稍微改变使用,所有其他姿势都将从中进行比较(我想知道对象是否已经从其原始位置移动,如果是这样计算这个变化)。可以将原点旋转角度减去当前旋转角度吗? (翻译也一样?)感谢您的帮助。以上是关于如何在 Dlib C++ 中获取头部姿势估计的 3D 坐标轴的主要内容,如果未能解决你的问题,请参考以下文章