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

在这一章中,我们将讨论:

  1. 面部检测
  2. 动态检测
  3. 将检测添加到应用程序中

面部检测

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

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

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

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

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

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

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

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

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

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

首先,我们需要问自己一个问题,我们想要解决的问题到底是什么。到底是人脸识别还是人脸检测。这里不得不提到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的部分源码。

  1. List<HaarCascadeStage> stages = new List<HaarCascadeStage>();
  2. List<HaarFeatureNode[]> nodes;
  3. HaarCascadeStage stage;
  4. stage = new HaarCascadeStage(0.822689414024353);
  5. nodes = new List<HaarFeatureNode[]>();
  6. nodes.Add(
  7. new[] {
  8. new HaarFeatureNode(
  9. 0.004014195874333382,0.0337941907346249,
  10. 0.8378106951713562,
  11. new int[] { , , , , - },
  12. new int[] { , , , , }
  13. )
  14. }
  15. );
  16. nodes.Add(
  17. new[] {
  18. new HaarFeatureNode(
  19. 0.0151513395830989,
  20. 0.1514132022857666,
  21. 0.7488812208175659,
  22. new int[] { , , , , - },
  23. new int[] { , , , , }
  24. )
  25. }
  26. );
  27. nodes.Add(
  28. new[] {
  29. new HaarFeatureNode(
  30. 0.004210993181914091,
  31. 0.0900492817163467,
  32. 0.6374819874763489,
  33. new int[] { , , , , - },
  34. new int[] { , , , , }
  35. )
  36. }
  37. );

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

接下来我们需要提供:

  1. 我们的面部级联对象
  2. 搜索对象时使用的最小窗口大小
  3. 我们的搜索模式,假设我们只搜索一个对象
  4. 在搜索期间重新缩放搜索窗口时要使用的重新缩放因子
  1. HaarCascade cascade = new FaceHaarCascade();
  2. detector = new HaarObjectDetector(
      cascade,
      ,
  3.   ObjectDetectorSearchMode.Single,
      1.2f,
  4.   ObjectDetectorScalingMode.GreaterToSmaller
    );

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

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

  1. // 创建视频源
  2. VideoCaptureDevice videoSource = new VideoCaptureDevice(form.VideoDevice);
  3. // 设置帧的大小
  4. videoSource.VideoResolution = selectResolution(videoSource);
  5.  
  6. /// <summary>
  7. /// 获取帧的大小
  8. /// </summary>
  9. /// <param name="videoSource">视频源</param>
  10. /// <returns>帧的大小</returns>
  11. private VideoCapabilities selectResolution(VideoCaptureDevice videoSource)
  12. {
  13. foreach (var cap in videoSource?.VideoCapabilities)
  14. {
  15. if (cap.FrameSize.Height == )
  16. return cap;
  17. if (cap.FrameSize.Width == )
  18. return cap;
  19. }
  20. return videoSource?.VideoCapabilities.Last();
  21. }

在这个演示中,你会注意到检测物体正对着摄像机,在背景中,还有一些其他的东西,那就是所谓的随机噪声。这样做是为了展示人脸检测算法是如何区分出脸的。如果我们的探测器不能处理这些,它就会在噪声中消失,从而无法检测到脸。

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

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

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

  1. ResizeNearestNeighbor resize = new ResizeNearestNeighbor(, );
  2.  
  3. UnmanagedImage downsample = resize.Apply(im);

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

  1. Rectangle[] regions = detector?.ProcessFrame(downsample);
  2. if (regions != null && regions.Length > )
  3. {
  4. tracker?.Reset();
  5. // 跟踪第一张脸
  6. Rectangle face = regions[];
  7. // 减小人脸检测的大小,避免跟踪背景上的其他内容
  8. Rectangle window = new Rectangle(
          (int)((regions[].X + regions[].Width / 2f) * xscale),
          (int)((regions[].Y + regions[].Height / 2f) * yscale),
          ,
          1
      );
  9. window.Inflate((int)(0.2f * regions[].Width * xscale), (int)(0.4f * regions[].Height * yscale));
  10. if (tracker != null)
  11. {
  12. tracker.SearchWindow = window;
  13. tracker.ProcessFrame(im);
  14. }
  15. marker = new RectanglesMarker(window);
  16. marker.ApplyInPlace(im);
  17. eventArgs.Frame = im.ToManagedImage();
  18. tracking = true;
  19.  
  20. }
  21. else
  22. {
  23. detecting = true;
  24. }

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

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

动态检测

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

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

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

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

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

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

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

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

将检测添加到应用程序中

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

  1. private void videoSourcePlayer_NewFrame(object sender, NewFrameEventArgs args)
  2. {
      lock (this)
  3.   {
  4.     if (motionDetector != null)
  5.     {
  6.       float motionLevel = motionDetector.ProcessFrame(args.Frame);
  7.       if (motionLevel > motionAlarmLevel)
  8.       {
  9.         //快门速度2秒
  10.         flash = (int)( * ( / timer.Interval));
  11.       }
  12.       //检查对象的数
  13.       if (motionDetector.MotionProcessingAlgorithm is BlobCountingObjectsProcessing)
  14.       {
  15.         BlobCountingObjectsProcessing countingDetector = (BlobCountingObjectsProcessing)motionDetector.MotionProcessingAlgorithm;
  16.         detectedObjectsCount = countingDetector.ObjectsCount;
  17.       }
  18.       else
  19.       {
  20.         detectedObjectsCount = -;
  21.       }
  22.       // 积累的历史
  23.       motionHistory.Add(motionLevel);
  24.       if (motionHistory.Count > )
  25.       {
  26.         motionHistory.RemoveAt();
  27.       }
  28.       if (显示运动历史ToolStripMenuItem.Checked)
  29.       DrawMotionHistory(args.Frame);
        }
      }
    }

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

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

