OpenCV實戰:人臉關鍵點檢測(FaceMark)

Summary:利用OpenCV中的LBF演算法進行人臉關鍵點檢測(Facial Landmark Detection)

Author: Amusi

Date: 2018-03-20

Note: OpenCV3.4和OpenCV Contrib3.4及上支持Facemark

強烈建議瀏覽下面的github鏈接,可閱讀最新的教程,並可下載所有源碼和模型,記得給star哦!

amusi/opencv-facial-landmark-detection?

github.com圖標

教程目錄

  • 測試環境
  • 引言
  • Facemark API
  • Facemark訓練好的模型
  • 利用OpenCV代碼進行實時人臉關鍵點檢測
  • 步驟
  • 代碼
  • 實驗結果
  • Reference

測試環境

  • Windows10
  • Visual Studio 2013
  • OpenCV3.4.1+OpenCV3.4.1 Contrib

註:使用Windows的童鞋請注意,不推薦使用官網提供的OpenCV3.4.1 Window版本,因為官方提供的OpenCV3.4.1無Contrib庫,而且只支持vc14和vc15。所以建議使用CMake,自己下載上述資源,然後使用CMake編譯OpenCV和Contrib,生成自己環境下的OpenCV動態鏈接庫。如何編譯,請自行百度,謝謝!


引言

人臉一般是有68個關鍵點,常用的人臉開源庫有Dlib,還有很多深度學習的方法。

本教程僅利用OpenCV,不依賴任何其它第三方庫來實現人臉關鍵點檢測,這一特性是之前沒有的。因為OpenCV自帶的samples中只有常見的人臉檢測、眼睛檢測和眼鏡檢測等(方法是harr+cascade或lbp+cascade)。

本教程主要參考Facemark : Facial Landmark Detection using OpenCV[1]

截止到2018-03-20,OpenCV3.4可支持三種人臉關鍵點檢測,但目前只能找到一種已訓練好的模型,所以本教程只介紹一種實現人臉關鍵點檢測的演算法。而且此類演算法還沒有Python介面,所以這裡只介紹C++的代碼實現。


Facemark API

OpenCV官方的人臉關鍵點檢測API稱為Facemark。Facemark目前分別基於下述三篇論文,實現了三種人臉關鍵點檢測的方法。

  • FacemarkKazemi[2]: This implementation is based on a paper titled 「One Millisecond Face Alignment with an Ensemble of Regression Trees」 by V.Kazemi and J. Sullivan published in CVPR 2014[3]. An alternative implementation of this algorithm can be found in DLIB
  • FacemarkAAM[4]: This implementation uses an Active Appearance Model (AAM) and is based on an the paper titled 「Optimization problems for fast AAM fitting in-the-wild」 by G. Tzimiropoulos and M. Pantic, published in ICCV 2013[5].
  • FacemarkLBF[6]: This implementation is based a paper titled 「Face alignment at 3000 fps via regressing local binary features」 by S. Ren published in CVPR 2014[7].

在寫這篇文章的時候,FacemarkKazemi類似乎不是從Facemark類派生的,而其他兩個類都是。


Facemark訓練好的模型

儘管Facemark API包含三種不同的實現,但只有FacemarkLBF(local binary features,LBF)才提供經過訓練的模型。 (之後在我們根據公共數據集訓練我們自己的模型後,這篇文章將在未來更新)

你可以從中下載已訓練好的模型:

  • lbfmodel.yaml[8]

利用OpenCV代碼進行實時人臉關鍵點檢測

步驟

1. 載入人臉檢測器(face detector)

所有的人臉關鍵點檢測演算法的輸入都是一個截切的人臉圖像。因為,我們的第一步就是在圖像中檢測所有的人臉,並將所有的人臉矩形框輸入到人臉關鍵點檢測器中。這裡,我們可以使用OpenCV的Haar人臉檢測器或者lbp人臉檢測器來檢測人臉。

2. 創建Facemark對象

創建Facemark類的對象。在OpenCV中,Facemark是使用智能指針(smart pointer,PTR),所以我們不需要考慮內存泄漏問題。

