Emgu CV 简介

        众所周知,Emgu CV是.NET平台下对OpenCV图像处理库的封装,也就是.NET版的OpenCV。开发者可以很方便的通过C#,VB等语言调用OpenCV函数来实现相应的图像处理功能。

其下载地址为:http://www.emgu.com/wiki/index.php/Main_Page。安装过程极其简单,网上教程很多,这里也就不详述了。

手势识别

在计算机科学中,手势识别是通过数学算法来识别人类手势的一个议题。手势识别可以来自人的身体各部位的运动,但一般是指脸部和手的运动。

腾讯有一个小工具,叫“QQ手势达人forPPT”,可以通过手势运动来控制PPT的放映,本文章亦是通过Emgu CV实现类似效果。

PPT控制类

控制的两个核心,一个是手势的检测,另一个就是如何使用C#控制PPT的播放、停止、上一页、下一页等操作。下面这个类即实现通过C#来控制PPT的加载,播放控制等。

   1:  // ***********************************************************************
   2:  // Assembly         : HandTrackerTestWindow
   3:  // Author           : pengdian
   4:  // Created          : 08-29-2014
   5:  //
   6:  // Last Modified By : pengdian
   7:  // Last Modified On : 08-29-2014
   8:  // ***********************************************************************
   9:  // <copyright file="PowerPointOperate.cs" company="nikoyo">
  10:  //     Copyright (c) . All rights reserved.
  11:  // </copyright>
  12:  // <summary>PPT操作</summary>
  13:  // ***********************************************************************
  14:  using System;
  15:  using System.IO;
  16:   
  17:  /// <summary>
  18:  /// The HandTrackerTestWindow namespace.
  19:  /// </summary>
  20:  namespace HandTrackerTestWindow
  21:  {
  22:      /// <summary>
  23:      /// PPT操作类.
  24:      /// </summary>
  25:      public class PowerPointOperate
  26:      {
  27:          /// <summary>
  28:          /// The object application
  29:          /// </summary>
  30:          private static Microsoft.Office.Interop.PowerPoint.Application objApp = null;
  31:   
  32:          /// <summary>
  33:          /// The object pres
  34:          /// </summary>
  35:          private static Microsoft.Office.Interop.PowerPoint.Presentation objPres = null;
  36:   
  37:          /////// <summary>
  38:          /////// The object ss ws
  39:          /////// </summary>
  40:          ////private Microsoft.Office.Interop.PowerPoint.SlideShowWindows objSSWs;
  41:   
  42:          /////// <summary>
  43:          /////// The object SST
  44:          /////// </summary>
  45:          ////private Microsoft.Office.Interop.PowerPoint.SlideShowTransition objSST;
  46:   
  47:          /// <summary>
  48:          /// The object SSS
  49:          /// </summary>
  50:          private static Microsoft.Office.Interop.PowerPoint.SlideShowSettings objSSS;
  51:   
  52:          /////// <summary>
  53:          /////// The object SLD RNG
  54:          /////// </summary>
  55:          ////private Microsoft.Office.Interop.PowerPoint.SlideRange objSldRng;
  56:   
  57:          public bool IsStart
  58:          {
  59:              get
  60:              {
  61:                  if (objPres == null || objPres.SlideShowWindow == null || objPres.SlideShowWindow.View == null)
  62:                  {
  63:                      return false;
  64:                  }
  65:                  return objPres.SlideShowWindow.View.State == Microsoft.Office.Interop.PowerPoint.PpSlideShowState.ppSlideShowRunning ? true : false;
  66:              }
  67:          }
  68:   
  69:          /// <summary>
  70:          /// Prevents a default instance of the <see cref="PowerPointOperate"/> class from being created.
  71:          /// </summary>
  72:          private PowerPointOperate()
  73:          {
  74:          }
  75:   
  76:          /// <summary>
  77:          /// 单例模式,获取ppt操作类实例.
  78:          /// </summary>
  79:          /// <returns>PowerPointOperate.</returns>
  80:          public static PowerPointOperate GetInstance()
  81:          {
  82:              return new PowerPointOperate();
  83:          }
  84:   
  85:          /// <summary>
  86:          /// 加载PPT文件.
  87:          /// </summary>
  88:          /// <param name="pptFile">The PPT file.</param>
  89:          /// <exception cref="System.Exception">指定文件不存在</exception>
  90:          public void LoadFile(string pptFile)
  91:          {
  92:              if (string.IsNullOrWhiteSpace(pptFile) || !File.Exists(pptFile))
  93:              {
  94:                  throw new Exception("指定文件不存在");
  95:              }
  96:   
  97:              ////防止连续打开多个PPT程序.
  98:              if (objApp == null)
  99:              {
 100:                  objApp = new Microsoft.Office.Interop.PowerPoint.Application() { Visible = Microsoft.Office.Core.MsoTriState.msoTrue };
 101:              }
 102:   
 103:              try
 104:              {
 105:                  ////以只读方式打开,方便操作结束后保存.
 106:                  objPres = objApp.Presentations.Open(pptFile, Microsoft.Office.Core.MsoTriState.msoTrue, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoTrue);
 107:                  //////Prevent Office Assistant from displaying alert messages:
 108:                  ////this.bAssistantOn = objApp.Assistant.On;
 109:                  ////objApp.Assistant.On = false;
 110:              }
 111:              catch
 112:              {
 113:                  objApp.Quit();
 114:                  GC.Collect();
 115:              }
 116:              finally
 117:              {
 118:                  objSSS = null;
 119:              }
 120:          }
 121:   
 122:          /// <summary>
 123:          /// 开始播放PPT
 124:          /// </summary>
 125:          public void PPTStart()
 126:          {
 127:              try
 128:              {
 129:                  if (objApp != null && objPres != null)
 130:                  {
 131:                      objSSS = objPres.SlideShowSettings;
 132:                      objSSS.Run();
 133:                  }
 134:              }
 135:              catch
 136:              {
 137:                  objApp.Quit();
 138:                  GC.Collect();
 139:              }
 140:          }
 141:   
 142:          /// <summary>
 143:          /// 停止播放PPT
 144:          /// </summary>
 145:          public void PPTStop()
 146:          {
 147:              try
 148:              {
 149:                  if (objApp != null && IsStart)
 150:                  {
 151:                      objPres.SlideShowWindow.View.Exit();
 152:                  }
 153:              }
 154:              catch
 155:              {
 156:                  objApp.Quit();
 157:                  GC.Collect();
 158:              }
 159:              finally
 160:              {
 161:                  objSSS = null;
 162:              }
 163:          }
 164:   
 165:          /// <summary>
 166:          /// 关闭PPT文档。
 167:          /// </summary>
 168:          public void PPTClose()
 169:          {
 170:              if (objApp != null)
 171:              {
 172:                  objApp.Quit();
 173:                  objApp = null;
 174:              } 
 175:   
 176:              GC.Collect();
 177:          }
 178:   
 179:          /// <summary>
 180:          /// PPT下一页。
 181:          /// </summary>
 182:          public void NextSlide()
 183:          {
 184:              if (objApp != null && IsStart)
 185:              {
 186:                  objPres.SlideShowWindow.View.Next();
 187:              }   
 188:          }
 189:   
 190:          /// <summary>
 191:          /// PPT上一页。
 192:          /// </summary>
 193:          public void PreviousSlide()
 194:          {
 195:              if (objApp != null && IsStart)
 196:              {
 197:                  objPres.SlideShowWindow.View.Previous();
 198:              }   
 199:          }
 200:      }
 201:  }

