当前位置:   article > 正文

Facemark:使用OpenCV进行面部特征点检测_lbfmodel.yaml

lbfmodel.yaml

 面部特征检测应用很多,我将在下一节介绍当前项目用到一个典型例子,因为疲劳检测有一张方案是通过检测人眼的闭合时间来实现的,在实际装车应用中效果还不错。本节先介绍一下opencv中自带的特征点检测功能,后续将讲解如何使用opencv+dlib实现疲劳检测功能。

现在OpenCV支持几种本地特征检测算法。然而,由于两个原因,实际使用中还需要做更多的工作

1、Python支持:截至OpenCV3.4似乎仍然没有python支持

2、缺乏训练过的模型:在三种用于特征检测的算法中,我只能找到一个训练过的模型。这不是很难解决的问题。在最坏的情况下,我们将尝试我们自己的模型,并使它可供人们使用。

预训练模型:

在进行本实验之前请先下载模型文件,https://github.com/kurnianggoro/GSOC2017/blob/master/data/lbfmodel.yaml(用于获取特征点),还要用到一个haarcascade_frontalface_alt2.xml(用于检测人脸),该模型在OpenCV安装目录中的\data\ haarcascades下。

先上代码:

1个头文件:drawLandmarks.hpp

  1. #ifndef _renderFace_H_
  2. #define _renderFace_H_
  3. using namespace cv;
  4. using namespace std;
  5. #define COLOR Scalar(255, 200,0)
  6. // drawPolyLine draws a poly line by joining
  7. // successive points between the start and end indices.
  8. void drawPolyline
  9. (
  10. Mat &im,
  11. const vector<Point2f> &landmarks,
  12. const int start,
  13. const int end,
  14. bool isClosed = false
  15. )
  16. {
  17. // Gather all points between the start and end indices
  18. vector <Point> points;
  19. for (int i = start; i <= end; i++)
  20. {
  21. points.push_back(cv::Point(landmarks[i].x, landmarks[i].y));
  22. }
  23. // Draw polylines.
  24. polylines(im, points, isClosed, COLOR, 2, 16);
  25. }
  26. void renderFace(cv::Mat &im, vector<Point2f> &landmarks)
  27. {
  28. // Draw face for the 68-point model.
  29. if (landmarks.size() == 68)
  30. {
  31. drawPolyline(im, landmarks, 0, 16); // Jaw line
  32. drawPolyline(im, landmarks, 17, 21); // Left eyebrow
  33. drawPolyline(im, landmarks, 22, 26); // Right eyebrow
  34. drawPolyline(im, landmarks, 27, 30); // Nose bridge
  35. drawPolyline(im, landmarks, 30, 35, true); // Lower nose
  36. drawPolyline(im, landmarks, 36, 41, true); // Left eye
  37. drawPolyline(im, landmarks, 42, 47, true); // Right Eye
  38. drawPolyline(im, landmarks, 48, 59, true); // Outer lip
  39. drawPolyline(im, landmarks, 60, 67, true); // Inner lip
  40. }
  41. else
  42. { // If the number of points is not 68, we do not know which
  43. // points correspond to which facial features. So, we draw
  44. // one dot per landamrk.
  45. for(int i = 0; i < landmarks.size(); i++)
  46. {
  47. circle(im,landmarks[i],3, COLOR, FILLED);
  48. }
  49. }
  50. }

