zoukankan      html  css  js  c++  java
  • OpenCV实战:人脸关键点检测(FaceMark)

    Summary:利用OpenCV中的LBF算法进行人脸关键点检测(Facial Landmark Detection)

    Author:    Amusi

    Date:       2018-03-20

    Note:       OpenCV3.4以及上支持Facemark

    原文:OpenCV实战:人脸关键点检测(FaceMark)

    PS:点击“阅读原文”,可以下载所有源码和模型,记得给star哦!

    教程目录

    • 测试环境

    • 引言

    • Facemark API

    • Facemark训练好的模型

    • 利用OpenCV代码进行实时人脸关键点检测

    • 步骤

    • 代码

    • 实验结果

    • Reference


    测试环境

    • Windows10

    • Visual Studio 2013

    • OpenCV3.4.1


    引言

    人脸一般是有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)。此人脸检测器是在几千幅带有关键点标签的人脸图像上训练得到的。

    带有注释/标签关键点的人脸图像公共数据集可以访问这个链接下载:https://ibug.doc.ic.ac.uk/resources/facial-point-annotations/

    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
    9
    10#include <opencv2/opencv.hpp>
    11#include <opencv2/face.hpp>
    12#include "drawLandmarks.hpp"
    13
    14
    15using namespace std;
    16using namespace cv;
    17using namespace cv::face;
    18
    19
    20int main(int argc,char** argv)
    21{
    22    // 加载人脸检测器(Face Detector)
    23    // [1]Haar Face Detector
    24    //CascadeClassifier faceDetector("haarcascade_frontalface_alt2.xml");
    25    // [2]LBP Face Detector
    26    CascadeClassifier faceDetector("lbpcascade_frontalface.xml");
    27
    28    // 创建Facemark类的对象
    29    Ptr<Facemark> facemark = FacemarkLBF::create();
    30
    31    // 加载人脸检测器模型
    32    facemark->loadModel("lbfmodel.yaml");
    33
    34    // 设置网络摄像头用来捕获视频
    35    VideoCapture cam(0);
    36
    37    // 存储视频帧和灰度图的变量
    38    Mat frame, gray;
    39
    40    // 读取帧
    41    while(cam.read(frame))
    42    {
    43
    44      // 存储人脸矩形框的容器
    45      vector<Rect> faces;
    46      // 将视频帧转换至灰度图, 因为Face Detector的输入是灰度图
    47      cvtColor(frame, gray, COLOR_BGR2GRAY);
    48
    49      // 人脸检测
    50      faceDetector.detectMultiScale(gray, faces);
    51
    52      // 人脸关键点的容器
    53      vector< vector<Point2f> > landmarks;
    54
    55      // 运行人脸关键点检测器(landmark detector)
    56      bool success = facemark->fit(frame,faces,landmarks);
    57
    58      if(success)
    59      {
    60        // 如果成功, 在视频帧上绘制关键点
    61        for(int i = 0; i < landmarks.size(); i++)
    62        {
    63            // 自定义绘制人脸特征点函数, 可绘制人脸特征点形状/轮廓
    64            drawLandmarks(frame, landmarks[i]);
    65            // OpenCV自带绘制人脸关键点函数: drawFacemarks
    66            drawFacemarks(frame, landmarks[i], Scalar(0, 0, 255));
    67        }
    68
    69      }
    70
    71      // 显示结果
    72      imshow("Facial Landmark Detection", frame);
    73
    74      // 如果按下ESC键, 则退出程序
    75      if (waitKey(1) == 27) break;
    76
    77    }
    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>
    10
    11using namespace cv;
    12using namespace std;
    13
    14#define COLOR Scalar(255, 200,0)
    15
    16// drawPolyline通过连接开始和结束索引之间的连续点来绘制多边形线。
    17void drawPolyline
    18(
    19  Mat &im,
    20  const vector<Point2f> &landmarks,
    21  const int start,
    22  const int end,
    23  bool isClosed = false
    24)
    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    }
    32
    33    // 绘制多边形曲线
    34    polylines(im, points, isClosed, COLOR, 2, 16);
    35
    36}
    37
    38// 绘制人脸关键点
    39void drawLandmarks(Mat &im, vector<Point2f> &landmarks)
    40{
    41    // 在脸上绘制68点及轮廓(点的顺序是特定的,有属性的)
    42    if (landmarks.size() == 68)
    43    {
    44      drawPolyline(im, landmarks, 0, 16);           // Jaw line
    45      drawPolyline(im, landmarks, 17, 21);          // Left eyebrow
    46      drawPolyline(im, landmarks, 22, 26);          // Right eyebrow
    47      drawPolyline(im, landmarks, 27, 30);          // Nose bridge
    48      drawPolyline(im, landmarks, 30, 35, true);    // Lower nose
    49      drawPolyline(im, landmarks, 36, 41, true);    // Left eye
    50      drawPolyline(im, landmarks, 42, 47, true);    // Right Eye
    51      drawPolyline(im, landmarks, 48, 59, true);    // Outer lip
    52      drawPolyline(im, landmarks, 60, 67, true);    // Inner lip
    53    }
    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    }
    62
    63}
    64
    65#endif // _renderFace_H_

    实验结果


    Reference

    [1]Tutorial:https://www.learnopencv.com/facemark-facial-landmark-detection-using-opencv/

    [2]FacemarkKazemi:https://docs.opencv.org/trunk/dc/de0/classcv_1_1face_1_1FacemarkKazemi.html

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

    [4]FacemarkAAM:

    https://docs.opencv.org/trunk/d5/d7b/classcv_1_1face_1_1FacemarkAAM.html

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

    https://ibug.doc.ic.ac.uk/media/uploads/documents/tzimiro_pantic_iccv2013.pdf

    [6]FacemarkLBF:https://docs.opencv.org/trunk/dc/d63/classcv_1_1face_1_1FacemarkLBF.html

    [7]Face alignment at 3000 fps via regressing local binary features:http://www.jiansun.org/papers/CVPR14_FaceAlignment.pdf

    [8]lbfmodel.yaml:https://github.com/kurnianggoro/GSOC2017/blob/master/data/lbfmodel.yaml

  • 相关阅读:
    Docker 私有仓库搭建
    事务提交与不同数据库的自增方式
    多环境切换&&注解方式&&增删改返回值问题
    查询缓存&&逆向工程
    Mybatis整合Log4j、延迟加载
    关联查询
    MyBatis实现动态SQL
    输出参数resultType
    MyBatis调用存储过程执行CRUD
    两种取值符号的异同
  • 原文地址:https://www.cnblogs.com/zhehan54/p/8744109.html
Copyright © 2011-2022 走看看