手势识别与运动检测

这里唯一的难点就是手势模型的创建,所幸,这种麻烦东西我们可以从“QQ手势达人forPPT”中提取出来,剩下的就是识别和检测手势了。代码如下:

   1:  using Emgu.CV;
   2:  using Emgu.CV.Structure;
   3:  using Emgu.CV.Util;
   4:  using System;
   5:  using System.Collections.Generic;
   6:  using System.Drawing;
   7:  using System.IO;
   8:  using System.Linq;
   9:  using System.Text;
  10:   
  11:  namespace HandTrackerTestWindow
  12:  {
  13:      public class HandTracker : IDisposable
  14:      {
  15:          CascadeClassifier palmHaar = new CascadeClassifier(@"data\palm.dat");
  16:          CascadeClassifier fistHaar = new CascadeClassifier(@"data\fist.dat");
  17:   
  18:          public void Dispose()
  19:          {
  20:              if (palmHaar != null)
  21:              {
  22:                  palmHaar.Dispose();
  23:                  palmHaar = null;
  24:              }
  25:              if (fistHaar != null)
  26:              {
  27:                  fistHaar.Dispose();
  28:                  fistHaar = null;
  29:              }
  30:          }
  31:   
  32:          public Rectangle DetectPalm(string imagePath)
  33:          {
  34:              if (!File.Exists(imagePath))
  35:              {
  36:                  return new Rectangle(0, 0, 0, 0);
  37:              }
  38:              Image<Bgr, Byte> img = new Image<Bgr, byte>(imagePath);
  39:              Image<Gray, Byte> grayImage = img.Copy().Convert<Gray, byte>();
  40:              Rectangle[] palmDetected = palmHaar.DetectMultiScale(grayImage, 1.4, 10, new Size(20, 20), Size.Empty);
  41:              //faces.AddRange(facesDetected);
  42:              if (palmDetected == null || palmDetected.Length == 0)
  43:              {
  44:                  return new Rectangle(0, 0, 0, 0);
  45:              }
  46:   
  47:              return palmDetected[0];
  48:          }
  49:          public Rectangle DetectPalm(Bitmap bitmap)
  50:          {
  51:              if (bitmap == null)
  52:              {
  53:                  return new Rectangle(0, 0, 0, 0);
  54:              }
  55:              Image<Bgr, Byte> img = new Image<Bgr, byte>(bitmap);
  56:              Image<Gray, Byte> grayImage = img.Copy().Convert<Gray, byte>();
  57:              Rectangle[] palmDetected = palmHaar.DetectMultiScale(grayImage, 1.4, 10, new Size(20, 20), Size.Empty);
  58:              //faces.AddRange(facesDetected);
  59:              if (palmDetected == null || palmDetected.Length == 0)
  60:              {
  61:                  return new Rectangle(0, 0, 0, 0);
  62:              }
  63:   
  64:              return palmDetected[0];
  65:          }
  66:          public Rectangle DetectFist(string imagePath)
  67:          {
  68:              if (!File.Exists(imagePath))
  69:              {
  70:                  return new Rectangle(0, 0, 0, 0);
  71:              }
  72:              Image<Bgr, Byte> img = new Image<Bgr, byte>(imagePath);
  73:              Image<Gray, Byte> grayImage = img.Copy().Convert<Gray, byte>();
  74:              Rectangle[] fistDetected = fistHaar.DetectMultiScale(grayImage, 1.4, 10, new Size(20, 20), Size.Empty);
  75:              if (fistDetected == null || fistDetected.Length == 0)
  76:              {
  77:                  return new Rectangle(0, 0, 0, 0);
  78:              }
  79:   
  80:              return fistDetected[0];
  81:          }
  82:   
  83:          public Rectangle DetectFist(Bitmap bitmap)
  84:          {
  85:              if (bitmap == null)
  86:              {
  87:                  return new Rectangle(0, 0, 0, 0);
  88:              }
  89:              Image<Bgr, Byte> img = new Image<Bgr, byte>(bitmap);
  90:              Image<Gray, Byte> grayImage = img.Copy().Convert<Gray, byte>();
  91:              Rectangle[] fistDetected = fistHaar.DetectMultiScale(grayImage, 1.4, 10, new Size(20, 20), Size.Empty);
  92:              if (fistDetected == null || fistDetected.Length == 0)
  93:              {
  94:                  return new Rectangle(0, 0, 0, 0);
  95:              }
  96:   
  97:              return fistDetected[0];
  98:          }
  99:      }
 100:  }