3. 載入landmark檢測器

載入關鍵點檢測器(lbfmodel.yaml)。此人臉檢測器是在幾千幅帶有關鍵點標籤的人臉圖像上訓練得到的。

帶有注釋/標籤關鍵點的人臉圖像公共數據集可以訪問這個鏈接下載:ibug.doc.ic.ac.uk/resou

4.從網路攝像頭中捕獲幀

捕獲視頻幀並處理。我們既可以打開一個本地視頻(.mp4),也可以打開網路攝像機(如果電腦有的話)來進行人臉關鍵點檢測。

5. 檢測人臉

我們對視頻的每一幀運行人臉檢測器。人臉檢測器的輸出是一個包含一個或多個矩形(rectangles)的容器(vector),即視頻幀中可能有一張或者多張人臉。

6. 運行人臉關鍵點檢測器

我們根據人臉矩形框截取原圖中的人臉ROI,再利用人臉關鍵點檢測器(facial landmark detector)對人臉ROI進行檢測。

對於每張臉我們獲得,我們可以獲得68個關鍵點,並將其存儲在點的容器中。因為視頻幀中可能有多張臉,所以我們應採用點的容器的容器。

7. 繪製人臉關鍵點

根據獲得關鍵點,我們可以在視頻幀上繪製出來並顯示。

代碼

本教程的代碼一共有兩個程序,分別為faceLandmarkDetection.cpp和drawLandmarks.hpp。

  • faceLandmarkDetection.cpp實現視頻幀捕獲、人臉檢測、人臉關鍵點檢測;
  • drawLandmarks.hpp實現人臉關鍵點繪製和多邊形線繪製。

faceLandmarkDetection.cpp

1// Summary: 利用OpenCV的LBF演算法進行人臉關鍵點檢測 2// Author: Amusi 3// Date: 2018-03-20 4// Reference: 5// [1]Tutorial: https://www.learnopencv.com/facemark-facial-landmark-detection-using-opencv/ 6// [2]Code: https://github.com/spmallick/learnopencv/tree/master/FacialLandmarkDetection 7 8// Note: OpenCV3.4以及上支持Facemark 910#include <opencv2/opencv.hpp>11#include <opencv2/face.hpp>12#include "drawLandmarks.hpp"131415using namespace std;16using namespace cv;17using namespace cv::face;181920int main(int argc,char** argv)21{22 // 載入人臉檢測器(Face Detector)23 // [1]Haar Face Detector24 //CascadeClassifier faceDetector("haarcascade_frontalface_alt2.xml");25 // [2]LBP Face Detector26 CascadeClassifier faceDetector("lbpcascade_frontalface.xml");2728 // 創建Facemark類的對象29 Ptr<Facemark> facemark = FacemarkLBF::create();3031 // 載入人臉檢測器模型32 facemark->loadModel("lbfmodel.yaml");3334 // 設置網路攝像頭用來捕獲視頻35 VideoCapture cam(0);3637 // 存儲視頻幀和灰度圖的變數38 Mat frame, gray;3940 // 讀取幀41 while(cam.read(frame))42 {4344 // 存儲人臉矩形框的容器45 vector<Rect> faces;46 // 將視頻幀轉換至灰度圖, 因為Face Detector的輸入是灰度圖47 cvtColor(frame, gray, COLOR_BGR2GRAY);4849 // 人臉檢測50 faceDetector.detectMultiScale(gray, faces);5152 // 人臉關鍵點的容器53 vector< vector<Point2f> > landmarks;5455 // 運行人臉關鍵點檢測器(landmark detector)56 bool success = facemark->fit(frame,faces,landmarks);5758 if(success)59 {60 // 如果成功, 在視頻幀上繪製關鍵點61 for(int i = 0; i < landmarks.size(); i++)62 {63 // 自定義繪製人臉特徵點函數, 可繪製人臉特徵點形狀/輪廓64 drawLandmarks(frame, landmarks[i]);65 // OpenCV自帶繪製人臉關鍵點函數: drawFacemarks66 drawFacemarks(frame, landmarks[i], Scalar(0, 0, 255));67 }6869 }7071 // 顯示結果72 imshow("Facial Landmark Detection", frame);7374 // 如果按下ESC鍵, 則退出程序75 if (waitKey(1) == 27) break;7677 }78 return 0;79}

