这是我的第一篇帖子,我会尽力描述问题。我正在尝试使用OpenCV、Dlib和网络摄像头数据实时地对3D虚拟角色的面部进行动画化,类似于this software等高级应用程序。
在 这里的示例 的指导下,使用网络摄像头,我可以在屏幕空间中获得实时的2D面部标志数据,以及头部姿态的3D位移数据的估计。但我真正想知道的是面部标志的估计3D世界坐标。例如,当头部向一侧倾斜30度时,嘴巴的外观与演员做“w”形状时相同。
有人能告诉我将这些2D面部标志转换为3D数据的策略是什么,或者这就是使这些实时面部动画应用程序如此昂贵的原因吗?
std::vector<cv::Point3d> object_pts;
std::vector<cv::Point2d> image_pts;
std::vector<cv::Point3d> reprojectsrc;
std::vector<cv::Point2d> reprojectdst;
cv::Mat rotation_vec;
cv::Mat rotation_mat;
cv::Mat translation_vec;
cv::Mat pose_mat;
cv::Mat euler_angle;
cv::Mat cam_matrix;
cv::Mat dist_coeffs;
cv::Mat out_intrinsics;
cv::Mat out_rotation;
cv::Mat out_translation;
int UpdateFace(dlib::cv_image<dlib::bgr_pixel> cimg, dlib::rectangle face)
{
// get facial landmarks
shape = predictor(cimg, face);
// draw facial landmarks
for (unsigned int i = 0; i < 68; ++i)
{
cv::circle(frame, cv::Point(shape.part(i).x(), shape.part(i).y()), 2, cv::Scalar(0, 0, 255), -1);
}
// clear data and fill in 2D ref points
image_pts.clear();
//#17 left brow left corner
image_pts.push_back(cv::Point2d(shape.part(17).x(), shape.part(17).y()));
//#21 left brow right corner
image_pts.push_back(cv::Point2d(shape.part(21).x(), shape.part(21).y()));
//#22 right brow left corner
image_pts.push_back(cv::Point2d(shape.part(22).x(), shape.part(22).y()));
//#26 right brow right corner
image_pts.push_back(cv::Point2d(shape.part(26).x(), shape.part(26).y()));
//#36 left eye left corner
image_pts.push_back(cv::Point2d(shape.part(36).x(), shape.part(36).y()));
//#39 left eye right corner
image_pts.push_back(cv::Point2d(shape.part(39).x(), shape.part(39).y()));
//#42 right eye left corner
image_pts.push_back(cv::Point2d(shape.part(42).x(), shape.part(42).y()));
//#45 right eye right corner
image_pts.push_back(cv::Point2d(shape.part(45).x(), shape.part(45).y()));
//#31 nose left corner
image_pts.push_back(cv::Point2d(shape.part(31).x(), shape.part(31).y()));
//#35 nose right corner
image_pts.push_back(cv::Point2d(shape.part(35).x(), shape.part(35).y()));
//#48 mouth left corner
image_pts.push_back(cv::Point2d(shape.part(48).x(), shape.part(48).y()));
//#54 mouth right corner
image_pts.push_back(cv::Point2d(shape.part(54).x(), shape.part(54).y()));
//#57 mouth central bottom corner
image_pts.push_back(cv::Point2d(shape.part(57).x(), shape.part(57).y()));
//#8 chin corner
image_pts.push_back(cv::Point2d(shape.part(8).x(), shape.part(8).y()));
// calculate the head pose
cv::solvePnP(object_pts, image_pts, cam_matrix, dist_coeffs, rotation_vec, translation_vec);
// reproject
cv::projectPoints(reprojectsrc, rotation_vec, translation_vec, cam_matrix, dist_coeffs, reprojectdst);
//draw 3d box around the actors head
cv::line(frame, reprojectdst[0], reprojectdst[1], cv::Scalar(0, 0, 255));
cv::line(frame, reprojectdst[1], reprojectdst[2], cv::Scalar(0, 0, 255));
cv::line(frame, reprojectdst[2], reprojectdst[3], cv::Scalar(0, 0, 255));
cv::line(frame, reprojectdst[3], reprojectdst[0], cv::Scalar(0, 0, 255));
cv::line(frame, reprojectdst[4], reprojectdst[5], cv::Scalar(0, 0, 255));
cv::line(frame, reprojectdst[5], reprojectdst[6], cv::Scalar(0, 0, 255));
cv::line(frame, reprojectdst[6], reprojectdst[7], cv::Scalar(0, 0, 255));
cv::line(frame, reprojectdst[7], reprojectdst[4], cv::Scalar(0, 0, 255));
cv::line(frame, reprojectdst[0], reprojectdst[4], cv::Scalar(0, 0, 255));
cv::line(frame, reprojectdst[1], reprojectdst[5], cv::Scalar(0, 0, 255));
cv::line(frame, reprojectdst[2], reprojectdst[6], cv::Scalar(0, 0, 255));
cv::line(frame, reprojectdst[3], reprojectdst[7], cv::Scalar(0, 0, 255));
//calculate euler angle to move avatars head
cv::Rodrigues(rotation_vec, rotation_mat);
cv::hconcat(rotation_mat, translation_vec, pose_mat);
cv::decomposeProjectionMatrix(pose_mat, out_intrinsics, out_rotation,
out_translation, cv::noArray(), cv::noArray(), cv::noArray(), euler_angle);
// calculate 3D transformation of facial landmarks to animate avatars facial features
// code needed here ...
}