解决了手势检测控制类和PPT放映控制类,剩下的就是创建一个界面来进行控制了。

   1:  private void test()
   2:          {
   3:              bool isPalm = false;
   4:              bool isFist = false;
   5:              int count = 0;
   6:              while (true)
   7:              {
   8:                  if (count > 10)
   9:                  {
  10:                      isPalm = false;
  11:                      isFist = false;
  12:                      count = 0;
  13:                      this.Invoke(showControllerDelegate, false);
  14:                  }
  15:                  if (!isPalm)
  16:                  {
  17:                      isFist = false;
  18:                      Bitmap bitmap = videoPlayer.GetCurrentVideoFrame();
  19:                      if (handTracker.DetectPalm(bitmap).Width > 0)
  20:                      {
  21:                          isPalm = true;
  22:                          count = 0;
  23:                          this.Invoke(showControllerDelegate, true);
  24:                      }
  25:                      Thread.Sleep(50);
  26:                  }
  27:                  else
  28:                  {
  29:                      if (!isFist)
  30:                      {
  31:                          Bitmap bitmap = videoPlayer.GetCurrentVideoFrame();
  32:                          Rectangle rect = handTracker.DetectFist(bitmap);
  33:                          if (rect.Width > 0)
  34:                          {
  35:                              firstRect = rect;
  36:                              isFist = true;
  37:                              count = 0;
  38:                              this.Invoke(showButtonDelegate, true);
  39:                          }
  40:                          else
  41:                          {
  42:                              isFist = false;
  43:                              if (handTracker.DetectPalm(bitmap).Width > 0)
  44:                              {
  45:                                  isPalm = true;
  46:                                  count = 0;
  47:                                  this.Invoke(showButtonDelegate, false);
  48:                              }
  49:                              else
  50:                              {
  51:                                  count++;
  52:                              }
  53:   
  54:                          }
  55:                          Thread.Sleep(50);
  56:                      }
  57:                      else
  58:                      {
  59:                          Bitmap bitmap = videoPlayer.GetCurrentVideoFrame();
  60:                          Rectangle rect = handTracker.DetectFist(bitmap);
  61:                          if (rect.Width > 0)
  62:                          {
  63:                              if (firstRect.Left - rect.Left > 30)
  64:                              {
  65:                                  this.Invoke(nextPPTDelegate);
  66:                                  PowerPointOperate.GetInstance().NextSlide();
  67:                                  isPalm = false;
  68:                                  isFist = false;
  69:                                  count = 0;
  70:                                  Thread.Sleep(500);
  71:                                  this.Invoke(showControllerDelegate, false);
  72:                              }
  73:                              else if (firstRect.Left - rect.Left < -30)
  74:                              {
  75:                                  this.Invoke(prePPTDelegate);
  76:                                  PowerPointOperate.GetInstance().PreviousSlide();
  77:                                  isPalm = false;
  78:                                  isFist = false;
  79:                                  count = 0;
  80:                                  Thread.Sleep(500);
  81:                                  this.Invoke(showControllerDelegate, false);
  82:                              }
  83:                              else
  84:                              {
  85:                                  isPalm = true;
  86:                                  isFist = true;
  87:                                  count = 0;
  88:                              }
  89:                              //this.Invoke(showButtonDelegate);
  90:                          }
  91:                          else
  92:                          {
  93:                              if (handTracker.DetectPalm(bitmap).Width > 0)
  94:                              {
  95:                                  isPalm = true;
  96:                                  isFist = false;
  97:                                  count = 0;
  98:                                  this.Invoke(showButtonDelegate, false);
  99:                              }
 100:                              else
 101:                              {
 102:                                  count++;
 103:                              }
 104:                          }
 105:                          Thread.Sleep(50);
 106:                      }
 107:   
 108:                  }
 109:   
 110:   
 111:                  //PowerPointOperate.GetInstance().PPTStop();
 112:              }
 113:          }

