OpenCV基于残差网络实现人脸检测

Posted OpenCV学堂

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV基于残差网络实现人脸检测相关的知识,希望对你有一定的参考价值。

OpenCV基于残差网络实现人脸检测

OpenCV3.3版本第一次把深度神经网络(DNN)模块引入到正式发布版本中,最新的OpenCV3.4中DNN模块发布了两个必杀技,一个支持Faster R-CNN的对象检测,比SSD与YOLO这些模型有更好的检测精度与小对象检测能力,另外一个是支持基于SSD+Resnet模型的人脸检测,虽然速度还达不到HAAR级联检测器的实时性,但是准确性与模型泛化能力可以说完爆HAAR级联检测器方式的人脸检测算法。作为OpenCV开发者需要人脸检测功能时候又多了一种更加可靠的选择,这里我们首先简单介绍一下什么是残差网络,然后给出其人脸检测模型在OpenCV基于摄像头实时人脸检测演示。

一:残差网络(Resnet)

最初的CNN网络LeNet与AlexNet卷积层都比较少,VGG通过小的卷积核实现了网络深度的增加取得了显著效果,但是当层数过度增加的时候就发现训练错误与测试错误都在增加,图示如下:

最开始人们以为是因为梯度消失或者梯度爆炸导致的,不过随着大家的努力,认为这个不是一个过拟合问题,而是网络褪化现象,所以针对这种情况,MSRA何凯明团队提出了一种新的网络模型-Residual Networks,其主要思想是使用残差结构来训练网络,一个残差结构如下:

OpenCV基于残差网络实现人脸检测

作者认为F(x) = H(x)-x所以得到H(x) = F(x) + x这样的恒等映射,然后作者就建立34层plain网络与34层的残差网络作为对比,而最左边的VGG-19网络作为参考,整个的网络结构显示如下: 

OpenCV基于残差网络实现人脸检测

 模型建立好的之后,作者在不同的数据集上进行了训练与测试,均观察到残差网络的效果要明显优于34层plain网络,而且发现基于残差结构的网络层数越深效果越好,而34层plain网络跟18层的plain网络相比有明显的褪化现象出现。对比训练的结果如下:

OpenCV基于残差网络实现人脸检测

在残差网络没有出来之前,很少有网络的层数会超过100层,但是残差网络可以达到上千层,毫无疑问何凯明团队也凭借残差网络模型在2015年的ImageNet图像分类比赛中获得了冠军,当时使用152层的残差网络。OpenCV中人脸检测的残差网络模型是基于SSD实现的,所以速度还是挺快的,而且效果是特别的好。废话不多说了,下面看看OpenCV中如何使用它实现人脸检测。

二:人脸检测代码实现

下载好模型之后放在本地的一个文件夹下即可,然后就可以开始编程工作啦。 首先需要加载模型成网络:

 
   
   
 
  1.  String modelDesc = "D:/vcprojects/images/dnn/face/deploy.prototxt";

  2.  String modelBinary = "D:/vcprojects/images/dnn/face/res10_300x300_ssd_iter_140000.caffemodel";

  3.  // 初始化网络

  4.  dnn::Net net = readNetFromCaffe(modelDesc, modelBinary);

  5.  if (net.empty())

  6.  {

  7.  printf("could not load net...\n");

  8.  return -1;

  9.  }

然后要打开本地相机或者一段视频文件,使用VideoCapture对象即可,代码如下:

 
   
   
 
  1. // 打开摄像头

  2.  VideoCapture capture(0);

  3.  if (!capture.isOpened()) {

  4.  printf("could not load camera...\n");

  5.  return -1;

  6.  }

打开相机成功之后就可以读写每帧图像,然后转换成网络可以接受的数据类型,代码如下:

 
   
   
 
  1.  // 输入数据调整

  2.  Mat inputBlob = blobFromImage(frame, inScaleFactor,

  3.  Size(inWidth, inHeight), meanVal, false, false);

  4.  net.setInput(inputBlob, "data");

然后在OpenCV中通过调用net.forward实现检测,对结果提取置信分数(0~1)之间,对大于阈值(假设0.5)的提取BOX位置,就可以绘制矩形框显示了,这部分的代码如下:

 
   
   
 
  1. // 人脸检测

  2. Mat detection = net.forward("detection_out");

  3. vector<double> layersTimings;

  4. double freq = getTickFrequency() / 1000;

  5. double time = net.getPerfProfile(layersTimings) / freq;

  6. Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());

  7. ostringstream ss;

  8. ss << "FPS: " << 1000 / time << " ; time: " << time << " ms";

  9. putText(frame, ss.str(), Point(20, 20), 0, 0.5, Scalar(0, 0, 255));

  10. for (int i = 0; i < detectionMat.rows; i++)

  11. {

  12.  // 置信度 0~1之间

  13.  float confidence = detectionMat.at<float>(i, 2);

  14.  if (confidence > confidenceThreshold)

  15.  {

  16.  int xLeftBottom = static_cast<int>(detectionMat.at<float>(i, 3) * frame.cols);

  17.  int yLeftBottom = static_cast<int>(detectionMat.at<float>(i, 4) * frame.rows);

  18.  int xRightTop = static_cast<int>(detectionMat.at<float>(i, 5) * frame.cols);

  19.  int yRightTop = static_cast<int>(detectionMat.at<float>(i, 6) * frame.rows);

  20.  Rect object((int)xLeftBottom, (int)yLeftBottom,

  21.  (int)(xRightTop - xLeftBottom),

  22.  (int)(yRightTop - yLeftBottom));

  23.  rectangle(frame, object, Scalar(0, 255, 0));

  24.  ss.str("");

  25.  ss << confidence;

  26.  String conf(ss.str());

  27.  String label = "Face: " + conf;

  28.  int baseLine = 0;

  29.  Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);

  30.  rectangle(frame, Rect(Point(xLeftBottom, yLeftBottom - labelSize.height),

  31.  Size(labelSize.width, labelSize.height + baseLine)),

  32.  Scalar(255, 255, 255), CV_FILLED);

  33.  putText(frame, label, Point(xLeftBottom, yLeftBottom),

  34.  FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0));

  35.  }

  36. }

最终运行显示结果如下: 脸部无遮挡,正常情况下:

OpenCV基于残差网络实现人脸检测

脸部无遮挡,头部倾斜的情况下:

OpenCV基于残差网络实现人脸检测

脸部有遮挡的情况下:

OpenCV基于残差网络实现人脸检测

更多倾斜、侧脸、模糊等各种情况下:

一勤天下无难事、

百思胸中有良谋!


关注【OpenCV学堂】

长按或者扫码下面二维码即可关注

+OpenCV识别交流群 657875553

进群暗号:OpenCV



以上是关于OpenCV基于残差网络实现人脸检测的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV+OpenVINO实现人脸Landmarks实时检测

OpenCV+OpenVINO实现人脸Landmarks实时检测

MTCNN实时人脸检测网络详解与opencv+tensorflow代码演示

基于OpenCV读取摄像头进行人脸检测和人脸识别

opencv 是怎么实现人脸检测的

如何用opencv实现人脸检测与跟踪