C++ OpenCV人脸图像提取

2021-03-12 11:34:46 浏览数 (1)

前言

《C OpenCV Contrib模块LBF人脸特征点检测》文章中已经介绍了人脸特征点的检测,本篇文章是在原代码的基础上实现人脸的提取。

实现效果

从上图上可以看到,左边蓝色方框里面是截取的人脸图像,然后在人脸图像的基础上针对特征点选定区域,最后生成右边圆框中的人脸图像。

#

实现方式

1

使用DNN检测到人脸并截取人脸部分区域

2

在截取的人脸区域中检测人脸68个特征点

3

针对68个特征点实现凸包检测形成图像掩膜

4

根据掩膜提取图像的人脸信息

关于人脸68个特征点

微卡智享

上图中介绍了人脸特征点的几个关键位置:

位置

点的范围

左侧下巴轮廓

0-7

下巴

8

右侧下巴轮廓

9-16

左侧眉毛

17-21

右侧眉毛

22-26

鼻梁区域

27-30 ‍

鼻底区域

31-35

左眼

36-41

右眼

42-47

嘴唇外缘

48-59

嘴唇内缘

60-67

人脸关键点

  • 鼻尖 30
  • 鼻根 27
  • 下巴 8
  • 左眼外角 36
  • 左眼内角 39
  • 右眼外角 45
  • 右眼内角 42
  • 嘴中心 66
  • 嘴左角 48
  • 嘴右角 54
  • 左脸最外 0
  • 右脸最外 16

核心代码

微卡智享

代码语言:javascript复制
//初始化模版人脸
void InitFaceMarkModel(Mat& frame, Rect rect, Mat& dst, vector<Point2f>& dstfacemarkmodel)
{
  vector<int> faceid = { 30,27,8,36,39,45,42,66,48,54,0,16 };
  vector<int>::iterator it;

  dst = Mat(frame, rect);

  Mat tmpmodel;
  dst.copyTo(tmpmodel);

  Rect tmprect = Rect(0, 0, dst.cols, dst.rows);
  vector<Rect> tmprects;
  tmprects.push_back(tmprect);
  vector<vector<Point2f>> tmpfacemodels;
  facemarkdetect.facemarkdetector(dst, tmprects, tmpfacemodels);
  Mat tmpdst = Mat::zeros(dst.size(), CV_8UC1);
  if (tmpfacemodels.size() > 0) {
    facemarkmodel = tmpfacemodels[0];
    
    //将vector<Point2f>转为vector<Point>用于做凸包检测
    vector<Point> facemarkcontour;    
    for (int i = 0; i < facemarkmodel.size();   i) {
      facemarkcontour.push_back(Point(facemarkmodel[i].x, facemarkmodel[i].y));
      //it = find(faceid.begin(), faceid.end(), i);
      //if (it != faceid.end()) {
      //  putText(tmpmodel, to_string(i), facemarkmodel[i], FONT_HERSHEY_PLAIN, 1, Scalar(255, 0, 0));
      //}
      cout << "模版特征点"<< i <<":" << facemarkmodel[i] << endl;
    }

    //凸包检测
    vector<Point> contourhull;
    convexHull(facemarkcontour, contourhull);

    //存入二维数组vector<vector<Point>>中用于画轮廓处理
    vector<vector<Point>> contours;
    contours.push_back(contourhull);
    //画轮廓并添充
    drawContours(tmpdst, contours, -1, Scalar(255, 255, 255), -1);
  }

  dst = Mat::zeros(tmpmodel.size(), CV_8UC3);
  tmpmodel.copyTo(dst, tmpdst);
  imshow("dst", dst);

  //resize(tmpmodel, tmpmodel, Size(0, 0), 5, 5);
  imshow("srcmodel", tmpmodel);
  imshow("tmpdst", tmpdst);
}

划重点

上面的代码还是比较简单的,两个需要注意的点:

  1. 人脸关键点检测出来的数据是vector<vector<Point2f>>,而做凸包检测的时候需要将vector<vector<Point2f>>转换成vector<vector<Point>>。
  2. 做区域掩膜时先生成一张相同大小的全黑的图片,然后把要截取的区域全部填充为白色,再通过copyto的方式生成即可。

结语

源码下一篇会再提交上去,现在的源码在处理人脸的Delaunay三角形的

提取,正好遇到了问题。等下篇的时候一起说一下。

0 人点赞