drawLandmarks.hpp

1// Summary: 繪製人臉關鍵點和多邊形線 2// Author: Amusi 3// Date: 2018-03-20 4 5#ifndef _renderFace_H_ 6#define _renderFace_H_ 7 8#include <iostream> 9#include <opencv2/opencv.hpp>1011using namespace cv; 12using namespace std; 1314#define COLOR Scalar(255, 200,0)1516// drawPolyline通過連接開始和結束索引之間的連續點來繪製多邊形線。17void drawPolyline18(19 Mat &im,20 const vector<Point2f> &landmarks,21 const int start,22 const int end,23 bool isClosed = false24)25{26 // 收集開始和結束索引之間的所有點27 vector <Point> points;28 for (int i = start; i <= end; i++)29 {30 points.push_back(cv::Point(landmarks[i].x, landmarks[i].y));31 }3233 // 繪製多邊形曲線34 polylines(im, points, isClosed, COLOR, 2, 16);3536}3738// 繪製人臉關鍵點39void drawLandmarks(Mat &im, vector<Point2f> &landmarks)40{41 // 在臉上繪製68點及輪廓(點的順序是特定的,有屬性的)42 if (landmarks.size() == 68)43 {44 drawPolyline(im, landmarks, 0, 16); // Jaw line45 drawPolyline(im, landmarks, 17, 21); // Left eyebrow46 drawPolyline(im, landmarks, 22, 26); // Right eyebrow47 drawPolyline(im, landmarks, 27, 30); // Nose bridge48 drawPolyline(im, landmarks, 30, 35, true); // Lower nose49 drawPolyline(im, landmarks, 36, 41, true); // Left eye50 drawPolyline(im, landmarks, 42, 47, true); // Right Eye51 drawPolyline(im, landmarks, 48, 59, true); // Outer lip52 drawPolyline(im, landmarks, 60, 67, true); // Inner lip53 }54 else 55 { 56 // 如果人臉關鍵點數不是68,則我們不知道哪些點對應於哪些面部特徵。所以,我們為每個landamrk畫一個圓圈。57 for(int i = 0; i < landmarks.size(); i++)58 {59 circle(im,landmarks[i],3, COLOR, FILLED);60 }61 }6263}6465#endif // _renderFace_H_

實驗結果


Reference

[1]Tutorial:learnopencv.com/facemar

[2]FacemarkKazemi:docs.opencv.org/trunk/d

[3]One Millisecond Face Alignment with an Ensemble of Regression Trees:csc.kth.se/~vahidk/face

[4]FacemarkAAM:

docs.opencv.org/trunk/d

[5]Optimization problems for fast AAM fitting in-the-wild:

ibug.doc.ic.ac.uk/media

[6]FacemarkLBF:docs.opencv.org/trunk/d

[7]Face alignment at 3000 fps via regressing local binary features:jiansun.org/papers/CVPR

[8]lbfmodel.yaml:github.com/kurnianggoro

-----我是可愛的分割線-------

如何下載教程中的所有源碼和模型?

請點擊下面github鏈接!

記得給star哦!OpenCV實戰:人臉關鍵點檢測(FaceMark)

amusi/opencv-facial-landmark-detection?

github.com圖標

-----我還是可愛的分割線-------

若喜歡Amusi寫的文章,可以掃描下方二維碼關注CVer公眾號!

weixin.qq.com/r/NioZAUb (二維碼自動識別)


推薦閱讀:

新手學opencv怎麼做?opencv各個版本有什麼區別?
opencv提供了多少個特徵點的descriptor?
Opencv學習筆記(1)
1.27【OpenCV圖像處理】尋找輪廓
【小林的OpenCV基礎課 番外】答疑篇

TAG:OpenCV | 計算機視覺 | 人臉識別 |