## 先上结果
红色的是用网上普遍的方法,参照是以旷视人脸检测的api。用六个关键点来评估误差太大,没啥用。
## 环境:
说是C# 写的,实际都是调用opencv跟dlib的封装包。
## code:
主要代码opencv的Cv2.SolvePnP
输入为六个人脸关键点,图像宽和高,获取关键点还是最下面项目github看吧。
public Angles GetAnglesAndPoints(Mat<Point2d> points, int width, int height) { var cameraMatrix = new Mat<double>(3, 3, new double[] { width, 0, width / 2, 0, width, height / 2, 0, 0, 1 }); var dist = new Mat<double> { 0, 0, 0, 0, 0 }; var rvec = new Mat<double>(); var tvec = new Mat(); var Model_points = new Mat<Point3f> { new Point3f(0.0f, 0.0f, 0.0f), // Nose tip new Point3f(0.0f, -330.0f, -65.0f), // Chin new Point3f(-225.0f, 170.0f, -135.0f), // Left eye left corner new Point3f(225.0f, 170.0f, -135.0f), // Right eye right corne new Point3f(-150.0f, -150.0f, -125.0f), // Left Mouth corner new Point3f(150.0f, -150.0f, -125.0f) // Right mouth corner }; Cv2.SolvePnP(Model_points, points, cameraMatrix, dist, rvec, tvec, flags: SolvePnPFlags.Iterative); return GetEulerAngle(rvec); }
旋转向量转化为欧拉角
public Angles GetEulerAngle(Mat<double> rotation_vector) { var rotArray = rotation_vector.ToArray(); Mat mat = new Mat(3, 1, MatType.CV_64FC1, rotArray); var theta = Cv2.Norm(mat, NormTypes.L2); var w = Math.Cos(theta / 2); var x = Math.Sin(theta / 2) * rotArray[0] / theta; var y = Math.Sin(theta / 2) * rotArray[1] / theta; var z = Math.Sin(theta / 2) * rotArray[2] / theta; var ysqr = y * y; // pitch (x-axis rotation) var t0 = 2.0 * (w * x + y * z); var t1 = 1.0 - 2.0 * (x * x + ysqr); var pitch = Math.Atan2(t0, t1);//反正切(给坐标轴,x,y) // yaw (y-axis rotation) var t2 = 2.0 * (w * y - z * x); if (t2 > 1.0) t2 = 1.0; if (t2 < -1.0) t2 = -1.0; var yaw = Math.Asin(t2); //反正弦函数 // roll (z-axis rotation) var t3 = 2.0 * (w * z + x * y); var t4 = 1.0 - 2.0 * (ysqr + z * z); var roll = Math.Atan2(t3, t4); // 单位转换:将弧度转换为度 var Y = (pitch / Math.PI) * 180; Y = Math.Sign(Y) * 180 - Y; var X = (yaw / Math.PI) * 180; var Z = (roll / Math.PI) * 180; Angles angles = new Angles() { Pitch = Y, Roll = Z, Yaw = X }; return angles; }
Angles就三个属性
public class Angles { public double Roll { get; set; } public double Pitch { get; set; } public double Yaw { get; set; } }
效果图:(图源网络,侵删)
## 引用:
C++实现 https://blog.csdn.net/u013512448/article/details/77804161
python实现 https://blog.csdn.net/loveliuzz/article/details/102716290
旷视api调用 https://www.faceplusplus.com.cn/face-detection/
人脸识别 https://github.com/takuya-takeuchi/FaceRecognitionDotNet
C# 实现 https://github.com/TrojanOlx/AI
https://github.com/cheat13/FaceDetect
https://github.com/Zhaofan-Su/FaceRig-Scripts(这个项目太旧,可以运行,但升级最新的opencv没成功)
结尾:
网上基于6个关键点评估方法并不靠谱,误差太大,完全没有实用价值。
文章代码:https://github.com/zlyxm/HeadPoseSharp
FaceRecognitionDotNet 最新版(1.3.0.2)已经支持关键点评估,比6个关键点强不知道多少,不过模型要自己训练就是,试下看。渣渣电脑训练了1天15个钟才45.43%....