最后实现的效果图如下:

检测手掌:

检测拳头:

移动拳头控制PPT

由于只是写一个用于演示的Demo,因此代码没做优化,有兴趣的可以自行修改,目前只做了上一页和下一页,开始播放和停止播放,有兴趣的可以自行补上。

最后,附上源代码地址(百度网盘):http://pan.baidu.com/s/1o6nyYFK

文章已迁移到:http://www.izonso.com/forum.php

基于Emgu CV 的手势识别实现PPT的控制放映的更多相关文章

  1. 基于Emgu CV+百度人脸识别,实现视频动态 人脸抓取与识别

    背景 目前AI 处于风口浪尖,作为 公司的CTO,也作为自己的技术专研,开始了AI之旅,在朋友圈中也咨询 一些大牛对于AI 机器学习框架的看法,目前自己的研究方向主要开源的 AI 库,如:Emgu C ...

  2. 基于Emgu CV的人脸检测代码

    这个提供的代码例子是Emgu CV提供的源码里面自带的例子,很好用,基本不需要改,代码做的是人脸检测不是人脸识别,这个要分清楚.再就是新版本的Emgu CV可能会遇到系统32位和64位处理方式有区别的 ...

  3. 基于Emgu cv的图像拼接(转)

    分类: 编程 C# Emgu cv Stitching 2012-10-27 11:04 753人阅读 评论(1) 收藏 举报 在新版本的Emgu cv中添加了Emgu.CV.Stitching,这极 ...

  4. 可学习的多人人脸识别程序(基于Emgu CV)

    源代码下载(需要安装Emgu CV,安装方法请百度) 很多朋友使用Emgu CV遇到CvInvoke()的报错,我找到一种解决方法. 把EmguCV目录下bin里面的所有dll复制到C:\WINDOW ...

  5. [Winform]基于Emgu.CV人脸识别

    摘要 “OpenCV是一个开源的计算机视觉库.OpenCV采用C/C++语言编写,可以运行在Linux/Windows/Mac等操作系统上.OpenCV还提供了Python.Ruby.MATLAB以及 ...

  6. [转载+原创]Emgu CV on C# (六) —— Emgu CV on Canny边缘检测

    Canny边缘检测也是一种边缘检测方法,本文介绍了Canny边缘检测的函数及其使用方法,并利用emgucv方法将轮廓检测解算的结果与原文进行比较. 图像的边缘检测的原理是检测出图像中所有灰度值变化较大 ...

  7. [转载+原创]Emgu CV on C# (四) —— Emgu CV on 全局固定阈值二值化

    重点介绍了全局二值化原理及数学实现,并利用emgucv方法编程实现. 一.理论概述(转载,如果懂图像处理,可以略过,仅用作科普,或者写文章凑字数)  1.概述 图像二值化是图像处理中的一项基本技术,也 ...

  8. .NET开源工程推荐(Accord,AForge,Emgu CV)

         本人用C#开发了一些项目,下面的开源工程给了我很大的帮助——详细的源代码介绍加丰富的实例运用,是非常不错的学习资源,分享给大家,同时附上我的相关开发项目.    Accord.NET The ...

  9. Emgu.CV(一)

    由于这块的知识不少,会分好几期写完 什么是OpenCV? OpenCV是一个基于(开源)发行的跨平台计算机视觉库,可以运行在Linux.Windows和Mac OS操作系统上.它轻量级而且高效--由一 ...

