<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          使用OpenCV和Dlib的頭部姿態(tài)估計

          共 8332字,需瀏覽 17分鐘

           ·

          2021-06-24 19:15

          點(diǎn)擊上方小白學(xué)視覺”,選擇加"星標(biāo)"或“置頂

          重磅干貨,第一時間送達(dá)

          在許多應(yīng)用中,我們需要知道頭部相對于相機(jī)是如何傾斜的。例如,在虛擬現(xiàn)實(shí)應(yīng)用程序中,人們可以使用頭部的姿勢來呈現(xiàn)場景的正確視圖。在駕駛員輔助系統(tǒng)中,一個攝像頭可以用頭部姿態(tài)估計來判斷司機(jī)是否注意到了道路。當(dāng)然,我們可以使用基于頭部姿勢的手勢來控制一個沒有手的應(yīng)用程序/游戲。顯然,頭部姿勢估計在生活中是很有用的。


          姿態(tài)估計是什么?


          在計算機(jī)視覺中,物體的姿態(tài)是指物體相對于攝像機(jī)的相對方位和位置。可以通過相對于相機(jī)移動物體或相對于物體移動相機(jī)來改變姿勢。


          本篇文章中描述的姿態(tài)估計問題通常稱為透視-n點(diǎn)計算機(jī)視覺術(shù)語中的問題或PNP。我們將在下面的章節(jié)中更詳細(xì)地看到,在這個問題中,我們的目標(biāo)是當(dāng)我們有一個校準(zhǔn)的照相機(jī)時,找到一個物體的姿態(tài),并且我們知道N物體上的三維點(diǎn)和圖像中相應(yīng)的2D投影。


          如何用數(shù)學(xué)方法表示攝像機(jī)的運(yùn)動?


          三維剛性物體相對于攝像機(jī)只有兩種運(yùn)動方式。


          1. 平移:將相機(jī)從其當(dāng)前的3D位置移動(X,Y,Z)到一個新的3D位置(X',Y',Z')。正如我們看到的,平移有3個自由度-你可以在X,Y或Z方向移動。翻譯用向量表示。t等于(X'-X,Y'-Y,Z'-Z)。

          2. 旋轉(zhuǎn):我們還可以將攝像機(jī)旋轉(zhuǎn)到X,Y,Z軸。因此,旋轉(zhuǎn)也有三個自由度。有許多表示旋轉(zhuǎn)的方法。我們可以使用歐拉角(滾動、俯仰和偏航),a 旋轉(zhuǎn)矩陣,或旋轉(zhuǎn)方向(即軸)和角度.

          因此,估計三維物體的姿態(tài)意味著找到6個數(shù)字--3個用于平移,3個用于旋轉(zhuǎn)。


          估計姿態(tài)需要什么?

          要計算圖像中物體的三維姿態(tài),需要以下信息


          1. 幾個點(diǎn)的二維坐標(biāo):我們需要二維(x,y)位置的幾個點(diǎn)的圖像。在上圖情況中,我們可以選擇眼角,鼻尖,嘴角等等。面部標(biāo)志探測器為我們提供了很多可供選擇的地方。在本篇文章中,我們將使用鼻尖,下巴,左眼的左角,右眼的右角,嘴角的左下角和嘴角。

          2. 相同點(diǎn)的三維位置:我們還需要2D特征點(diǎn)的三維位置。你可能會想,我們需要照片中人的三維模型,以獲得三維位置。理想情況下,是的,但實(shí)際上并非如此。一個通用的3D模型就足夠了。你從哪里得到頭部的三維模型?我們不需要一個完整的3D模型。你只需要一些任意參照系中的幾個點(diǎn)的3D位置。在本篇文章中,我們將使用以下3D點(diǎn)。

          鼻尖:(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)

          請注意,上述各點(diǎn)位于某些任意的參考框架/坐標(biāo)系中。這叫做世界坐標(biāo)(OpenCV文檔中的模型坐標(biāo))。


          3. 攝像機(jī)固有參數(shù)。如前所述,在這個問題中,相機(jī)被假定是校準(zhǔn)的。換句話說,我們需要知道相機(jī)的焦距,圖像中的光學(xué)中心和徑向畸變參數(shù)。所以我們需要校準(zhǔn)相機(jī)。我們可以用圖像的中心近似光學(xué)中心,近似焦距由圖像的寬度(以像素為單位)并假定徑向失真不存在。


          姿態(tài)估計算法是如何工作的?


          姿態(tài)估計有幾種算法。第一個已知的算法可以追溯到1841年。解釋這些算法的細(xì)節(jié)超出了這篇文章的范圍,但是這里有一個一般性的想法。


          這里有三個坐標(biāo)系。上述各種面部特征的三維坐標(biāo)如下所示世界坐標(biāo)。如果我們知道旋轉(zhuǎn)和平移(即姿態(tài)),我們就可以將世界坐標(biāo)中的3d點(diǎn)轉(zhuǎn)換為相機(jī)坐標(biāo)。相機(jī)坐標(biāo)中的三維點(diǎn)可以投影到圖像平面上。圖像坐標(biāo)系)利用攝像機(jī)的本征參數(shù)(焦距、光學(xué)中心等)。



          Levenberg-Marquardt優(yōu)化


          由于一些原因,DLT解決方案不太準(zhǔn)確。第一,旋轉(zhuǎn)有三個自由度,但DLT解中使用的矩陣表示有9個數(shù)字。DLT解中沒有任何東西強(qiáng)迫估計的3×3矩陣為旋轉(zhuǎn)矩陣。更重要的是,DLT解決方案不會最小化正確的目標(biāo)函數(shù)。理想情況下,我們希望將重投影誤差如下所述。


          如方程式所示2和3,如果我們知道正確的姿勢(和)通過將三維點(diǎn)投影到二維圖像上,可以預(yù)測三維人臉點(diǎn)在圖像上的二維位置。換句話說,如果我們知道和我們能找到重點(diǎn)在圖像中每一個3D點(diǎn).

          我們還知道二維面部特征點(diǎn)(使用dlib或手動單擊)。我們可以觀察投影三維點(diǎn)和二維面部特征之間的距離。當(dāng)估計的姿態(tài)完美時,投影到圖像平面上的三維點(diǎn)幾乎與二維人臉特征一致。當(dāng)姿態(tài)估計不正確時,我們可以計算出再投影誤差測量-投影三維點(diǎn)和二維面部特征點(diǎn)之間的平方距離之和。


          如前所述,對姿勢的大致估計(R和t)可以使用DLT解決方案找到。改進(jìn)DLT解決方案是隨機(jī)改變姿勢(R和t)并檢查重投影誤差是否減小。如果是的話,我們可以接受新的姿態(tài)估計。


          OpenCV解決方案


          在OpenCV中解決PnP和SolvePnPRansac可以用來估計姿勢。


          解決PnP實(shí)現(xiàn)了幾種可以使用參數(shù)選擇的姿態(tài)估計算法。SOLVEPNP迭代它本質(zhì)上是DLT解,其次是Levenberg-Marquardt優(yōu)化。SOLVEPNP_P3P只使用一部分內(nèi)容來計算姿勢,只在使用時才調(diào)用。


          在OpenCV 3中,引入了兩種新方法-SOLVEPNP_DLS和SOLVEPNP_UPnP。有趣的是SOLVEPNP_UPnP它也試圖估計攝像機(jī)的內(nèi)部參數(shù)。


          SolvePnPRansac非常類似于解決PnP只是它用隨機(jī)樣本一致性(RANSAC)來準(zhǔn)確地估計姿勢。


          當(dāng)我們懷疑一些數(shù)據(jù)噪聲比較大時,使用RANSAC是非常有用的。例如,考慮將一條線擬合到2D點(diǎn)的問題。這個問題可以用線性最小二乘法來解決,其中所有點(diǎn)離擬合線的距離都是最小的。現(xiàn)在來考慮一個糟糕的數(shù)據(jù)點(diǎn),這個數(shù)據(jù)點(diǎn)離我們很遠(yuǎn)。這一個數(shù)據(jù)點(diǎn)可以控制最小二乘解,我們對這條線的估計是非常錯誤的。在RANSAC中,參數(shù)是通過隨機(jī)選擇所需的最小點(diǎn)數(shù)來估計的。在一個直線擬合問題中,我們從所有數(shù)據(jù)中隨機(jī)選取兩個點(diǎn),并找到通過它們的直線。其他距離這條線足夠近的數(shù)據(jù)點(diǎn)被稱為“不動點(diǎn)”(Inliers)。通過隨機(jī)選取兩點(diǎn)得到直線的多個估計值,并選取最大誤差數(shù)的直線作為正確的估計。


          使用SolvePnPRansac的參數(shù)如下所示。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標(biāo)志=迭代)
          Python:cv2.solvePnPRansac(ObjectPoint,ImagePoint,CameraMatrix,distCoeffs[,rvec[,tvc[,useExtrinsicGuess[,iterationsCount[,reprojectionError[,minInliersCount[,Inliers[,標(biāo)志])→rvec,tvc,inliers

          迭代計數(shù)-挑選最低點(diǎn)數(shù)的次數(shù)和估計參數(shù)。重投射錯誤-正如前面在RANSAC中提到的,預(yù)測足夠接近的點(diǎn)稱為“不穩(wěn)定點(diǎn)”。這個參數(shù)值是觀測到的點(diǎn)投影和計算的點(diǎn)投影之間的最大允許距離,從而認(rèn)為它是一個獨(dú)立點(diǎn)。

          MinInliersCount-不穩(wěn)定因素的數(shù)目。如果算法在某個階段發(fā)現(xiàn)了比minInliersCount更多的inliersCount,它就完成了。襯墊-輸出向量,其中包含ObtPoint和ImagePoint中的inliers索引。


          OpenCV POSIT


          OpenCV習(xí)慣于一種名為POSIT的姿態(tài)估計算法。它仍然存在于C API中(CvPosit),但不是C++API的一部分。PREST假設(shè)一個縮放的正射相機(jī)模型,因此你不需要提供焦距估計。這個函數(shù)現(xiàn)在已經(jīng)過時了,我們建議使用SolvePnp。我們提供了源程序代碼,感興趣的小伙伴們可以嘗試一下。

          #include <opencv2/opencv.hpp>using namespace std;using namespace cv;int main(int argc, char **argv){// Read input imagecv::Mat im = cv::imread("headPose.jpg");// 2D image points. If you change the image, you need to change vectorstd::vector<cv::Point2d> image_points;image_points.push_back( cv::Point2d(359391) );    // Nose tipimage_points.push_back( cv::Point2d(399561) );    // Chinimage_points.push_back( cv::Point2d(337297) );     // Left eye left cornerimage_points.push_back( cv::Point2d(513301) );    // Right eye right cornerimage_points.push_back( cv::Point2d(345465) );    // Left Mouth cornerimage_points.push_back( cv::Point2d(453469) );    // Right mouth corner// 3D model points.std::vector<cv::Point3d> model_points;model_points.push_back(cv::Point3d(0.0f0.0f0.0f));               // Nose tipmodel_points.push_back(cv::Point3d(0.0f-330.0f-65.0f));          // Chinmodel_points.push_back(cv::Point3d(-225.0f170.0f-135.0f));       // Left eye left cornermodel_points.push_back(cv::Point3d(225.0f170.0f-135.0f));        // Right eye right cornermodel_points.push_back(cv::Point3d(-150.0f-150.0f-125.0f));      // Left Mouth cornermodel_points.push_back(cv::Point3d(150.0f-150.0f-125.0f));       // Right mouth corner// Camera internalsdouble focal_length = im.cols; // Approximate focal length.Point2d center = cv::Point2d(im.cols/2,im.rows/2);cv::Mat camera_matrix = (cv::Mat_<double>(3,3) << focal_length, 0, center.x, 0 , focal_length, center.y, 001);cv::Mat dist_coeffs = cv::Mat::zeros(4,1,cv::DataType<double>::type); // Assuming no lens distortioncout << "Camera Matrix " << endl << camera_matrix << endl ; // Output rotation and translationcv::Mat rotation_vector; // Rotation in axis-angle formcv::Mat translation_vector;// Solve for posecv::solvePnP(model_points, image_points, camera_matrix, dist_coeffs, rotation_vector, translation_vector);// Project a 3D point (0, 0, 1000.0) onto the image plane.// We use this to draw a line sticking out of the nosevector<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(int i=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 << "Rotation Vector " << endl << rotation_vector << endl;cout << "Translation Vector" << endl << translation_vector << endl;cout <<  nose_end_point2D << endl;// Display image.cv::imshow("Output", im);cv::waitKey(0);}


          下載1:OpenCV-Contrib擴(kuò)展模塊中文版教程
          在「小白學(xué)視覺」公眾號后臺回復(fù):擴(kuò)展模塊中文教程即可下載全網(wǎng)第一份OpenCV擴(kuò)展模塊教程中文版,涵蓋擴(kuò)展模塊安裝、SFM算法、立體視覺、目標(biāo)跟蹤、生物視覺、超分辨率處理等二十多章內(nèi)容。

          下載2:Python視覺實(shí)戰(zhàn)項目52講
          小白學(xué)視覺公眾號后臺回復(fù):Python視覺實(shí)戰(zhàn)項目即可下載包括圖像分割、口罩檢測、車道線檢測、車輛計數(shù)、添加眼線、車牌識別、字符識別、情緒檢測、文本內(nèi)容提取、面部識別等31個視覺實(shí)戰(zhàn)項目,助力快速學(xué)校計算機(jī)視覺。

          下載3:OpenCV實(shí)戰(zhàn)項目20講
          小白學(xué)視覺公眾號后臺回復(fù):OpenCV實(shí)戰(zhàn)項目20講即可下載含有20個基于OpenCV實(shí)現(xiàn)20個實(shí)戰(zhàn)項目,實(shí)現(xiàn)OpenCV學(xué)習(xí)進(jìn)階。

          交流群


          歡迎加入公眾號讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器自動駕駛、計算攝影、檢測、分割、識別、醫(yī)學(xué)影像、GAN算法競賽等微信群(以后會逐漸細(xì)分),請掃描下面微信號加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺SLAM“。請按照格式備注,否則不予通過。添加成功后會根據(jù)研究方向邀請進(jìn)入相關(guān)微信群。請勿在群內(nèi)發(fā)送廣告,否則會請出群,謝謝理解~


          瀏覽 84
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一级特色日本黄色 | 九九三级片 | 黄色三级片网站 | 无码在线免费播放 | 一级特一级黄色电影 |