Kinect开发教程四:用Kinect控制鼠标玩水果忍者PC版

最近Kinect连接Xbox玩水果忍者的视频非常红火,可惜小斤只有本本和Kinect,没法玩Xbox上的体感游戏。幸运的是,寻寻觅觅后,小斤发现水果忍者有PC版本,既然上一个教程我们已经可以让Kinect认出我们手势,在这基础上,我们用手来控制鼠标,就可以在PC上玩咯!

视频地址:,徒手切还需要多练练。

上个教程,我们通过RaiseHand来捕捉举起后手的位置,于是小斤决定,用RaiseHand来触发鼠标移动事件,用Click来触发鼠标单击,但测试结果不让人满意,鼠标移动一卡一卡的,原因是RaiseHand识别需要时间,达不到实时的标准,怎么办呢?小斤翻阅了OpenNI的文档,找到了tracking的相关API。这样,在我们识别出手后,使用跟踪的办法得到手的实时位置,移动鼠标的问题迎刃而解!这就好比在茫茫人海中,跟着一个人走比找到一个人更容易!

因为这个教程代码量稍微多了点,小斤就不一股脑全抛上来了,先上主函数,再解释回调函数。

以下是Main.cpp的内容:

#include <stdlib.h>#include <iostream>#include "opencv/cv.h"#include "opencv/highgui.h"#include <XnCppWrapper.h>#include "KinectGesture.h"#include "Appmessage.h"using namespacestd;using namespacecv;//Generatorxn::GestureGenerator gestureGenerator;xn::HandsGenerator handsGenerator;xn::ImageGenerator imageGenerator;int isRealMouseControl=0;//【1】// main functionvoid main(){IplImage* drawPadImg=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);IplImage* cameraImg=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);cvNamedWindow("Gesture",1);cvNamedWindow("Camera",1);clearImg(drawPadImg);CvFont font;cvInitFont( &font,CV_FONT_VECTOR0,1, 1, 0, 3, 5);XnStatus res;char key=0;// Contextxn::Context context;res = context.Init();xn::ImageMetaData imageMD;// Generatorres = imageGenerator.Create( context);res = gestureGenerator.Create( context);//【2】res=handsGenerator.Create(context);// Add gesturegestureGenerator.AddGesture("Wave", NULL);gestureGenerator.AddGesture("Click", NULL);// Register callback functionsXnCallbackHandle gestureCBHandle;XnCallbackHandle handsCBHandle;gestureGenerator.RegisterGestureCallbacks(GRecognized, GProgress,(void*)drawPadImg,gestureCBHandle );//【3】handsGenerator.RegisterHandCallbacks(Hand_Create, Hand_Update,Hand_Destroy, (void*)drawPadImg, handsCBHandle);// Start generatecontext.StartGeneratingAll();res = context.WaitAndUpdateAll();while( (key!=27) && !(res = context.WaitAndUpdateAll()) ){res = context.WaitAndUpdateAll();imageGenerator.GetMetaData(imageMD);memcpy(cameraImg->imageData,imageMD.Data(),640*480*3);cvCvtColor(cameraImg,cameraImg,CV_RGB2BGR);cvPutText(drawPadImg,"Wave Your Hand to Start Tracking",cvPoint(20, 20), &font, CV_RGB(255,0,0));cvShowImage("Gesture",drawPadImg);cvShowImage("Camera",cameraImg);key=cvWaitKey(20);switch(key){case ‘c’:clearImg(drawPadImg);break;//【4】case ‘m’://simulate real mouseisRealMouseControl=1-isRealMouseControl;break;default:if(key != -1) printf("You Press%d\n",key);}}cvDestroyWindow("Gesture");cvDestroyWindow("Camera");cvReleaseImage(&drawPadImg);cvReleaseImage(&cameraImg);context.StopGeneratingAll();context.Shutdown();}

【1】程序执行后,窗体和显示和上一个手势识别的例程是一样的,由于要使用mouse_event来控制鼠标,小斤选择了MFC框架,主要是一个Dialog和一个按钮。由于我们的程序执行时,是使用OpenCV的highgui进行图像显示的,这里点击窗体上按钮后创建并开始线程,线程函数KinectGestureMain(),也就是这里的主函数。

【2】KinectGestureMain()中的内容,大部分和上一个例程是一样的,在【2】这里,小斤创建了一个HandsGenerator,这个生成器主要帮我们负责跟踪的工作。它的创建方法和其它的生成器是一样的,,传一个Context给Create()方法

【3】与GestureGenerator类似,我们需要为HandsGenerator注册回调函数,

XnStatusxn::HandsGenerator::RegisterHandCallbacks ( HandCreate CreateCB, HandUpdate UpdateCB, HandDestroy DestroyCB, void * pCookie, XnCallbackHandle & hCallback )

其中定义HandCreate是一个新的手(跟踪)被创建时调用的,HandDestroy 则相反,在手消失后被调用,UpdateCB在手变化位置时被调用。另外,pCookie是传给回调函数的指针,可以放一些用户数据,小斤把程序的画板图像指针传入,这样可在回调函数中直接绘图了。phCallback是一个回调函数的handle,可用来注销回调函数。

【4】这边设定了,按m键,进入鼠标控制模式。

其它代码都和上一个例程差不多,我们来看看回调函数。

// callback function for gesture recognizedvoid XN_CALLBACK_TYPEGRecognized( xn::GestureGenerator &generator,const XnChar *strGesture,const XnPoint3D *pIDPosition,const XnPoint3D *pEndPosition,void *pCookie ){int imgStartX=0;int imgStartY=0;int imgEndX=0;int imgEndY=0;//【5】imgStartX=(int)(640/2-(pIDPosition->X));imgStartY=(int)(480/2-(pIDPosition->Y));imgEndX=(int)(640/2-(pEndPosition->X));imgEndY=(int)(480/2-(pEndPosition->Y));IplImage* refimage=(IplImage*)pCookie;if(strcmp(strGesture,"Wave")==0){cvLine(refimage,cvPoint(imgStartX,imgStartY),cvPoint(imgEndX,imgEndY),CV_RGB(255,255,0),6);//【6】handsGenerator.StartTracking(*pEndPosition);}else if(strcmp(strGesture,"Click")==0){cvCircle(refimage,cvPoint(imgStartX,imgStartY),6,CV_RGB(0,0,255),12);//【7】if(isRealMouseControl){messageHandler(cvPoint(imgStartX,imgStartY),0,REAL_MOUSE_CLICK);}}}// callback function forgesture progressvoid XN_CALLBACK_TYPEGProgress( xn::GestureGenerator &generator,const XnChar *strGesture,const XnPoint3D *pPosition,XnFloat fProgress,void *pCookie ){}

【5】由于pIDPosition和pEndPosition的坐标,是以屏幕中心为(0,0)点的坐标系,在OpenCV中的显示,是以屏幕左上角为(0,0)点,所以这里做了一个转换。

【6】这一段代码,我们的GestureGenerator识别出“挥动”手势后,调用了HandsGenerator的StartTracking()方法来开始在pEndPosition这个位置跟踪手,pEndPosition便是“挥动”“手势的结束位置。

【7】中,如果识别出了“前推”手势,并开启了鼠标控制模式,就调用小斤定义的messageHandler()方法模拟鼠标点击。这个messageHandler()待会会在AppMessage.cpp中实现。

战胜困难,走出困境,成功就会属于你。

Kinect开发教程四:用Kinect控制鼠标玩水果忍者PC版

相关文章:

你感兴趣的文章:

标签云: