基于Emgu CV 的手势识别实现PPT的控制放映
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的控制放映的更多相关文章
- 基于Emgu CV+百度人脸识别,实现视频动态 人脸抓取与识别
背景 目前AI 处于风口浪尖,作为 公司的CTO,也作为自己的技术专研,开始了AI之旅,在朋友圈中也咨询 一些大牛对于AI 机器学习框架的看法,目前自己的研究方向主要开源的 AI 库,如:Emgu C ...
- 基于Emgu CV的人脸检测代码
这个提供的代码例子是Emgu CV提供的源码里面自带的例子,很好用,基本不需要改,代码做的是人脸检测不是人脸识别,这个要分清楚.再就是新版本的Emgu CV可能会遇到系统32位和64位处理方式有区别的 ...
- 基于Emgu cv的图像拼接(转)
分类: 编程 C# Emgu cv Stitching 2012-10-27 11:04 753人阅读 评论(1) 收藏 举报 在新版本的Emgu cv中添加了Emgu.CV.Stitching,这极 ...
- 可学习的多人人脸识别程序(基于Emgu CV)
源代码下载(需要安装Emgu CV,安装方法请百度) 很多朋友使用Emgu CV遇到CvInvoke()的报错,我找到一种解决方法. 把EmguCV目录下bin里面的所有dll复制到C:\WINDOW ...
- [Winform]基于Emgu.CV人脸识别
摘要 “OpenCV是一个开源的计算机视觉库.OpenCV采用C/C++语言编写,可以运行在Linux/Windows/Mac等操作系统上.OpenCV还提供了Python.Ruby.MATLAB以及 ...
- [转载+原创]Emgu CV on C# (六) —— Emgu CV on Canny边缘检测
Canny边缘检测也是一种边缘检测方法,本文介绍了Canny边缘检测的函数及其使用方法,并利用emgucv方法将轮廓检测解算的结果与原文进行比较. 图像的边缘检测的原理是检测出图像中所有灰度值变化较大 ...
- [转载+原创]Emgu CV on C# (四) —— Emgu CV on 全局固定阈值二值化
重点介绍了全局二值化原理及数学实现,并利用emgucv方法编程实现. 一.理论概述(转载,如果懂图像处理,可以略过,仅用作科普,或者写文章凑字数) 1.概述 图像二值化是图像处理中的一项基本技术,也 ...
- .NET开源工程推荐(Accord,AForge,Emgu CV)
本人用C#开发了一些项目,下面的开源工程给了我很大的帮助——详细的源代码介绍加丰富的实例运用,是非常不错的学习资源,分享给大家,同时附上我的相关开发项目. Accord.NET The ...
- Emgu.CV(一)
由于这块的知识不少,会分好几期写完 什么是OpenCV? OpenCV是一个基于(开源)发行的跨平台计算机视觉库,可以运行在Linux.Windows和Mac OS操作系统上.它轻量级而且高效--由一 ...
随机推荐
- qt helper
qt帮助文档(中文版) http://www.kuqin.com/qtdocument/index.html qt基础 http://www.devbean.net/2012/08/qt-study- ...
- springMVC项目在jboss7中配置应用自己的log4j--转载
原文地址:http://www.xuebuyuan.com/1954635.html Jboss7默认采用容器自己的log4j module,应用自己配置的log4j不起作用,需要应用做一些设置: 以 ...
- Regular Expressions --正则表达式官方教程
http://docs.oracle.com/javase/tutorial/essential/regex/index.html This lesson explains how to use th ...
- MySQL(6):数据操作
1.创建数据(插入数据) (1)insert into tab_name(字段列表) values(值列表) (2)如果需要在插入时,为所有的字段设置值,那么可以省略字段列表.要求是值的顺序,应该 ...
- Android之HTTP网络通信--GET传递(二)
根据上一篇写的是实现了通过url接口将接口中的数据显示出来,这次根据上一篇的基础,进一步说明一下AsynTask的使用. AsynTask类有几个函数是大家必须知道的. doInBackGround( ...
- stitching detail输出的dot图含义
如果利用opencv里面提供的stitching detail的话. 输入参数: stitching_detail --save_graph a.dot 1.png 2.png 其中a.dot 文件中 ...
- 为Debain &&Centos安装dig
Debain&Ubuntu sudo apt-get install dnsutils Fdeoar&Centos yum install bind-utils
- Div+Css的初步运用
采用DIV+CSS模式的网站具有以下优势:1.表现和内容相分离 2.代码简洁,提高页面浏览速度 3.易于维护和改版 4.提高搜索引擎对网页的索引效率. 然后呢html文件中放置CSS有三种类型:内联. ...
- asp下实现多条件模糊查询SQL语句
常写一个简单的模糊查询的SQL语句格式可以如下例: sql="select * from 表名 where 字段名 like ’%" & request.form(&quo ...
- SQL SERVER中的逻辑读,预读和物理读
sqlserver:数据存储方式:最小单位是页,每一页8k,sqlserver 对页的读取是具有原子性,也就是说,要么读取完整一页,要么完全不读取,不会有中间状态,而页之间的数据组织结构是B树 但是每 ...