C#的机器学习:面部和动态检测

2019 年 2 月 18 日 DotNet

(给DotNet加星标,提升.Net技能


转自:王振耀

cnblogs.com/wangzhenyao1994/p/10386907.html


在本章中我们将展示两个独立的例子,一个用于人脸检测,另一个用于动态检测,以及如何快速地将这些功能添加到应用程序中。


面部检测


人脸检测,是人脸识别的第一部分。如果你不能从屏幕上的所有东西中识别出一个或多个人脸,那么你将永远无法识别那是谁的脸。


首先让我们看一张我们的应用程序截图:



上图中,通过摄像头我们已经捕获到一张图像,接下来启用面部跟踪,看看会发生什么:



物体面部特征正在被追踪。我们在物体周围看到的是面部追踪器(白色线框),它告诉我们我们这里有一张脸;以及我们的角度探测器(红线),它提供了一些关于我们脸所处水平方向的参考。


当我们移动物体时,面部追踪器和角度探测器会追踪他。这一切都很好,但是如果我们在真实的人脸上启用面部跟踪会发生什么呢?


如下图,面部追踪器和角度探测器正在追踪人的面部。



当我们把头从一边移到另一边时,面部追踪器会跟踪这个动作,可以看到角度探测器会根据它所识别的面部水平角度进行调整。


可以看到,在这里我们的颜色是黑白的,而不是彩色的。因为这是一个直方图的反向投影,而且它是一个可以更改的选项。



即使我们远离摄像机,让其他物体也进入视野中,面部追踪器也能在诸多噪音中跟踪我们的脸,如下图所示。这正是我们在电影中看到的面部识别系统的工作原理,尽管它更为先进。



现在让我们深入程序内部,看看它到底是如何工作的。


首先,我们需要问自己一个问题,我们想要解决的问题到底是什么。到底是人脸识别还是人脸检测。这里不得不提到Viola-Jones算法,因为,首先它有很高的检出率和很低的误报率,然后它非常擅长对数据的实时处理,最终要的一点是,它非常善于从非人脸中分别出人脸。


要永远记住,人脸检测只是人脸识别的第一步!


这个算法要求输入一个完整的正面,垂直的脸。脸部需要直接指向采集设备,头部尽量不要歪,不要昂头或低头。


这里有必要在强调一次,我们要做的只是在图像中检测出人脸即可。


我们的算法需要经过四个步骤来完成这件事:


  1. Haar 特征选择


  2. 创建一个完整的图像


  3. AdaBoost算法(通过迭代弱分类器而产生最终的强分类器的算法) 训练分类器


  4. 级联分类器


在正式开始之前,让我们先捋一捋面部检测到底是如果工作的。所有的脸,无论是人的,动物的还是其他的,都有一些相似的特征。


例如,都有一个鼻子,两个鼻孔,一张嘴巴,两个眼睛,两个耳朵等等。我们的算法通过Haar特征来匹配这些内容,我们可以通过其中任一项找到其他的特征。


但是,我们这里会遇到一个问题。在一个24x24像素的窗口中,一共有162336个可能的特征。如果这个计算结果是正确的,那么计算他们的时间和成本将非常之高。因此,我们将会使用一种被称为adaptive boosting(自适应提升法)的算法,或者更为常见的AdaBoost算法。


如果你研究过机器学习,我相信你听说过一种叫做boosting(提升)的技术。我们的学习算法将使用AdaBoost来选择最好的特征并训练分类器来使用它们。


AdaBoost可以与许多类型的学习算法一起使用,并且被业界认为是许多需要增强的任务的最佳开箱即用算法。通常在切换到另一种算法并对其进行基准测试之前,您不会注意到它有多好和多快。实际上这种区别是非常明显的。


在继续之前,我们先来了解一下什么是boosting(提升)技术。


Boosting从其他弱学习算法中获取输出,并将其与weighted sum(加权和)结合,加权和是boost分类器的最终输出。AdaBoost的自适应部分来自于这样一个事实,即后续的学习者被调整,以支持那些被以前的分类器错误分类的实例。


与其他算法相比,该算法更倾向于对数据进行过拟合,所以AdaBoost对噪声数据和异常值很敏感。因此我们在准备数据的时候,需要格外注意这一点。


现在,让我们来看看示例中的程序到底是如何工作的。对于这个示例,我们将再次使用Accord框架。


首先创建一个FaceHaarCascade对象。该对象包含一系列 Haarlike 的特征的弱分类阶段的集合。每个阶段都包含一组分类器树, 这些分类器树将在决策过程中使用。FaceHaarCascade自动为我们创建了所有这些阶段和树,而不需要我们去关心具体实现的细节。


首先,需要在底层构建一个决策树,它将为每个阶段提供节点,并为每个特性提供数值。以下是Accord的部分源码。


List<HaarCascadeStage> stages = new List<HaarCascadeStage>();
List<HaarFeatureNode[]> nodes;
HaarCascadeStage stage;
stage = new HaarCascadeStage(0.822689414024353);
nodes = new List<HaarFeatureNode[]>();
nodes.Add(
   new[] {
       new HaarFeatureNode(
           0.004014195874333382,0.0337941907346249,
           0.8378106951713562,
           new int[] { 3, 7, 14, 4, -1 },
           new int[] { 3, 9, 14, 2, 2 }
       )
   }
);
nodes.Add(
   new[] {
       new HaarFeatureNode(
           0.0151513395830989,
           0.1514132022857666,
           0.7488812208175659,
           new int[] { 1, 2, 18, 4, -1 },
           new int[] { 7, 2, 6, 4, 3 }
       )
   }
);
nodes.Add(
   new[] {
       new HaarFeatureNode(
           0.004210993181914091,
           0.0900492817163467,
           0.6374819874763489,
           new int[] { 1, 7, 15, 9, -1 },
           new int[] { 1, 10, 15, 3, 3 }
       )
   }
);


一旦构建完成,我们就可以使用cascade对象来创建HaarObjectDetector,这就是我们将用于检测的对象。


接下来我们需要提供:


  1. 我们的面部级联对象


  2. 搜索对象时使用的最小窗口大小


  3. 我们的搜索模式,假设我们只搜索一个对象


  4. 在搜索期间重新缩放搜索窗口时要使用的重新缩放因子


HaarCascade cascade = new FaceHaarCascade();
detector = new HaarObjectDetector(
  cascade,
  25,
  ObjectDetectorSearchMode.Single,
  1.2f,
  ObjectDetectorScalingMode.GreaterToSmaller
);


现在,我们需要准备数据,在本示例中,我们将使用笔记本电脑上的摄像头捕获所有图像。然而,Accord.NET framework 使得使用其他源进行数据采集变得很容易。例如 avi文件,jpg文件等等。


接下来,连接摄像头,选择分辨率:


// 创建视频源
VideoCaptureDevice videoSource = new VideoCaptureDevice(form.VideoDevice);
// 设置帧的大小
videoSource.VideoResolution = selectResolution(videoSource);
/// <summary>
///获取帧的大小
/// </summary>
/// <param name="videoSource">视频源</param>
/// <returns>帧的大小</returns>
private VideoCapabilities selectResolution(VideoCaptureDevice videoSource)
{
       foreach (var cap in videoSource?.VideoCapabilities)
       {
           if (cap.FrameSize.Height == 240)
                   return cap;
           if (cap.FrameSize.Width == 320)
                   return cap;
       }
        return videoSource?.VideoCapabilities.Last();
}



在这个演示中,你会注意到检测物体正对着摄像机,在背景中,还有一些其他的东西,那就是所谓的随机噪声。这样做是为了展示人脸检测算法是如何区分出脸的。


如果我们的探测器不能处理这些,它就会在噪声中消失,从而无法检测到脸。


随着视频源的加入,我们需要在接收到新的视频帧时得到通知,以便处理它、应用标记,等等。我们通过频源播放器的NewFrameReceived事件来实现这一点。\


在我们已经有了一个视频源和一个视频,让我们看看每当我们被通知有一个新的视频帧可用时发生了什么。


我们需要做的第一件事是对图像进行采样,以使它更容易工作:


ResizeNearestNeighbor resize = 
new ResizeNearestNeighbor(160, 120);
UnmanagedImage downsample = resize.Apply(im);


如果我们没有找到一张脸,我们将保持跟踪模式,等待一个具有可检测面部的帧。一旦我们找到了面部区域,我们需要重置跟踪器,定位脸部,减小它的大小,以尽可能的剔除背景噪声,然后初始化跟踪器,并将在图像上进行标记。代码如下:


Rectangle[] regions = detector?.ProcessFrame(downsample);
if (regions != null && regions.Length > 0)
{
    tracker?.Reset();
   // 跟踪第一张脸
   Rectangle face = regions[0];
   // 减小人脸检测的大小,避免跟踪背景上的其他内容
   Rectangle window = new Rectangle(
      (int)((regions[0].X + regions[0].Width / 2f) * xscale),
      (int)((regions[0].Y + regions[0].Height / 2f) * yscale),
      1,
      1
  );
   window.Inflate((int)(0.2f * regions[0].Width * xscale), (int)(0.4f * regions[0].Height * yscale));
   if (tracker != null)
   {
        tracker.SearchWindow = window;
        tracker.ProcessFrame(im);
   }    
   marker = new RectanglesMarker(window);
   marker.ApplyInPlace(im);
   eventArgs.Frame = im.ToManagedImage();
   tracking = true;
}
else
{
   detecting = true;
}


一旦检测到脸,我们的图像帧是这样的:



如果把头偏向一边,我们现在的形象应该是这样的:



动态检测


可以看到,在上一个例子中,我们不仅实现了面部检测,还实现了动态检测。现在,让我们把目光转向更大的范围,检测任何物体的运动,而不仅仅是面部。我们将继续使用Accord.NET来实现。


在动态检测中,我们会用红色高亮显示屏幕上的任何运动。移动的数量由任何一个区域的红色浓度表示。所以,如下图所示,我们可以看到手指在移动但是其他的都是静止的。



如下图所示,可以看到整个手的移动范围在增加。



如下图所示,一旦整只手开始移动,你不仅可以看到更多的红色,而且红色的总量是在增加的:



如果不希望对整个屏幕区域进行运动处理,可以自定义运动区域;运动检测只会发生在这些区域。如下图,可以看到我们已经定义了一个运动区域,这是唯一的一个区域。



现在,如果我们在摄像头前面做一些运动,可以看到程序只检测到了来自我们定义区域发生的运动。



现在,我们来做这样一个测试,在我们自定义的检测区域范围内,放置一个物体,然后我们把手放在这个物体后面进行运动,当然手也是在这个自定义的检测区域范围内进行运动的。如下图,可以看到,手的运动被检测出来了。



现在我们使用另一个选项,网格运动突出显示。它会使得检测到的运动区域基于定义的网格在红色方块中突出显示,如下图所示。



将检测添加到应用程序中


以下是处理接收到新的帧的代码:       


private void videoSourcePlayer_NewFrame(object sender, NewFrameEventArgs args)
{
  lock (this)
  {
    if (motionDetector != null)
    {
      float motionLevel = motionDetector.ProcessFrame(args.Frame);

      if (motionLevel > motionAlarmLevel)
      {
        //快门速度2秒
        flash = (int)(2 * (1000 / timer.Interval));
      }
      //检查对象的数
      if (motionDetector.MotionProcessingAlgorithm is BlobCountingObjectsProcessing)
      {
        BlobCountingObjectsProcessing countingDetector = (BlobCountingObjectsProcessing)motionDetector.MotionProcessingAlgorithm;
        detectedObjectsCount = countingDetector.ObjectsCount;
      }
      else
      {
        detectedObjectsCount = -1;
      }
      // 积累的历史
      motionHistory.Add(motionLevel);
      if (motionHistory.Count > 300)
      {
        motionHistory.RemoveAt(0);
      }
      if (显示运动历史ToolStripMenuItem.Checked)
      DrawMotionHistory(args.Frame);
    }
  }
}


这里的关键是检测视频帧中发生的动量,这是通过以下代码完成的。对于本例,我们使用的是两级的运动报警级别,但是你也可以使用任何你喜欢的级别定义。一旦超过这个阈值,就可以实现所需的逻辑,例如发送电子邮件、开始视频捕获等等。


float motionLevel = motionDetector.ProcessFrame(args.Frame);
if (motionLevel > motionAlarmLevel)
{
  //快门速度2秒
  flash = (int)(2 * (1000 / timer.Interval));
}


总结


在这一章中,我们学习了面部和动态检测,还展示了一些简单易用的代码。我们可以轻松的将这些功能添加到自己的程序中。


推荐阅读

(点击标题可跳转阅读)

C# 10分钟完成百度人脸识别

.NET中的对象引用、非托管指针和托管指针

.NET平台功能最强大,性能最佳的JSON库


看完本文有收获?请转发分享给更多人

关注「DotNet」加星标,提升.Net技能 

喜欢就点一下「好看」呗~

登录查看更多
0

相关内容

Adaboost 是一种迭代算法,是集成学习的一种,其核心思想是针对同一个训练集训练不同的分类器(弱分类器),然后把这些弱分类器集合起来,构成一个更强的最终分类器(强分类器)。
【实用书】学习用Python编写代码进行数据分析,103页pdf
专知会员服务
190+阅读 · 2020年6月29日
【CMU】基于图神经网络的联合检测与多目标跟踪
专知会员服务
54+阅读 · 2020年6月24日
【实用书】Python机器学习Scikit-Learn应用指南,247页pdf
专知会员服务
255+阅读 · 2020年6月10日
最新《Deepfakes:创造与检测》2020综述论文,36页pdf
专知会员服务
62+阅读 · 2020年5月15日
基于视觉的三维重建关键技术研究综述
专知会员服务
154+阅读 · 2020年5月1日
【干货书】机器学习Python实战教程,366页pdf
专知会员服务
331+阅读 · 2020年3月17日
深度神经网络实时物联网图像处理,241页pdf
专知会员服务
76+阅读 · 2020年3月15日
使用ONNX+TensorRT部署人脸检测和关键点250fps
极市平台
34+阅读 · 2019年10月22日
1500+ FPS!目前最快的CNN人脸检测算法开源
极市平台
25+阅读 · 2019年3月15日
一文综述人脸检测算法(附资源)
数据派THU
7+阅读 · 2018年5月8日
微表情检测和识别的研究进展与趋势
中国计算机学会
15+阅读 · 2018年3月23日
Python | 50行代码实现人脸检测
计算机与网络安全
3+阅读 · 2018年1月23日
教你快速使用OpenCV/Python/dlib进行眨眼检测识别!
全球人工智能
3+阅读 · 2018年1月8日
【机器视觉】人脸检测与识别总结
产业智能官
7+阅读 · 2017年12月6日
人脸检测与识别总结
计算机视觉战队
21+阅读 · 2017年11月29日
人脸检测与识别年度进展概述
深度学习大讲堂
5+阅读 · 2017年6月26日
Object detection on aerial imagery using CenterNet
Arxiv
6+阅读 · 2019年8月22日
VIP会员
相关资讯
使用ONNX+TensorRT部署人脸检测和关键点250fps
极市平台
34+阅读 · 2019年10月22日
1500+ FPS!目前最快的CNN人脸检测算法开源
极市平台
25+阅读 · 2019年3月15日
一文综述人脸检测算法(附资源)
数据派THU
7+阅读 · 2018年5月8日
微表情检测和识别的研究进展与趋势
中国计算机学会
15+阅读 · 2018年3月23日
Python | 50行代码实现人脸检测
计算机与网络安全
3+阅读 · 2018年1月23日
教你快速使用OpenCV/Python/dlib进行眨眼检测识别!
全球人工智能
3+阅读 · 2018年1月8日
【机器视觉】人脸检测与识别总结
产业智能官
7+阅读 · 2017年12月6日
人脸检测与识别总结
计算机视觉战队
21+阅读 · 2017年11月29日
人脸检测与识别年度进展概述
深度学习大讲堂
5+阅读 · 2017年6月26日
Top
微信扫码咨询专知VIP会员