随机推荐

  1. eclipse+ADT 进行android应用签名详解

    http://jojol-zhou.iteye.com/blog/719428 1.Eclipse工程中右键工程,弹出选项中选择 android工具-生成签名应用包: 2.选择需要打包的android ...

  2. V9最新手机门户域名绑定教程。

    如需要绑定域名为wap.domain.com,作下如操作: 一.把wap.domain.com域名绑定到你的这个网站主机上.二.在网站后台模块>手机门户域名里面填写“http://wap.dom ...

  3. Helpers\CSRF

    Helpers\CSRF CSRF Protection The CSRF helper is used to protect post request from cross site request ...

  4. oracle字段类型

    oracle 字段类型CHAR    固定长度字符串    最大长度2000    bytes              VARCHAR2    可变长度的字符串    最大长度4000    byt ...

  5. 汽车OBD2诊断程序开发 (原文转载,思路很清晰!)

    1.因TL718已经为你建立了物理层.数据链层和部分应用层的协议,所以只要OBD2标准应用层协议文本,ISO15031-5 或 SAE J1979(这两个协议是相同的内容).    2.TL718诊断 ...

  6. Android_AsyncTask_Method

    package com.example.day07_asynctask_method; import android.os.AsyncTask; import android.os.Bundle; i ...

  7. Oracle删除重复数据的几种常用方法

    1.有可区分的主键,其他数据相同 select * from 表名 dl where dl.id not in (select min(d.id) from  表名 d group by 重复列) 2 ...

  8. [转]如何解决:Android中 Error generating final archive: Debug Certificate expired on 10/09/18 16:30 的错误

    本文转自:http://www.cnblogs.com/yyangblog/archive/2011/01/07/1929657.html 问题概述: 在导入一个app后提示如下错误: “Error ...

  9. ADO.NET通用数据库访问类

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  10. 【高级JSE技术】线程池

    引言 线程池是java并发技术中常用的一种,通过缓存线程资源避免了频繁的创建销毁线程带来的额外开销,从而提高性能.JDK中有相应的Executor框架实现,而Spring中也带有线程池的功能.本文将从 ...