如何在Dlib C++中获取头部姿势估计的三维坐标轴

8

Dlib C++可以非常好地检测特征点和估计面部姿势。但是,如何获取头部姿势的三维坐标轴方向(x,y,z)?


1
这个问题已经有一个被接受的答案了。不过,为了以后参考,这里还有一篇关于这个主题的很好的博客文章:http://www.learnopencv.com/head-pose-estimation-using-opencv-and-dlib/ - Luiz Vieira
1个回答

16
我曾经遇到了同样的问题,一段时间前进行了搜索,并找到了1-2篇有用的博客文章。这个链接可以帮助你了解涉及的技术概述。如果您只需要计算小数位的3D姿态,则可以跳过OpenGL渲染部分。但是,如果您想要直观的反馈,则也可以尝试使用OpenGL。但是我建议初学者忽略OpenGL部分。因此,从github页面提取的最小工作代码片段将如下所示:

enter image description here

// 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 - Rain Maker
我正在尝试您提供的解决方案,但是在从dlib提供的链接(http://sourceforge.net/projects/dclib/files/dlib/v18.10/shape_predictor_68_face_landmarks.dat.bz2)获取眼睛、鼻子等点位置的步骤中卡住了。该.dat文件非常通用。我尝试更改文件扩展名以从某些3D软件中读取它,但没有用。您有什么建议吗? - Rain Maker
您无需重写这些3D点,只需要相应地更新“srcImagePoints”即可。 - ZdaR
嗨,我正在尝试您的解决方案,正如您所说,我应该将相应的点放入模型中,以便将它们映射到3D模型中。但是给定的shape_predictor_68_face_landmarks.dat文件如何标记这些点呢?虽然有68个点,但我们当然需要获取正确的点放入srcImagePoints中。我已经尝试查找一些文档,但没有找到任何有用的信息,对此有什么建议吗? - fiipi
@ZdaR:我正在尝试这个解决方案,它似乎有效。我想稍微改变一下使用方式,通过设置“原始姿态”来比较所有其他姿态(我想知道物体是否已经从其原始位置移动,如果是,则计算此更改)。 只需将原始旋转角度减去当前旋转角度即可吗?(平移也是如此吗?) 感谢您的帮助。 - Irisciences
@Irisciences 关于翻译部分,它应该可以正常工作,但我不确定旋转部分是否有效,不过您可以尝试一下看看是否有效? - ZdaR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接