- 浏览: 33519 次
文章分类
最新评论
-
Tophuhu:
这个系列的图全挂了,请检查一下
Kinect开发教程七:OpenNI2自带范例程序的编译执行 -
tianzhilishu:
我使用过opencv,看到你的程序非常的激情,希望能够获得你的 ...
Kinect开发教程四:用Kinect控制鼠标玩水果忍者PC版
临近毕业,小斤最近一直忙活着相关事宜,教程这边也搁浅了一阵。前几篇教程介绍了OpenNI的一些基本范例以及手势应用,但如果光用Kinect识别一些手势,总有点杀鸡用牛刀的感觉。在大部分体感应用中,获取骨架的步骤都不可缺少,这也是小斤一直想写的专题。
好了,废话不多说了,让我们进入正题吧!
在OpenNI库的enum XnSkeletonJoint中,定义了24个人体的关节,如下:
XN_SKEL_HEAD = 1, XN_SKEL_NECK = 2,
XN_SKEL_TORSO = 3, XN_SKEL_WAIST = 4,
XN_SKEL_LEFT_COLLAR = 5, XN_SKEL_LEFT_SHOULDER = 6,
XN_SKEL_LEFT_ELBOW = 7, XN_SKEL_LEFT_WRIST = 8,
XN_SKEL_LEFT_HAND = 9, XN_SKEL_LEFT_FINGERTIP =10,
XN_SKEL_RIGHT_COLLAR =11, XN_SKEL_RIGHT_SHOULDER =12,
XN_SKEL_RIGHT_ELBOW =13, XN_SKEL_RIGHT_WRIST =14,
XN_SKEL_RIGHT_HAND =15, XN_SKEL_RIGHT_FINGERTIP =16,
XN_SKEL_LEFT_HIP =17, XN_SKEL_LEFT_KNEE =18,
XN_SKEL_LEFT_ANKLE =19, XN_SKEL_LEFT_FOOT =20,
XN_SKEL_RIGHT_HIP =21, XN_SKEL_RIGHT_KNEE =22,
XN_SKEL_RIGHT_ANKLE =23, XN_SKEL_RIGHT_FOOT =24
小斤试下来,目前可使用的有14个关节,如下图:
先上代码:
#include <stdlib.h> #include <iostream> #include <vector> #include <XnCppWrapper.h> #include <XnModuleCppInterface.h> #include "cv.h" #include "highgui.h" using namespace std; using namespace cv; //#pragma comment (lib,"cv210") //#pragma comment (lib,"cxcore210") //#pragma comment (lib,"highgui210") //#pragma comment (lib,"OpenNI") //【1】 xn::UserGenerator userGenerator; xn::DepthGenerator depthGenerator; xn::ImageGenerator imageGenerator; /* XN_SKEL_HEAD = 1, XN_SKEL_NECK = 2, XN_SKEL_TORSO = 3, XN_SKEL_WAIST = 4, XN_SKEL_LEFT_COLLAR = 5, XN_SKEL_LEFT_SHOULDER = 6, XN_SKEL_LEFT_ELBOW = 7, XN_SKEL_LEFT_WRIST = 8, XN_SKEL_LEFT_HAND = 9, XN_SKEL_LEFT_FINGERTIP =10, XN_SKEL_RIGHT_COLLAR =11, XN_SKEL_RIGHT_SHOULDER =12, XN_SKEL_RIGHT_ELBOW =13, XN_SKEL_RIGHT_WRIST =14, XN_SKEL_RIGHT_HAND =15, XN_SKEL_RIGHT_FINGERTIP =16, XN_SKEL_LEFT_HIP =17, XN_SKEL_LEFT_KNEE =18, XN_SKEL_LEFT_ANKLE =19, XN_SKEL_LEFT_FOOT =20, XN_SKEL_RIGHT_HIP =21, XN_SKEL_RIGHT_KNEE =22, XN_SKEL_RIGHT_ANKLE =23, XN_SKEL_RIGHT_FOOT =24 */ //a line will be drawn between start point and corresponding end point int startSkelPoints[14]={1,2,6,6,12,17,6,7,12,13,17,18,21,22}; int endSkelPoints[14]={2,3,12,21,17,21,7,9,13,15,18,20,22,24}; // callback function of user generator: new user void XN_CALLBACK_TYPE NewUser( xn::UserGenerator& generator, XnUserID user,void* pCookie ) { cout << "New user identified: " << user << endl; //userGenerator.GetSkeletonCap().LoadCalibrationDataFromFile( user, "UserCalibration.txt" ); generator.GetPoseDetectionCap().StartPoseDetection("Psi", user); } // callback function of user generator: lost user void XN_CALLBACK_TYPE LostUser( xn::UserGenerator& generator, XnUserID user,void* pCookie ) { cout << "User " << user << " lost" << endl; } // callback function of skeleton: calibration start void XN_CALLBACK_TYPE CalibrationStart( xn::SkeletonCapability& skeleton,XnUserID user,void* pCookie ) { cout << "Calibration start for user " << user << endl; } // callback function of skeleton: calibration end void XN_CALLBACK_TYPE CalibrationEnd( xn::SkeletonCapability& skeleton,XnUserID user,XnCalibrationStatus calibrationError,void* pCookie ) { cout << "Calibration complete for user " << user << ", "; if( calibrationError==XN_CALIBRATION_STATUS_OK ) { cout << "Success" << endl; skeleton.StartTracking( user ); //userGenerator.GetSkeletonCap().SaveCalibrationDataToFile(user, "UserCalibration.txt" ); } else { cout << "Failure" << endl; //For the current version of OpenNI, only Psi pose is available ((xn::UserGenerator*)pCookie)->GetPoseDetectionCap().StartPoseDetection( "Psi", user ); } } // callback function of pose detection: pose start void XN_CALLBACK_TYPE PoseDetected( xn::PoseDetectionCapability& poseDetection,const XnChar* strPose,XnUserID user,void* pCookie) { cout << "Pose " << strPose << " detected for user " << user << endl; ((xn::UserGenerator*)pCookie)->GetSkeletonCap().RequestCalibration( user, FALSE ); poseDetection.StopPoseDetection( user ); } void clearImg(IplImage* inputimg) { CvFont font; cvInitFont( &font, CV_FONT_VECTOR0,1, 1, 0, 3, 5); memset(inputimg->imageData,255,640*480*3); } int main( int argc, char** argv ) { char key=0; int imgPosX=0; int imgPosY=0; // initial context xn::Context context; context.Init(); xn::ImageMetaData imageMD; IplImage* cameraImg=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3); cvNamedWindow("Camera",1); // map output mode XnMapOutputMode mapMode; mapMode.nXRes = 640; mapMode.nYRes = 480; mapMode.nFPS = 30; // create generator depthGenerator.Create( context ); depthGenerator.SetMapOutputMode( mapMode ); imageGenerator.Create( context ); userGenerator.Create( context ); //【2】 // Register callback functions of user generator XnCallbackHandle userCBHandle; userGenerator.RegisterUserCallbacks( NewUser, LostUser, NULL, userCBHandle ); //【3】 // Register callback functions of skeleton capability xn::SkeletonCapability skeletonCap = userGenerator.GetSkeletonCap(); skeletonCap.SetSkeletonProfile( XN_SKEL_PROFILE_ALL ); XnCallbackHandle calibCBHandle; skeletonCap.RegisterToCalibrationStart( CalibrationStart,&userGenerator, calibCBHandle ); skeletonCap.RegisterToCalibrationComplete( CalibrationEnd,&userGenerator, calibCBHandle ); //【4】 // Register callback functions of Pose Detection capability XnCallbackHandle poseCBHandle; userGenerator.GetPoseDetectionCap().RegisterToPoseDetected( PoseDetected,&userGenerator, poseCBHandle ); // start generate data context.StartGeneratingAll(); while( key!=27 ) { context.WaitAndUpdateAll(); imageGenerator.GetMetaData(imageMD); memcpy(cameraImg->imageData,imageMD.Data(),640*480*3); cvCvtColor(cameraImg,cameraImg,CV_RGB2BGR); // get users XnUInt16 userCounts = userGenerator.GetNumberOfUsers(); if( userCounts > 0 ) { XnUserID* userID = new XnUserID[userCounts]; userGenerator.GetUsers( userID, userCounts ); for( int i = 0; i < userCounts; ++i ) { //【5】 // if is tracking skeleton if( skeletonCap.IsTracking( userID[i] ) ) { XnPoint3D skelPointsIn[24],skelPointsOut[24]; XnSkeletonJointTransformation mJointTran; for(int iter=0;iter<24;iter++) { //XnSkeletonJoint from 1 to 24 skeletonCap.GetSkeletonJoint( userID[i],XnSkeletonJoint(iter+1), mJointTran ); skelPointsIn[iter]=mJointTran.position.position; } depthGenerator.ConvertRealWorldToProjective(24,skelPointsIn,skelPointsOut); //【6】 for(int d=0;d<14;d++) { CvPoint startpoint = cvPoint(skelPointsOut[startSkelPoints[d]-1].X,skelPointsOut[startSkelPoints[d]-1].Y); CvPoint endpoint = cvPoint(skelPointsOut[endSkelPoints[d]-1].X,skelPointsOut[endSkelPoints[d]-1].Y); cvCircle(cameraImg,startpoint,3,CV_RGB(0,0,255),12); cvCircle(cameraImg,endpoint,3,CV_RGB(0,0,255),12); cvLine(cameraImg,startpoint,endpoint,CV_RGB(0,0,255),4); } } } delete [] userID; } cvShowImage("Camera",cameraImg); key=cvWaitKey(20); } // stop and shutdown cvDestroyWindow("Camera"); cvReleaseImage(&cameraImg); context.StopGeneratingAll(); context.Shutdown(); return 0; }
【1】 对于人体骨架的获取,小斤声明了UserGenerator这个生成器,UserGenerator具有检测新的User(以下称为人物)出现或者离开, 获取画面中的人物数,人物位置信息,与上一教程介绍的GestureGenerator类似,通过注册回调函数的方式,一旦其检测到了动静(如人物出 现),那么相应的回调函数就会被调用。
【2】 小斤为UserGenerator注册了NewUser和LostUser两个回调函数,对应人物出现和人物消失。
【3】 这里出现了一个新的Capability,SkeletonCapability。小斤为了避免混淆,常常将Capability理解为生成器的一种能 力,比如SkeletonCapability就可以理解UserGenerator获取人物骨架信息的能力。
在获取人物骨架前,首先要进行标定的工作,因此SkeletonCapability需要注册两个回调函数CalibrationStart和CalibrationEnd,分别在人物标定开始与结束时调用。(在较早版本的OpenNI中,接口名可能有所变化)
【4】 与【3】类似,userGenerator.GetPoseDetectionCap()获取了一个PoseDetectionCapability,这个Capability可以检测人物的特定姿势,目前来说,只支持Psi姿势,如图:
小斤并为其注册了回调函数PoseDetected,在检测到人物的Psi姿势时,会调用该函数。
将【2】【3】【4】的回调函数串联起来看,(1)人物出现会触发NewUser(),开始Pose检测;(2)检测到Pose会触发 PoseDetected(),请求标定;(3)标定开始触发CalibrationStart();(4)标定结束触发 CalibrationEnd(),如果标定成功,那么调用SkeletonCapability的StartTracking()开始跟踪对应的人物。
【5】 通过GetSkeletonJoint()方法,可以得到对应关节的XnSkeletonJointTransformation,这个结构体包含 position和orientation,position中又包含一个position和fConfidence,分别代表关节的位置和可信 度,orientation同样如此,包含关节的运动方向和可信度。这里小斤对24个关节都进行了操作,但能得到位置信息的只有14个。
这些步骤得到的position信息,是一个真实场景的3D坐标,需要通过投影转换到屏幕坐标,转换过程通过ConvertRealWorldToProjective()方法实现。
【6】 为了更直观地输出显示,可以各个关节通过直线连接起来,形成一个人体的骨架。小斤定义了startSkelPoints和endSkelPoints数 组,两个数组的值一一对应,代表一组起点终点的关节对,将每组起点和终点通过直线连接,比如HEAD与NECT与TORSO等。
整个程序启动后,先将身体正对摄像头(至少露出头部和上半身),控制台会显示“New user identified”,然后做出Psi姿势,在Pose Psi detected后,程序开始标定工作,此时维持Psi姿势数秒,标定成功后,骨架就会正确显示出来了。祝大家玩得愉快。
----------------------------------
作者:小斤(陈忻)
本文属于原创文章,如需转载引用请注明原文作者和链接,谢谢。
发表评论
-
Kinect开发教程八:OpenNI2显示深度、彩色及融合图像
2013-02-27 23:55 3868在《Kinect开发教程二:OpenNI读取深度 ... -
Kinect开发教程七:OpenNI2自带范例程序的编译执行
2013-02-14 19:30 2019小斤觉得,研究自 ... -
Kinect开发教程六:OpenNI2简介、安装与VS开发环境配置
2013-02-14 19:27 3108简介 最近OpenNI2的推出,小斤也 ... -
Kinect开发教程四:用Kinect控制鼠标玩水果忍者PC版
2011-10-20 23:37 4004最近Kinect连接Xbox玩水果忍者的视频非常红火, ... -
Kinect开发教程三:利用OpenNI进行手势识别
2011-10-20 23:30 3915这是第二个范例,小斤将介绍如何使 用OpenNI让K ... -
Kinect开发教程二:OpenNI读取深度图像与彩色图像并显示
2011-10-20 23:18 5539细心的朋友肯定已经发现Kinect上长了三只眼睛, ... -
Kinect开发教程一:OpenNI的安装与开发环境配置
2011-10-20 23:15 6965Kinect作为新一代的体感 ...
相关推荐
"适合学习Kinect开发的使用"进一步强调了这个包的教育和学习价值,它可能包含示例代码、文档以及教程资源,帮助用户理解和掌握如何利用Kinect进行自然交互的编程。 **标签解析:** - **openNI**:这是一个跨平台的...
3. **骨架追踪**:OpenNI能识别并追踪人体的关节,生成骨架模型,这在游戏、健身应用或者人机交互界面设计中非常有用。 4. **编程接口**:OpenNI提供了C++和C#的API,方便开发者进行程序开发。同时,它也支持脚本...
5. **骨架追踪**:OpenNI支持人体骨骼追踪,可以识别和跟踪用户的关节位置,这对于体感游戏和动作识别应用非常有用。 6. **社区支持**:OpenNI有一个活跃的开发者社区,提供了许多示例代码、教程和论坛支持,帮助...
3. **骨骼追踪**:OpenNI2 支持对人体骨架的实时追踪,可以识别出关键关节的位置,用于游戏控制、运动分析等领域。 4. **手势识别**:利用深度信息,OpenNI2 可以识别和理解特定的手势,实现无接触的用户界面或控制...
OpenNI(Open Natural Interaction)是一种开源中间件,旨在简化与自然人机交互相关的软件开发,尤其是针对3D摄像头,如微软的Kinect。OpenNI2是其第二个主要版本,提供了更多的功能和改进的性能。在本例中,我们...
4. **骨架追踪**:对于支持骨骼追踪的设备,OpenNI2提供了API来检测和跟踪人体关节的位置,这对于开发体感游戏和交互式应用非常有用。 5. **数据同步**:OpenNI2能够确保不同数据流(如深度图和颜色图)之间的精确...
OpenNI(Open Natural Interaction)的主要目标是为开发者提供一个统一的接口,以便于他们开发基于自然交互的应用程序,比如手势识别、人体骨架追踪、环境感知等。在OpenNI2.1.0中,你可以期待以下核心功能和改进: ...
使用OpenNI与Unity3D开发Kinect体感游戏,首先要了解OpenNI的基本概念和API,包括如何初始化传感器,获取深度图像和骨架数据等。然后,在Unity3D中,我们需要创建对应的脚本和游戏对象,以处理从OpenNI获取的数据,...
1. **OpenNI框架**:OpenNI是为自然用户界面提供一个通用平台,它定义了API和规范,使得开发者能够轻松地集成3D传感器,如Kinect、PrimeSense Carmine等,实现手势识别、身体骨架跟踪等功能。它包括数据捕获、处理和...
在配置和开发环境中,国内的CNKINECT论坛是一个宝贵的资源库,提供了许多配置OpenNI和Kinect的教程。在Windows XP系统上,可能需要使用特定版本的OpenNI和.NET框架,因为新版本可能会与操作系统不兼容。OpenCV是一个...
OpenNI1是早期版本的OpenNI框架,虽然现在有了更新的OpenNI2,但OpenNI1仍然被许多项目和教程所使用,因为它对旧硬件有更好的支持。 这个程序可能包括了以下关键知识点: 1. **OpenNI框架**:OpenNI是Natural ...
OpenNI(开放自然交互)是一个跨平台的开发框架,它允许程序员创建能够与用户进行自然交互的应用程序,特别是那些涉及手势识别、三维重建和运动捕捉的项目。在Processing中使用SimpleOpenNI,开发者可以轻松地接入...
3. **工具与库**:如OpenCV和OpenNI等第三方库可以辅助Kinect的开发,提供额外的功能和优化。 通过深入学习和实践,开发者可以掌握利用Kinect C++ SDK开发AR应用的核心技术,无论是游戏、教育还是工业领域,都有...