首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 开源软件 >

Kinect开发课程三:利用OpenNI进行手势识别

2012-07-16 
Kinect开发教程三:利用OpenNI进行手势识别??? 这是第二个范例,小斤将介绍如何使用OpenNI让Kinect识别出手

Kinect开发教程三:利用OpenNI进行手势识别

??? 这是第二个范例,小斤将介绍如何使用OpenNI让Kinect识别出手势,并显示输出。目前版本的OpenNI支持四种手势:RaiseHand, Wave, Click和MovingHand,分别代表手的“举起”,“挥动”,“前推”和“移动”四种动作。值得一提的是,当前微软官方的Kinect SDK还不支持手势识别,也可以说是使用OpenNI的好处之一吧。


??? 有了手势识别后,其实可以利用Kinect做一些实际的东东,比如利用鼠标键盘控制一些应用程序等等。

?

??? 闲话不说了,速度搞起。代码一部分参考了Heresy童鞋的文章,手势部分写得很完备了,在巨人的肩膀上,小斤使用OpenCV进行显示,红色点表示手的位置轨迹,蓝色实心圈表示前推的位置,黄色直线表示手挥动的轨迹(从起点到终点)。

?

#include <stdlib.h>#include <iostream>#include "opencv/cv.h"#include "opencv/highgui.h"#include <XnCppWrapper.h>using namespace std;using namespace cv;// output for XnPoint3Dostream& operator<<( ostream& out, const XnPoint3D& rPoint ){out << "(" << rPoint.X << "," << rPoint.Y << "," << rPoint.Z << ")";return out;}//【4】// callback function for gesture recognizedvoid XN_CALLBACK_TYPE gestureRecog( xn::GestureGenerator &generator,   const XnChar *strGesture,   const XnPoint3D *pIDPosition,   const XnPoint3D *pEndPosition,   void *pCookie ){cout << strGesture<<" from "<<*pIDPosition<<" to "<<*pEndPosition << endl;int imgStartX=0;int imgStartY=0;int imgEndX=0;int imgEndY=0;char locationinfo[100];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,"RaiseHand")==0){cvCircle(refimage,cvPoint(imgStartX,imgStartY),1,CV_RGB(255,0,0),2);}else if(strcmp(strGesture,"Wave")==0){cvLine(refimage,cvPoint(imgStartX,imgStartY),cvPoint(imgEndX,imgEndY),CV_RGB(255,255,0),6);}else if(strcmp(strGesture,"Click")==0){cvCircle(refimage,cvPoint(imgStartX,imgStartY),6,CV_RGB(0,0,255),12);}cvSetImageROI(refimage,cvRect(40,450,640,30));CvFont font;cvInitFont( &font, CV_FONT_VECTOR0,1, 1, 0, 3, 5);cvSet(refimage, cvScalar(255,255,255));sprintf(locationinfo,"From: %d,%d to %d,%d",(int)pIDPosition->X,(int)pIDPosition->Y,(int)(pEndPosition->X),(int)(pEndPosition->Y));cvPutText(refimage, locationinfo ,cvPoint(30, 30), &font, CV_RGB(0,0,0));cvResetImageROI(refimage);}void clearImg(IplImage* inputimg){CvFont font;cvInitFont( &font, CV_FONT_VECTOR0,1, 1, 0, 3, 5);memset(inputimg->imageData,255,640*480*3);cvPutText(inputimg, "Hand Raise!" ,cvPoint(20, 20), &font, CV_RGB(255,0,0));cvPutText(inputimg, "Hand Wave!" , cvPoint(20, 50), &font, CV_RGB(255,255,0));cvPutText(inputimg, "Hand Push!" , cvPoint(20, 80), &font, CV_RGB(0,0,255));}//【5】// callback function for gesture progressvoid XN_CALLBACK_TYPE gestureProgress( xn::GestureGenerator &generator,  const XnChar *strGesture,  const XnPoint3D *pPosition,  XnFloat fProgress,  void *pCookie ){cout << strGesture << ":" << fProgress << " at " << *pPosition << endl;}int main( int argc, char** argv ){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);XnStatus res;char key=0;// contextxn::Context context;res = context.Init();xn::ImageMetaData imgMD;// create generator xn::ImageGenerator imageGenerator;res = imageGenerator.Create( context ); //【1】xn::GestureGenerator gestureGenerator;res = gestureGenerator.Create( context );  //【2】// Add gesture//gestureGenerator.AddGesture( "MovingHand", NULL );gestureGenerator.AddGesture( "Wave", NULL );gestureGenerator.AddGesture( "Click", NULL );gestureGenerator.AddGesture( "RaiseHand", NULL );//gestureGenerator.AddGesture("MovingHand",NULL);  /【3】// 6. Register callback functions of gesture generatorXnCallbackHandle handle;gestureGenerator.RegisterGestureCallbacks( gestureRecog, gestureProgress, (void*)drawPadImg, handle );//start generate datacontext.StartGeneratingAll();res = context.WaitAndUpdateAll();  while( (key!=27) && !(res = context.WaitAndUpdateAll())  ) {  if(key=='c'){clearImg(drawPadImg);}imageGenerator.GetMetaData(imgMD);memcpy(cameraImg->imageData,imgMD.Data(),640*480*3);cvCvtColor(cameraImg,cameraImg,CV_RGB2BGR);cvShowImage("Gesture",drawPadImg);cvShowImage("Camera",cameraImg);key=cvWaitKey(20);}cvDestroyWindow("Gesture");cvDestroyWindow("Camera");cvReleaseImage(&drawPadImg);cvReleaseImage(&cameraImg);context.StopGeneratingAll();context.Shutdown();return 0;}

