opencvsvm算法详解(使用OpenCV和Dlib的头部姿态估计)

在许多应用中,我们需要知道头部相对于相机是如何倾斜的。例如,在虚拟现实应用程序中,人们可以使用头部的姿势来呈现场景的正确视图。在驾驶员辅助系统中,一个摄像头可以用头部姿态估计来判断司机是否注意到了道路。当然,我们可以使用基于头部姿势的手势来控制一个没有手的应用程序/游戏。显然,头部姿势估计在生活中是很有用的。

opencvsvm算法详解(使用OpenCV和Dlib的头部姿态估计)(1)

姿态估计是什么?

在计算机视觉中,物体的姿态是指物体相对于摄像机的相对方位和位置。可以通过相对于相机移动物体或相对于物体移动相机来改变姿势。

本篇文章中描述的姿态估计问题通常称为透视-n点计算机视觉术语中的问题或PNP。我们将在下面的章节中更详细地看到,在这个问题中,我们的目标是当我们有一个校准的照相机时,找到一个物体的姿态,并且我们知道N物体上的三维点和图像中相应的2D投影。

如何用数学方法表示摄像机的运动?

三维刚性物体相对于摄像机只有两种运动方式。

1. 平移:将相机从其当前的3D位置移动(X,Y,Z)到一个新的3D位置(X',Y',Z')。正如我们看到的,平移有3个自由度-你可以在X,Y或Z方向移动。翻译用向量表示。t等于(X'-X,Y'-Y,Z'-Z)。

2. 旋转:我们还可以将摄像机旋转到X,Y,Z轴。因此,旋转也有三个自由度。有许多表示旋转的方法。我们可以使用欧拉角(滚动、俯仰和偏航),a 旋转矩阵,或旋转方向(即轴)和角度.

因此,估计三维物体的姿态意味着找到6个数字--3个用于平移,3个用于旋转。

估计姿态需要什么?

opencvsvm算法详解(使用OpenCV和Dlib的头部姿态估计)(2)

要计算图像中物体的三维姿态,需要以下信息

1. 几个点的二维坐标:我们需要二维(x,y)位置的几个点的图像。在上图情况中,我们可以选择眼角,鼻尖,嘴角等等。面部标志探测器为我们提供了很多可供选择的地方。在本篇文章中,我们将使用鼻尖,下巴,左眼的左角,右眼的右角,嘴角的左下角和嘴角。

2. 相同点的三维位置:我们还需要2D特征点的三维位置。你可能会想,我们需要照片中人的三维模型,以获得三维位置。理想情况下,是的,但实际上并非如此。一个通用的3D模型就足够了。你从哪里得到头部的三维模型?我们不需要一个完整的3D模型。你只需要一些任意参照系中的几个点的3D位置。在本篇文章中,我们将使用以下3D点。

鼻尖:(0.0,0.0,0.0)

下巴:(0.0,-330.0,-65.0)

左眼角:(-225.0f,170.0f,-135.0)

右眼角:(225.0,170.0,-135.0)

嘴角:(-150.0,-150.0,-125.0)

嘴角:(150.0,-150.0,-125.0)

请注意,上述各点位于某些任意的参考框架/坐标系中。这叫做世界坐标(OpenCV文档中的模型坐标)。

3. 摄像机固有参数。如前所述,在这个问题中,相机被假定是校准的。换句话说,我们需要知道相机的焦距,图像中的光学中心和径向畸变参数。所以我们需要校准相机。我们可以用图像的中心近似光学中心,近似焦距由图像的宽度(以像素为单位)并假定径向失真不存在。

姿态估计算法是如何工作的?

姿态估计有几种算法。第一个已知的算法可以追溯到1841年。解释这些算法的细节超出了这篇文章的范围,但是这里有一个一般性的想法。

这里有三个坐标系。上述各种面部特征的三维坐标如下所示世界坐标。如果我们知道旋转和平移(即姿态),我们就可以将世界坐标中的3d点转换为相机坐标。相机坐标中的三维点可以投影到图像平面上。图像坐标系)利用摄像机的本征参数(焦距、光学中心等)。

opencvsvm算法详解(使用OpenCV和Dlib的头部姿态估计)(3)

Levenberg-Marquardt优化

由于一些原因,DLT解决方案不太准确。第一,旋转有三个自由度,但DLT解中使用的矩阵表示有9个数字。DLT解中没有任何东西强迫估计的3×3矩阵为旋转矩阵。更重要的是,DLT解决方案不会最小化正确的目标函数。理想情况下,我们希望将重投影误差如下所述。

如方程式所示2和3,如果我们知道正确的姿势(和)通过将三维点投影到二维图像上,可以预测三维人脸点在图像上的二维位置。换句话说,如果我们知道和我们能找到重点在图像中每一个3D点.

opencvsvm算法详解(使用OpenCV和Dlib的头部姿态估计)(4)

opencvsvm算法详解(使用OpenCV和Dlib的头部姿态估计)(5)

我们还知道二维面部特征点(使用dlib或手动单击)。我们可以观察投影三维点和二维面部特征之间的距离。当估计的姿态完美时,投影到图像平面上的三维点几乎与二维人脸特征一致。当姿态估计不正确时,我们可以计算出再投影误差测量-投影三维点和二维面部特征点之间的平方距离之和。

如前所述,对姿势的大致估计(R和t)可以使用DLT解决方案找到。改进DLT解决方案是随机改变姿势(R和t)并检查重投影误差是否减小。如果是的话,我们可以接受新的姿态估计。

OpenCV解决方案

在OpenCV中解决PnP和SolvePnPRansac可以用来估计姿势。

