作者:野比 (conmajia@gmail.com)
时间:May, 2012
封面图片为野比原创,请勿未经允许私自引用
Nobi's Somatosensory Game -- Catch the Brick
野比的体感游戏 —— 抓住板砖
写在前面的话:这纯粹是个实验小品,妄称游戏,娱乐而已,不要当真。做这个东西的原因,其一在于对体感游戏的兴趣,其二也是为了练习使用Emgu CV。希望通过这篇文章,抛砖引玉,能够激发出大家创造的激情。希望能有更多更好的关于体感控制方面的精品出现!
====>源代码下载<====
要使用源代码,请先安装Emgu CV(请找度娘索取),并且把bin目录添加到系统变量中。如果不行或者不会,就把bin下面的所有dll文件复制到C:\Windows\system32里去。
源代码里面有一个BitmapEx,是增强的System.Drawing.Bitmap,用到指针来进行GetPixel()和SetPixel(),性能比Bitmap好不少。
BitmapEx的代码如下。
- /**********************************************
- *ExtendedBitmapClass
- *增强型位图类
- *--------------------------------------------
- *野比春熊
- *conmajia@gmail.com
- *May13th,2012Mother'sDay
- *--------------------------------------------
- *YouMAYABLETOUSE,DUPLICATEthisprogram.
- *ButyouMAYNOTMODIFYitWITHOUTmyper-
- *mission.
- *(Haha,justajoke.Yougotthisfile,you
- *goteverythingalready.)
- *Useasyouwish.Youcandonatetomeif
- *youfeelgrateful.
- ********************************************/
- usingSystem;
- usingSystem.Collections.Generic;
- usingSystem.Text;
- usingSystem.Drawing.Imaging;
- usingSystem.Drawing;
- namespaceSpringbearWorks.Image
- {
- ///<summary>
- ///增强位图类。
- ///</summary>
- ///<remarks>
- ///高性能Bitmap类。
- ///</remarks>
- publicclassBitmapEx:IDisposable,ICloneable
- {
- #region字段
- internalBitmap_bitmap;
- BitmapData_bitmapData;
- #endregion
- #region构造与析构
- privateBitmapEx(){}
- publicBitmapEx(intwidth,intheight,PixelFormatformat)
- {
- _bitmap=newBitmap(width,height,format);
- }
- ~BitmapEx()
- {
- Dispose(false);
- }
- publicvoidDispose()
- {
- GC.SuppressFinalize(this);
- Dispose(true);
- }
- protectedvirtualvoidDispose(booldisposing)
- {
- Unlock();
- if(disposing)
- {
- _bitmap.Dispose();
- }
- }
- #endregion
- #region方法
- publicobjectClone()
- {
- BitmapExclone=newBitmapEx();
- clone._bitmap=(Bitmap)_bitmap.Clone();
- returnclone;
- }
- publicintWidth
- {
- get{return_bitmap.Width;}
- }
- publicintHeight
- {
- get{return_bitmap.Height;}
- }
- publicvoidLock()
- {
- _bitmapData=_bitmap.LockBits(
- newRectangle(0,0,_bitmap.Width,_bitmap.Height),
- ImageLockMode.ReadWrite,
- _bitmap.PixelFormat
- );
- }
- unsafepublicColorGetPixel(intx,inty)
- {
- if(_bitmapData.PixelFormat==PixelFormat.Format32bppArgb)
- {
- byte*b=(byte*)_bitmapData.Scan0+(y*_bitmapData.Stride)+(x*4);
- returnColor.FromArgb(*(b+3),*(b+2),*(b+1),*b);
- }
- if(_bitmapData.PixelFormat==PixelFormat.Format24bppRgb)
- {
- byte*b=(byte*)_bitmapData.Scan0+(y*_bitmapData.Stride)+(x*3);
- returnColor.FromArgb(*(b+2),*(b+1),*b);
- }
- returnColor.Empty;
- }
- unsafepublicvoidSetPixel(intx,inty,Colorc)
- {
- if(_bitmapData.PixelFormat==PixelFormat.Format32bppArgb)
- {
- byte*b=(byte*)_bitmapData.Scan0+(y*_bitmapData.Stride)+(x*4);
- *b=c.B;
- *(b+1)=c.G;
- *(b+2)=c.R;
- *(b+3)=c.A;
- }
- if(_bitmapData.PixelFormat==PixelFormat.Format24bppRgb)
- {
- byte*b=(byte*)_bitmapData.Scan0+(y*_bitmapData.Stride)+(x*3);
- *b=c.B;
- *(b+1)=c.G;
- *(b+2)=c.R;
- }
- }
- publicByteGetIntensity(intx,inty)
- {
- Colorc=GetPixel(x,y);
- return(byte)((c.R*0.30+c.G*0.59+c.B*0.11)+0.5);
- }
- publicvoidUnlock()
- {
- if(_bitmapData!=null)
- {
- _bitmap.UnlockBits(_bitmapData);
- _bitmapData=null;
- }
- }
- publicvoidSave(stringfilename,ImageFormatformat)
- {
- _bitmap.Save(filename,format);
- }
- publicvoidSave(stringfilename)
- {
- _bitmap.Save(filename);
- }
- #endregion
- }
- }
在项目中添加现有项,把Form1.cs和Form1.Designer.cs一起加入,使其为启动的主窗体,即可开始调试本程序。
游戏原理很简单,就这这几个步骤。
- 对背景采样(注意不能有运动物体)
- 从视频里减去背景(剩下的就是伟岸的你了)
- 二值化剪影
- 读取板砖范围内的像素点,和剪影交叉超过20%则认为被点击
- 5.如此这般
上面第4步,按照我设想的其实应该分成a.查找剪影边界,生成Region,b.求板砖和Region的交集,若不为空,则认为相交。现在这种算法效率太低。
实际操作时发现AForge的边缘检测算法似乎对我电脑上130w的摄像头有点勉为其难,效果相当不好。
无所谓了,反正是玩嘛。于是就用遮罩+XOR提取了运动图像部分(人)。
游戏攻略:
- 使用身体任何一个部分去碰触红色板砖即可。
- 永远不要妄想能抓住板砖。
下面来个游戏动画图。
欢迎指正!
关于体感游戏的一些思考
体感游戏,从Wii打响第一枪开始至今已经很多年了。NDS的吹气玩法,Microsoft的Kinect等等,无不在提醒着我们,体感控制,正在日趋完善。
前段时间看到一个科技视频,美国科学家使用布置在房间、手持的多个摄像机、投影仪同步,然后实时生成房间、物品和人的3D数据模型,实现了人体体感控制任意虚拟物品的科幻效果。
视频链接:点击访问
作者:野比 (conmajia@gmail.com)
时间:May, 2012
(全文完)