?

??? 【1】看过上一篇文章的童鞋应该已经了解了生成器的用法(传送门),对于手势识别,小斤使用了GestureGenerator这个生成器,它的创建方式与ImageGenerator一致,使用Context作为参数调用Create方法。


??? 【2】GestureGenerator创建后,只有我们告诉它,要识别什么手势它才干活。这边使用AddGesture方法,把手势加入。

?

??? 【3】这一步小斤注册了GestureGenerator相关的回调函数:

XnStatus xn::GestureGenerator::RegisterGestureCallbacks  (GestureRecognized  RecognizedCB,  GestureProgress  ProgressCB,  void *  pCookie, XnCallbackHandle &  hCallback )

??? 其中定义RecognizedCB是手势识别后的回调函数,ProgressCB是手势进行中的回调函数。pCookie是传给回调函数的指针,可以放一些用户数据,代码中,小斤把程序的画板图像指针传给了回调函数,这样便可以在回调函数中直接绘图了。hCallback是一个回调函数的handle,可用来注销回调函数,注销的方法是调用UnregisterGestureCallbacks? ( XnCallbackHandle? hCallback?? ) 。


??? 【4】这个gestureRecog()便是RecognizedCB回调函数的真身了,它有五个参数:

??? generator指定发现手势的生成器。

??? strGesture告诉我们哪种手势已被识别。

??? pIDPosition和pEndPosition代表了该手势的起始位置和终止位置。对于RaiseHand的手势,两个值是一样的,但对于Click和Wave手势,由于手的位置是发生过变化的,值是不同的。
??? pCookie是传入的用户数据。
??? 在【4】中,小斤针对不同的手势进行了绘图,此外,还显示了手的当前pIDPosition和pEndPosition。


??? 【5】gestureProgress()回调函数与gestureRecog()类似,因为是在手势进行中被调用的,它只有一个position,表示当前手的位置,此外,还有一个fProgress表示当前的进度。


??? 程序编译执行后,效果如下:
Kinect开发课程三:利用OpenNI进行手势识别


??? 小斤这边测试结果是,RaiseHand最容易触发,基本上都在RecognizedCB中出现,而MovingHand没有被触发过。Click和Wave手势在RecognizedCB和ProgressCB都可能触发,虽然Wave手势的轨迹不一定准确,但Wave轨迹的用处不大。

?

??? 如果组合使用RaiseHand,Click和Wave,通过一些位置判定和调整,实现应用程序的部分控制是没有多大问题的,大家自由发挥想象吧,有好点子欢迎讨论!



----------------------------------

?

作者:小斤(陈忻)

本文属于原创文章,如需转载引用请注明原文作者和链接,谢谢。

热点排行