1个cpp文件:facialLandmarkDetection.cpp

  1. #include <opencv2/opencv.hpp>
  2. #include <opencv2/face.hpp>
  3. #include "drawLandmarks.hpp"
  4. using namespace std;
  5. using namespace cv;
  6. using namespace cv::face;
  7. int main(int argc,char** argv)
  8. {
  9. // Load Face Detector
  10. CascadeClassifier faceDetector("haarcascade_frontalface_alt2.xml");
  11. // Create an instance of Facemark
  12. Ptr<Facemark> facemark = FacemarkLBF::create();
  13. // Load landmark detector
  14. facemark->loadModel("lbfmodel.yaml");
  15. // Set up webcam for video capture
  16. VideoCapture cam(1);
  17. // Variable to store a video frame and its grayscale
  18. Mat frame, gray;
  19. // Read a frame
  20. while(cam.read(frame))
  21. {
  22. // Find face
  23. vector<Rect> faces;
  24. // Convert frame to grayscale because
  25. // faceDetector requires grayscale image.
  26. cvtColor(frame, gray, COLOR_BGR2GRAY);
  27. // Detect faces
  28. faceDetector.detectMultiScale(gray, faces);
  29. // Variable for landmarks.
  30. // Landmarks for one face is a vector of points
  31. // There can be more than one face in the image. Hence, we
  32. // use a vector of vector of points.
  33. vector< vector<Point2f> > landmarks;
  34. // Run landmark detector
  35. bool success = facemark->fit(frame,faces,landmarks);
  36. if(success)
  37. {
  38. // If successful, render the landmarks on the face
  39. for(int i = 0; i < landmarks.size(); i++)
  40. {
  41. drawLandmarks(frame, landmarks[i]);
  42. }
  43. }
  44. // Display results
  45. imshow("Facial Landmark Detection", frame);
  46. // Exit loop if ESC is pressed
  47. if (waitKey(1) == 27) break;
  48. }
  49. return 0;
  50. }

最后是cmake文件:

  1. cmake_minimum_required(VERSION 2.8)
  2. project(fd)
  3. find_package(OpenCV REQUIRED)
  4. include_directories(${OpenCV_INClUDE_DIRS})
  5. add_executable(fd facialLandmarkDetection.cpp)
  6. target_link_libraries(fd ${OpenCV_LIBS})

代码解析:

1、加载人脸检测器:

     所有的面部特征检测算法都以裁剪出的面部图像作为输入。因此,我们的第一步是检测图像中的所有人脸,并将这些人脸矩形框传递给特征点检测器。CascadeClassifier faceDetector("haarcascade_frontalface_alt2.xml");加载OpenCV的HAAR人脸检测器(haarcascade_frontalface_alt2.xml)。

2、创建Facemark实例:

Ptr<Facemark> facemark = FacemarkLBF::create();,我们创建了Facemark类的一个实例。它被包裹在OpenC V智能指针(Ptr)中,所以您不必担心内存管理。智能指针是c++的基础知识,请自行百度。

3、加载特征点检测器:

接下来,我们加载特征点检测器(lbfmodel.yaml)。这个地标探测器是在几千幅面部图像和相应的特征点上训练的。带有标注特征点的面部图像的公共数据集可以在这里找到https://ibug.doc.ic.ac.uk/resources/facial-point-annotations/

4、从摄像头捕捉帧:

下一步是抓取一个视频帧并处理它。VideoCapture cam(0);设置从本机第一个摄像头捕获视频,对应的设备文件为/dev/video0。可以使用 VideoCapture cap(“myvideo.mp4”);来读取视频文件, 然后,我们不断从视频抓取帧,直到ESC被按下。

5、检测面部:

我们在视频的每个帧上运行人脸检测器。人脸检测器的输出是矩形的向量,对应图像中的一个或多个人脸。faceDetector.detectMultiScale(gray, faces);

6、运行面部地标检测器:

我们将原始图像和检测到的人脸矩形传送到面部特征点检测器。对于每一张脸,我们得到68个特征点,这些特征点被存储在一个向量中。因为一个帧中可能有多个人脸,所以我们必须通过一个点向量的向量来存储地标,每个子向量对应一张脸。

bool success = facemark->fit(frame,faces,landmarks);

7、绘制地标:

一旦我们获得了特征点,我们就可以把它们画在图像上进行展示。绘图的代码在drawLandmarks.hpp中。

drawLandmarks(frame, landmarks[i]);

 

最后,实际代码运行效果如下:(没错,this guy is me ~ _~)

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/118541
推荐阅读
相关标签
  

闽ICP备14008679号