解决PnP实现了几种可以使用参数选择的姿态估计算法。SOLVEPNP迭代它本质上是DLT解,其次是Levenberg-Marquardt优化。SOLVEPNP_P3P只使用一部分内容来计算姿势,只在使用时才调用。

在OpenCV 3中,引入了两种新方法-SOLVEPNP_DLS和SOLVEPNP_UPnP。有趣的是SOLVEPNP_UPnP它也试图估计摄像机的内部参数。

SolvePnPRansac非常类似于解决PnP只是它用随机样本一致性(RANSAC)来准确地估计姿势。

当我们怀疑一些数据噪声比较大时,使用RANSAC是非常有用的。例如,考虑将一条线拟合到2D点的问题。这个问题可以用线性最小二乘法来解决,其中所有点离拟合线的距离都是最小的。现在来考虑一个糟糕的数据点,这个数据点离我们很远。这一个数据点可以控制最小二乘解,我们对这条线的估计是非常错误的。在RANSAC中,参数是通过随机选择所需的最小点数来估计的。在一个直线拟合问题中,我们从所有数据中随机选取两个点,并找到通过它们的直线。其他距离这条线足够近的数据点被称为“不动点”(Inliers)。通过随机选取两点得到直线的多个估计值,并选取最大误差数的直线作为正确的估计。

使用SolvePnPRansac的参数如下所示。SolvePnPRansac都被解释了。

C *无效SolvePnPRansac(InputArray ObjectPoint,InputArray ImagePoint,InputArray CameraMatrix,InputArray disCoeffs,OutputArray rvec,OutputArray TVEC,bool useExtrinsicGuess=false,int iterationsCount=100,浮动重投影Error=8.0,int minInliersCount=100,OutputArray inliers=noArray(),int标志=迭代)

Python:cv2.solvePnPRansac(ObjectPoint,ImagePoint,CameraMatrix,distCoeffs[,rvec[,tvc[,useExtrinsicGuess[,iterationsCount[,reprojectionError[,minInliersCount[,Inliers[,标志])→rvec,tvc,inliers

迭代计数-挑选最低点数的次数和估计参数。重投射错误-正如前面在RANSAC中提到的,预测足够接近的点称为“不稳定点”。这个参数值是观测到的点投影和计算的点投影之间的最大允许距离,从而认为它是一个独立点。

MinInliersCount-不稳定因素的数目。如果算法在某个阶段发现了比minInliersCount更多的inliersCount,它就完成了。衬垫-输出向量,其中包含ObtPoint和ImagePoint中的inliers索引。

OpenCV POSIT

OpenCV习惯于一种名为POSIT的姿态估计算法。它仍然存在于C API中(CvPosit),但不是C API的一部分。PREST假设一个缩放的正射相机模型,因此你不需要提供焦距估计。这个函数现在已经过时了,我们建议使用SolvePnp。我们提供了源程序代码,感兴趣的小伙伴们可以尝试一下。

#include <opencv2/opencv.hpp> usingnamespacestd; usingnamespacecv; int main(int argc, char **argv) { //Readinputimage cv::Matim=cv::imread("headPose.jpg"); //2Dimagepoints.Ifyouchangetheimage,youneedtochangevector std::vector<cv::Point2d>image_points; image_points.push_back(cv::Point2d(359,391));//Nosetip image_points.push_back(cv::Point2d(399,561));//Chin image_points.push_back(cv::Point2d(337,297));//Lefteyeleftcorner image_points.push_back(cv::Point2d(513,301));//Righteyerightcorner image_points.push_back(cv::Point2d(345,465));//LeftMouthcorner image_points.push_back(cv::Point2d(453,469));//Rightmouthcorner //3Dmodelpoints. std::vector<cv::Point3d>model_points; model_points.push_back(cv::Point3d(0.0f,0.0f,0.0f));//Nosetip 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));//Lefteyeleftcorner model_points.push_back(cv::Point3d(225.0f,170.0f,-135.0f));//Righteyerightcorner model_points.push_back(cv::Point3d(-150.0f,-150.0f,-125.0f));//LeftMouthcorner model_points.push_back(cv::Point3d(150.0f,-150.0f,-125.0f));//Rightmouthcorner //Camerainternals doublefocal_length=im.cols;//Approximatefocallength. Point2dcenter=cv::Point2d(im.cols/2,im.rows/2); cv::Matcamera_matrix=(cv::Mat_<double>(3,3)<<focal_length,0,center.x,0,focal_length,center.y,0,0,1); cv::Matdist_coeffs=cv::Mat::zeros(4,1,cv::DataType<double>::type);//Assumingnolensdistortion cout<<"CameraMatrix"<<endl<<camera_matrix<<endl; //Outputrotationandtranslation cv::Matrotation_vector;//Rotationinaxis-angleform cv::Mattranslation_vector; //Solveforpose cv::solvePnP(model_points,image_points,camera_matrix,dist_coeffs,rotation_vector,translation_vector); //Projecta3Dpoint(0,0,1000.0)ontotheimageplane. //Weusethistodrawalinestickingoutofthenose vector<Point3d>nose_end_point3D; vector<Point2d>nose_end_point2D; nose_end_point3D.push_back(Point3d(0,0,1000.0)); projectPoints(nose_end_point3D,rotation_vector,translation_vector,camera_matrix,dist_coeffs,nose_end_point2D); for(inti=0;i<image_points.size();i ) { circle(im,image_points[i],3,Scalar(0,0,255),-1); } cv::line(im,image_points[0],nose_end_point2D[0],cv::Scalar(255,0,0),2); cout<<"RotationVector"<<endl<<rotation_vector<<endl; cout<<"TranslationVector"<<endl<<translation_vector<<endl; cout<<nose_end_point2D<<endl; //Displayimage. cv::imshow("Output",im); cv::waitKey(0); }

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页