已阅读5页,还剩9页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Kinect+OpenNI学习笔记之7(OpenNI自带的类实现手部跟踪)前言本文主要介绍使用OpenNI中的HandsGenerator来完成对人体手部的跟踪,在前面的文章Kinect+OpenNI学习笔记之5(使用OpenNI自带的类进行简单手势识别)中已经介绍过使用GestureGenerator这个类来完成对几个简单手势的识别,这次介绍的手部跟踪是在上面简单手势识别的结果上开始跟踪的,这是OpenNI的优点,微软的SDK据说是不能单独对手部进行跟踪,因为使用MS的SDK需要检测站立人体的骨骼,然后找出节点再进行跟踪,不懂最新版本的是否支持这个功能。而此节讲的OpenNI完成手部的跟踪就不要求人必须处于站立姿势。开发环境:QtCreator2.5.1+OpenNI1.5.4.0+Qt4.8.2实验说明本次实验是分为2个类来设计的。COpenNI和CKinectReader这2个类。COpenNI类负责完成Kinect的OpenNI驱动,而CKinectReader类负责将kinect读取的信息在Qt中显示出来,且使用定时器定时刷新,此过程中可以在图像中画内容。进行手势的整体流程大概如下:有关手势识别和跟踪的回调函数的设置在COpenNI这个类中进行,但是因为回调函数是static类型,所以对应函数里面的变量也必须是static类型,但是我们的变量初始化又放在了类中进行,而static类型的变量不能在类中进行初始化,因此最好将回调函数用到的几个static类型的变量直接放在了类外,这样虽然达到了效果,不过貌似不是一个完整的类的设计。暂时没找到好的解决方法。从官方文档来看,OpenNI中进行手部跟踪,即采用节点hand generator来跟踪需要搭配手势检测的节点gesture generator,其代码实现流程如下:先使用gesture generator来侦测特定的手势当检测到特定的手势后开始进行handsgenerator的starttracking()函数来进行跟踪手部。当hands generator开始跟踪手部位置时,HandCreate()函数被调用。以后每当有变化的时候,都会执行HandUpdate()函数。如果手势超出了可侦测的范围,则其回自动调用HandDestroy()函数。C/c+知识点总结:如果一个数据类型声明为auto了,那么说明该数据类型为local局部变量,一般auot关键字可以省略。map表示的是一个键值对,其中第一个参数为键值对的类型id,这个具有唯一性,第二个是该数据类型的对应值。map的cbegin()方法表示的是返回一个常量迭代器。array数据类型其实就是一个数组类型,定义它的时为array表示,其长度为n,数组中的元素数据类型为int型。static函数有点类似回调函数,一般是用来记录类对象被引用的次数或者这个函数的地址需要被外部代码调用。静态函数有2个好处,一是只能被其自己的文件使用,不能被其它的文件使用。二是其它文件可以定义相同名字的函数,不会发生冲突。如果是在类中使用静态函数,则它是为类服务的而不是为了某一个类的具体对象服务。普通的成员函数都隐含了一个this指针,因为普通成员函数总是与具体的某个类的具体对象的。但静态成员函数由于不是与任何对象相联系,因此它不具有this指针。从这个意义上讲,它无法访问属于类对象的某个非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数。由于在本程序中,需要用到回调函数,而回调函数在类中一般需要声明成静态函数,所以在回调函数中调用类的成员变量时这些变量不能够是非静态的成员变量,编程时一定要注意。比如说在回调函数中有代码hands_generator.StartTracking(*pIDPosition);其中hands_generaotr是普通私有变量,这时编译代码时会出现如下错误提示:另外类中的静态成员变量是属于类的,不是属于对象的,因此在定义对象的时候不能够对其进行初始化,也就是说不能够用构造函数来初始化它,如果在类外来初始化它,应该加上在变量前加上类名,而不是变量名。Qt知识点总结:如果需要用QPainter来绘图的话,则需要将绘图部分的代码放在begin()和end()方法中,外,用QPainter 来创建一个新的绘图类时,其内部已经隐含了具有begin()方法。实验结果:这是实验中截图的一张结果,该实验可以同时跟踪多个手部,每一个使用不同的颜色来显示其轨迹,当识别到手部后,可以使用手指在空中写字。实验主要部分代码及注释(附录有实验工程code下载地址):copenni.cpp:#ifndef COPENNI_CLASS#define COPENNI_CLASS#include #include #include #include using namespace xn;using namespace std;static DepthGenerator depth_generator;static HandsGenerator hands_generator;static std:mapXnUserID, vector hands_track_points;class COpenNIpublic: COpenNI() context.Release();/释放空间 bool Initial() /初始化 status = context.Init(); if(CheckError(Context initial failed!) return false; context.SetGlobalMirror(true);/设置镜像 xmode.nXRes = 640; xmode.nYRes = 480; xmode.nFPS = 30; /产生颜色node status = image_generator.Create(context); if(CheckError(Create image generator error!) return false; /设置颜色图片输出模式 status = image_generator.SetMapOutputMode(xmode); if(CheckError(SetMapOutputMdoe error!) return false; /产生深度node status = depth_generator.Create(context); if(CheckError(Create depth generator error!) return false; /设置深度图片输出模式 status = depth_generator.SetMapOutputMode(xmode); if(CheckError(SetMapOutputMdoe error!) return false; /产生手势node status = gesture_generator.Create(context); if(CheckError(Create gesture generator error!) return false; /*添加手势识别的种类*/ gesture_generator.AddGesture(Wave, NULL); gesture_generator.AddGesture(click, NULL); gesture_generator.AddGesture(RaiseHand, NULL); gesture_generator.AddGesture(MovingHand, NULL); /产生手部的node status = hands_generator.Create(context); if(CheckError(Create hand generaotr error!) return false; /产生人体node status = user_generator.Create(context); if(CheckError(Create gesturen generator error!) return false; /视角校正 status = depth_generator.GetAlternativeViewPointCap().SetViewPoint(image_generator); if(CheckError(Cant set the alternative view point on depth generator!) return false; /设置与手势有关的回调函数 XnCallbackHandle gesture_cb; gesture_generator.RegisterGestureCallbacks(CBGestureRecognized, CBGestureProgress, NULL, gesture_cb); /设置于手部有关的回调函数 XnCallbackHandle hands_cb; hands_generator.RegisterHandCallbacks(HandCreate, HandUpdate, HandDestroy, NULL, hands_cb); /设置有人进入视野的回调函数 XnCallbackHandle new_user_handle; user_generator.RegisterUserCallbacks(CBNewUser, NULL, NULL, new_user_handle); user_generator.GetSkeletonCap().SetSkeletonProfile(XN_SKEL_PROFILE_ALL);/设定使用所有关节(共15个) /设置骨骼校正完成的回调函数 XnCallbackHandle calibration_complete; user_generator.GetSkeletonCap().RegisterToCalibrationComplete(CBCalibrationComplete, NULL, calibration_complete); return true; bool Start() status = context.StartGeneratingAll(); if(CheckError(Start generating error!) return false; return true; bool UpdateData() status = context.WaitNoneUpdateAll(); if(CheckError(Update date error!) return false; /获取数据 image_generator.GetMetaData(image_metadata); depth_generator.GetMetaData(depth_metadata); return true; /得到色彩图像的node ImageGenerator& getImageGenerator() return image_generator; /得到深度图像的node DepthGenerator& getDepthGenerator() return depth_generator; /得到人体的node UserGenerator& getUserGenerator() return user_generator; /得到手势姿势node GestureGenerator& getGestureGenerator() return gesture_generator; public: DepthMetaData depth_metadata; ImageMetaData image_metadata;/ static std:mapXnUserID, vector hands_track_points;private: /该函数返回真代表出现了错误,返回假代表正确 bool CheckError(const char* error) if(status != XN_STATUS_OK ) QMessageBox:critical(NULL, error, xnGetStatusString(status); cerr error : xnGetStatusString( status ) endl; return true; return false; /手势某个动作已经完成检测的回调函数 static void XN_CALLBACK_TYPE CBGestureRecognized(xn:GestureGenerator &generator, const XnChar *strGesture, const XnPoint3D *pIDPosition, const XnPoint3D *pEndPosition, void *pCookie) hands_generator.StartTracking(*pIDPosition); /手势开始检测的回调函数 static void XN_CALLBACK_TYPE CBGestureProgress(xn:GestureGenerator &generator, const XnChar *strGesture, const XnPoint3D *pPosition, XnFloat fProgress, void *pCookie) hands_generator.StartTracking(*pPosition); /手部开始建立的回调函数 static void XN_CALLBACK_TYPE HandCreate(HandsGenerator& rHands, XnUserID xUID, const XnPoint3D* pPosition, XnFloat fTime, void* pCookie) XnPoint3D project_pos; depth_generator.ConvertRealWorldToProjective(1, pPosition, &project_pos); pairXnUserID, vector hand_track_point(xUID, vector(); hand_track_point.second.push_back(project_pos); hands_track_points.insert(hand_track_point); /手部开始更新的回调函数 static void XN_CALLBACK_TYPE HandUpdate(HandsGenerator& rHands, XnUserID xUID, const XnPoint3D* pPosition, XnFloat fTime, void* pCookie) XnPoint3D project_pos; depth_generator.ConvertRealWorldToProjective(1, pPosition, &project_pos); hands_track_points.find(xUID)-second.push_back(project_pos); /销毁手部的回调函数 static void XN_CALLBACK_TYPE HandDestroy(HandsGenerator& rHands, XnUserID xUID, XnFloat fTime, void* pCookie) hands_track_points.erase(hands_track_points.find(xUID); /有人进入视野时的回调函数 static void XN_CALLBACK_TYPE CBNewUser(UserGenerator &generator, XnUserID user, void *p_cookie) /得到skeleton的capability,并调用RequestCalibration函数设置对新检测到的人进行骨骼校正 generator.GetSkeletonCap().RequestCalibration(user, true); /完成骨骼校正的回调函数 static void XN_CALLBACK_TYPE CBCalibrationComplete(SkeletonCapability &skeleton, XnUserID user, XnCalibrationStatus calibration_error, void *p_cookie) if(calibration_error = XN_CALIBRATION_STATUS_OK) skeleton.StartTracking(user);/骨骼校正完成后就开始进行人体跟踪了 else UserGenerator *p_user = (UserGenerator*)p_cookie; skeleton.RequestCalibration(user, true);/骨骼校正失败时重新设置对人体骨骼继续进行校正 private: XnStatus status; Context context; ImageGenerator image_generator; UserGenerator user_generator; GestureGenerator gesture_generator; XnMapOutputMode xmode;#endifckinectreader.cpp:#include #include #include #include copenni.cpp /要包含cpp文件,不能直接包含类#include #include #include using namespace std;class CKinectReader: public QObjectpublic: /构造函数,用构造函数中的变量给类的私有成员赋值 CKinectReader(COpenNI &openni, QGraphicsScene &scene) : openni(openni), scene(scene) test = 0.0; /设置画笔的颜色 pen_array0.setWidth(3); pen_array1.setColor(QColor:fromRgb( 255, 0, 0, 128 ); pen_array1.setWidth( 3 ); pen_array1.setColor( QColor:fromRgb( 0, 255, 0, 128 ) ); pen_array2.setWidth( 3 ); pen_array2.setColor( QColor:fromRgb( 0, 0, 255, 128 ) ); pen_array3.setWidth( 3 ); pen_array3.setColor( QColor:fromRgb( 255, 0, 255, 128 ) ); pen_array4.setWidth( 3 ); pen_array4.setColor( QColor:fromRgb( 255, 255, 0, 128 ) ); pen_array5.setWidth( 3 ); pen_array5.setColor( QColor:fromRgb( 0, 255, 255, 128 ) ); CKinectReader() scene.removeItem(image_item); scene.removeItem(depth_item); delete p_depth_argb; bool Start(int interval = 33) openni.Start();/因为在调用CKinectReader这个类的之前会初始化好的,所以这里直接调用Start了 image_item = scene.addPixmap(QPixmap(); image_item-setZValue(1); depth_item = scene.addPixmap(QPixmap(); depth_item-setZValue(2); openni.UpdateData(); p_depth_argb = new uchar4*openni.depth_metadata.XRes()*openni.depth_metadata.YRes(); startTimer(interval);/这里是继承QObject类,因此可以调用该函数 return true; float test ;private: COpenNI &openni; /定义引用同时没有初始化,因为在构造函数的时候用冒号来初始化 QGraphicsScene &scene; QGraphicsPixmapItem *image_item; QGraphicsPixmapItem *depth_item; uchar *p_depth_argb; array pen_array;private: void timerEvent(QTimerEvent *) openni.UpdateData(); /这里使用const,是因为右边的函数返回的值就是const类型的 const XnDepthPixel *p_depth_pixpel = openni.depth_metadata.Data(); unsigned int size = openni.depth_metadata.XRes()*openni.depth_metadata.YRes(); QImage draw_depth_image; /找深度最大值点 XnDepthPixel max_depth = *p_depth_pixpel; for(unsigned int i = 1; i max_depth ) max_depth = p_depth_pixpe
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 机械工程弹簧结构设计与应用练习题及答案
- 建筑安全知识竞赛题及答案全解析
- 科学探索智力挑战题及答案集
- 环境影响评价师考试模拟试题集与解析
- 机械设计实战形位公差应用测试题及答案收录
- 惠州安全生产法律法规考试试题
- 客户服务质量评估题及答案集合
- 化学科目实验题及答案详解手册
- 法律常识手册法律知识点测试题及答案
- 建筑电气照明设计自测题与答案详解指南
- 电磁学试题与答案
- 2025至2030中国药物离子电渗仪行业产业运行态势及投资规划深度研究报告
- 团队经营管理课件
- 云浮市云城区污水管网建设工程 水土保持方案报告书
- 文化认同机制构建-洞察及研究
- 氧同位素示踪技术-洞察及研究
- 2025年创新创业管理专业考试题及答案
- 教师十五五期间工作计划
- JG/T 235-2014建筑反射隔热涂料
- T/CCAS 010-2019水泥窑协同处置飞灰预处理产品水洗氯化物
- 领带订做合同协议
评论
0/150
提交评论