总结

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

基于C#的机器学习--面部和动态检测-图像过滤器的更多相关文章

  1. 机器学习&恶意代码动态检测

    目录 写在前面 1 基于API调用的统计特征 2 API序列特征 3 API调用图 4 基于行为的特征 references: 写在前面 对恶意程序动态检测方法做了概述, 关于方法1和2可以参考阿里云 ...

  2. 基于C#的机器学习--目录

    转载请注明出处:https://www.cnblogs.com/wangzhenyao1994/p/10223666.html 文章发表的另一个地址:https://blog.csdn.net/wyz ...

  3. 基于机器学习的web异常检测

    基于机器学习的web异常检测 Web防火墙是信息安全的第一道防线.随着网络技术的快速更新,新的黑客技术也层出不穷,为传统规则防火墙带来了挑战.传统web入侵检测技术通过维护规则集对入侵访问进行拦截.一 ...

  4. 基于机器学习的web异常检测——基于HMM的状态序列建模,将原始数据转化为状态机表示,然后求解概率判断异常与否

    基于机器学习的web异常检测 from: https://jaq.alibaba.com/community/art/show?articleid=746 Web防火墙是信息安全的第一道防线.随着网络 ...

  5. 基于深度学习的安卓恶意应用检测----------android manfest.xml + run time opcode, use 深度置信网络(DBN)

    基于深度学习的安卓恶意应用检测 from:http://www.xml-data.org/JSJYY/2017-6-1650.htm 苏志达, 祝跃飞, 刘龙     摘要: 针对传统安卓恶意程序检测 ...

  6. AIOps探索:基于VAE模型的周期性KPI异常检测方法——VAE异常检测

    AIOps探索:基于VAE模型的周期性KPI异常检测方法 from:jinjinlin.com   作者:林锦进 前言 在智能运维领域中,由于缺少异常样本,有监督方法的使用场景受限.因此,如何利用无监 ...

  7. 基于深度学习的恶意样本行为检测(含源码) ----采用CNN深度学习算法对Cuckoo沙箱的动态行为日志进行检测和分类

    from:http://www.freebuf.com/articles/system/182566.html 0×01 前言 目前的恶意样本检测方法可以分为两大类:静态检测和动态检测.静态检测是指并 ...

  8. 伪基站,卒于5G——本质上是基于网络和UE辅助的伪基站检测,就是将相邻基站的CI、信号强度等信息通过测量报告上报给网络,网络结合网络拓扑、配置信息等相关数据,对所有数据进行综合分析,确认在某个区域中是否存在伪基站

    伪基站,卒于5G from:https://www.huxiu.com/article/251252.html?h_s=h8 2018-07-05 21:58收藏27评论6社交通讯     本文来自微 ...

  9. python dlib 面部轮廓实时检测

    1.dlib 实现动态人脸检测及面部轮廓检测 模型下载连接 : http://dlib.net/files/ # coding:utf-8 import cv2 import os import dl ...

随机推荐

  1. ios开发者较为好用的工具

    移动应用世界发生了巨大的变化,无论是在风格上还是在市场竞争上,消费者意识都推动了移动应用开发公司的崛起. 新的应用以及新的功能的出现 Apple IOS是为用户提供最新工具和升级的平台之一,它为iPh ...

  2. JS知识点整理(二)

    前言 这是对平时的一些读书笔记和理解进行整理的第二部分,第一部分请前往:JS知识点整理(一).本文包含一些易混淆.遗漏的知识点,也会配上一些例子,也许不是很完整,也许还会有点杂,但也许会有你需要的,后 ...

  3. JS知识点整理(一)

    前言 本文把平时的一些读书笔记和理解进行了整理归纳,包含一些易混淆.遗漏的知识点,也会配上一些例子,可能不是很完整,还会有点杂,但也许会有你需要的(目前先整理了一部分,笔记有点多,后续会持续更新). ...

  4. docker 入门 (一)重要概念介绍

    序 之前一直想学一下docker,但是基本看完就忘记了,下次用还是要再翻一下教程. 最近项目要用,连续用了一段时间,就熟练了,基本的使用以及概念都记住了. 趁现在还刚入门,就把入门一些容易遇到的问题记 ...

  5. No space left on device 解决 Cydia 安装应用错误

    在 Cydia 上搜索应用进行安装,提示错误:failed to write (No space left on device),从字面上的意思看是磁盘空间不够,导致写入错误,但是到 “关于” 里看到 ...

  6. Java Hibernate Validator

    Hibernate Validator是Hibernate提供的一个开源框架,使用注解方式非常方便的实现服务端的数据校验. 官网:http://hibernate.org/validator/ hib ...

  7. PHP 查找二维数组中是否有指定字符串的字段

    Array ( ] => Array ( [content] => 您提交了订单,请等待系统确认 :: [operator] => 客户 ) ] => Array ( [con ...

  8. 客户端与服务器交互中的Token

    Token:在计算机身份认证中是令牌(临时)的意思,类似于 MD5 加密之后的长字符串 特点:1.随机性,不可预测  2.具有有限期 3.唯一 作用:1.防止重复提交  2.防止CSRF(跨站请求伪造 ...

  9. day 90 DjangoRestFramework学习二之序列化组件

      DjangoRestFramework学习二之序列化组件   本节目录 一 序列化组件 二 xxx 三 xxx 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 序列化组件 首先按照 ...

  10. Flume(2)-拓扑结构与Agent内部原理

    一. 拓扑结构 1. 串行模式 这种模式是将多个flume给顺序连接起来了,从最初的source开始到最终sink传送的目的存储系统.此模式不建议桥接过多的flume数量, flume数量过多不仅会影 ...