opencv - 如何从 ML Kit 人脸标志点估计人脸姿势

标签 opencv computer-vision face-detection firebase-mlkit

我在 iOS 上使用 Firebase ML Kit 来检测人脸。虽然它提供欧拉 Y 和 Z 角,但它不提供欧拉 X 角(间距)。所以我想尝试使用 OpenCV solvePnp 来计算音高,如下所述: https://www.learnopencv.com/head-pose-estimation-using-opencv-and-dlib/#code

这是我的 Objective C 函数:

+(void) estimatePose:(FIRVisionFace *)face imgSize:(CGSize)imgSize {

    // Contour legend: https://firebase.google.com/docs/ml-kit/images/examples/face_contours.svg
    FIRVisionFaceContour* faceOval = [face contourOfType:FIRFaceContourTypeFace];
    FIRVisionFaceContour* leftEyeContour = [face contourOfType:FIRFaceContourTypeLeftEye];
    FIRVisionFaceContour* rightEyeContour = [face contourOfType:FIRFaceContourTypeRightEye];
    FIRVisionFaceContour* noseBridge = [face contourOfType:FIRFaceContourTypeNoseBridge];
    FIRVisionFaceContour* upperLipTop = [face contourOfType:FIRFaceContourTypeUpperLipTop];

    FIRVisionPoint* chin = faceOval.points[18];
    FIRVisionPoint* leftEyeLeftCorner = leftEyeContour.points[0];
    FIRVisionPoint* rightEyeRightCorner = rightEyeContour.points[8];
    FIRVisionPoint* noseTip = noseBridge.points[1];
    FIRVisionPoint* leftMouthCorner = upperLipTop.points[0];
    FIRVisionPoint* rightMouthCorner = upperLipTop.points[10];

    // 2D/3D model points using https://www.learnopencv.com/head-pose-estimation-using-opencv-and-dlib/#code
    image_points.push_back( cv::Point2d(noseTip.x.doubleValue, noseTip.y.doubleValue) );    // Nose tip
    image_points.push_back( cv::Point2d(chin.x.doubleValue, chin.y.doubleValue) );    // Chin
    image_points.push_back( cv::Point2d(leftEyeLeftCorner.x.doubleValue, leftEyeLeftCorner.y.doubleValue) );    // Left eye left corner
    image_points.push_back( cv::Point2d(rightEyeRightCorner.x.doubleValue, rightEyeRightCorner.y.doubleValue) );     // Right eye right corner
    image_points.push_back( cv::Point2d(leftMouthCorner.x.doubleValue, leftMouthCorner.y.doubleValue) );    // Left Mouth corner
    image_points.push_back( cv::Point2d(rightMouthCorner.x.doubleValue, rightMouthCorner.y.doubleValue) );    // Right mouth corner

    model_points.push_back(cv::Point3d(0.0f, 0.0f, 0.0f));               // Nose tip
    model_points.push_back(cv::Point3d(0.0f, -330.0f, -65.0f));          // Chin
    model_points.push_back(cv::Point3d(-225.0f, 170.0f, -135.0f));       // Left eye left corner
    model_points.push_back(cv::Point3d(225.0f, 170.0f, -135.0f));        // Right eye right corner
    model_points.push_back(cv::Point3d(-150.0f, -150.0f, -125.0f));      // Left Mouth corner
    model_points.push_back(cv::Point3d(150.0f, -150.0f, -125.0f));       // Right mouth corner

    double focal_length = imgSize.width; // Approximate focal length.
    cv::Point2d center = cv::Point2d(imgSize.width / 2, imgSize.height / 2);
    cv::Mat camera_matrix = (cv::Mat_<double>(3,3) << focal_length, 0, center.x, 0 , focal_length, center.y, 0, 0, 1);
    cv::Mat dist_coeffs = cv::Mat::zeros(4,1,cv::DataType<double>::type); // Assuming no lens distortion

    // Output rotation and translation
    cv::Mat rotation_vector; // Rotation in axis-angle form
    cv::Mat translation_vector;

    // Solve for pose
    cv::solvePnP(model_points, image_points, camera_matrix, dist_coeffs, rotation_vector, translation_vector);

    NSLog(@"Rotation Vector %f %f %f", rotation_vector.at<float>(0), rotation_vector.at<float>(1), rotation_vector.at<float>(2));
}

函数末尾的 print 语句为大多数直立姿势的脸生成了不切实际的值,例如:

Rotation Vector 430085088834445557973284941130104832.000000 -2.169656 -37005999085886043916656699445870592.000000
Rotation Vector -31942776355636779193640943616.000000 -2.163979 51918482290645906067188728866013184.000000

我做错了什么?

最佳答案

问题出在日志语句上。它需要打印 double 而不是 float :

NSLog(@"Rotation Vector %f %f %f", rotation_vector.at<double>(0), rotation_vector.at<double>(1), rotation_vector.at<double>(2));

此外,旋转矢量不是欧拉角。需要转换:

http://answers.opencv.org/question/16796/computing-attituderoll-pitch-yaw-from-solvepnp/?answer=52913#post-id-52913

关于opencv - 如何从 ML Kit 人脸标志点估计人脸姿势,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55465420/

相关文章:

opencv - 网格搜索(libsvm)中的交叉验证非常慢

c# - emguCV 3.1 - 人脸检测

javascript - 检测旋转的面孔 Microsoft 认知服务

c++ - 如何使用 cmake 将两个库链接到我的程序?

android - 基本的 Hello World 应用程序不是使用 ndk-build(.mk 文件)构建的

android - 使用OpenCV检测透视角度并进行透视变换

python - 如何旋转摄像机录制的视频?

python - 使用 python 在 opencv 中显示 imshow 不是交互式的

c++ - 在硬盘中存储一个 CvSVM 对象

machine-learning - Tensorflow对象检测API中的模型配置参数是什么?