这是第二个范例,小斤将介绍如何使
用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 XnPoint3D
ostream& operator<<( ostream& out, const XnPoint3D& rPoint )
{
out << "(" << rPoint.X << "," << rPoint.Y << "," << rPoint.Z << ")";
return out;
}
//【4】
// callback function for gesture recognized
void 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 progress
void 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;
// context
xn::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 generator
XnCallbackHandle handle;
gestureGenerator.RegisterGestureCallbacks( gestureRecog, gestureProgress, (void*)drawPadImg, handle );
//start generate data
context.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表示当前的进度。
程序编译执行后,效果如下:
小斤这边测试结果是,RaiseHand最容易触发,基本上都在RecognizedCB中出现,而MovingHand没有被触发过。Click和
Wave手势在RecognizedCB和ProgressCB都可能触发,虽然Wave手势的轨迹不一定准确,但Wave轨迹的用处不大。
如果组合使用RaiseHand,Click和Wave,通过一些位置判定和调整,实现应用程序的部分控制是没有多大问题的,大家自由发挥想象吧,有好点子欢迎讨论!
----------------------------------
作者:小斤(陈忻)
本文属于原创文章,如需转载引用请注明原文作者和链接,谢谢。
分享到:
相关推荐
5. **opencv集成**:将openNI获取的数据与opencv结合,可以进行更复杂的图像处理和计算机视觉任务,如面部识别、手势识别等。 6. **代码移植**:学习如何将示例代码整合到自己的开发环境中,包括设置项目依赖、配置...
为了利用OPENNI2 Kinect.dll的功能,开发者需要确保他们的开发环境中已经包含了该库,并正确地配置和链接了相关的API。在应用中,通过调用DLL中的函数,开发者能够启动和管理Kinect设备,获取并处理深度和彩色图像...
通过这两份文档,开发者可以深入了解OpenNI的架构、功能和使用方法,从而利用这一框架开发出创新的自然交互应用。对于中文使用者,中文手册提供了一个方便的语言环境,而英文版用户指南则提供了更多细节和技术深度。...
它提供了数据捕获、处理和上下文理解的功能,便于开发者构建手势识别、物体识别等应用。 2. **ROS集成**:ROS(Robot Operating System)是一个广泛使用的机器人软件开发框架。OpenNI与ROS的结合,允许开发者将奥比...
OpenNI2 是一个开源的开发接口,用于与各种传感器(如Kinect,PrimeSense等)交互,以便在各种平台上进行自然交互和计算机视觉应用。它提供了简单易用的API,让开发者可以方便地访问和处理来自3D深度相机的数据,如...
在Kinect的支持下,通过对手势的识别和跟踪,来代替鼠标移动和点击。该程序使人能够徒手控制PC,如用Firefox浏览网页,玩水果忍者等等。此程序为非MFC版本。开发教程:...
"Kinect应用汇总"很可能是各种基于Kinect的应用实例和项目展示,这将涵盖从基础的体感游戏到复杂的三维人体扫描和手势识别等多种应用场景。通过学习这些案例,开发者能够了解到Kinect在实际项目中的应用方式,以及...
OpenNI(Open Natural Interaction)是一个开源框架,主要设计用于自然人机交互,特别是与3D摄像头,如微软的Kinect,进行交互。OpenNI 2.3.0.50是该框架的一个版本,提供了对多种传感器的支持,使得开发者能够轻松...
OpenNI(Open Natural Interaction)是一种开源中间件,旨在简化与自然人机交互相关的软件开发,尤其是针对3D摄像头,如微软的Kinect。OpenNI2是其第二个主要版本,提供了更多的功能和改进的性能。在本例中,我们...
OpenNI(Open Natural Interaction)的主要目标是为开发者提供一个统一的接口,以便于他们开发基于自然交互的应用程序,比如手势识别、人体骨架追踪、环境感知等。在OpenNI2.1.0中,你可以期待以下核心功能和改进: ...
开发者可以利用现有的资产和教程,如预设的Kinect角色模型、手势识别库等,来加速开发进程。同时,社区中的其他开发者也会分享他们的经验和解决方案,这对于初学者来说是一笔宝贵的财富。 总的来说,OpenNI与Unity...
1. **OpenNI框架**:OpenNI是为自然用户界面提供一个通用平台,它定义了API和规范,使得开发者能够轻松地集成3D传感器,如Kinect、PrimeSense Carmine等,实现手势识别、身体骨架跟踪等功能。它包括数据捕获、处理和...
OpenNI 支持多种感应器,包括深度相机和RGB摄像头,使得开发者可以创建具有手势识别、物体识别和场景分析等功能的项目。 2. **系统兼容性**:压缩包中的“Windows”、“Linux”和“Android”文件夹分别包含了针对这...
**Kinect 体感连线小游戏**是一款利用微软的Kinect传感器技术实现的人机交互游戏,旨在帮助用户通过手势识别进行游戏互动,为学习和理解Kinect体感技术提供了一个基础的入门实例。这款游戏展示了如何将Kinect传感器...
2. **深度图像处理**: Kinect的深度摄像头能生成3D空间信息,开发者可以利用这些数据进行物体识别、手势识别或场景分析。 3. **骨骼追踪**: Kinect能实时追踪人体关节,为游戏、健身应用或虚拟现实提供自然的运动...
OpenNI支持骨骼追踪、手势识别等功能,进一步丰富了Kinect的功能应用。 WPF,即Windows Presentation Foundation,是.NET Framework的一部分,用于构建Windows桌面应用程序。WPF提供了强大的图形渲染能力、数据绑定...
另一标签“OpenNI”(Open Natural Interaction)是一个开源框架,旨在为开发人员提供一个统一的接口,以便于他们在多种硬件平台上(如Kinect)实现自然交互,包括手势识别。OpenNI支持多种传感器,并且拥有丰富的库...
4. **配置OpenNI**:安装OpenNI和Primesense库,配置它们以识别和使用Kinect设备。 5. **测试驱动**:安装完成后,运行一些示例程序或者使用OpenNI的测试工具验证Kinect是否能正常工作,如捕获颜色图像、深度图或...
传统的Kinect开发通常采用C++或C#语言,但《Making Things See》一书提供了使用Java语言进行Kinect开发的指导。这对于那些熟悉Java语言的开发者来说是一大福音。书中详细介绍了如何安装并使用Simple OpenNI ...
OpenNI(开放自然交互)是一个跨平台的开发框架,它允许程序员创建能够与用户进行自然交互的应用程序,特别是那些涉及手势识别、三维重建和运动捕捉的项目。在Processing中使用SimpleOpenNI,开发者可以轻松地接入...