Kinect+OpenNI学习笔记之10不需要骨骼跟踪的人体多个手部分割.docx
- 文档编号:22810729
- 上传时间:2023-04-28
- 格式:DOCX
- 页数:18
- 大小:88.84KB
Kinect+OpenNI学习笔记之10不需要骨骼跟踪的人体多个手部分割.docx
《Kinect+OpenNI学习笔记之10不需要骨骼跟踪的人体多个手部分割.docx》由会员分享,可在线阅读,更多相关《Kinect+OpenNI学习笔记之10不需要骨骼跟踪的人体多个手部分割.docx(18页珍藏版)》请在冰豆网上搜索。
Kinect+OpenNI学习笔记之10不需要骨骼跟踪的人体多个手部分割
Kinect+OpenNI学习笔记之10(不需要骨骼跟踪的人体多个手部分割)
前言
这篇文章主要是介绍多个手部的分割,是在前面的博文:
不需要骨骼跟踪的人体手部分割 的基础上稍加改进的。
因为识别有的一个应用场合就是手势语言识别,而手势一般都需要人的2只手相配合完成,因此很有必要对人体的多个手部来进行分割。
实验说明
其实本文中使用的还是OpenNI自带的一些算法实现的,因为OpenNI中自己本身就对每个手部有一个UserID的标志,所以我们每当检测到一只手时就可以把手的位置连同他的ID一起存下来,后面进行手势分割时按照检测到的不同手势分别进行分割即可。
其程序流程图如下所示:
下面是本次实验特别需要注意的一些细节。
OpenNI知识点总结:
一般情况下OpenNI的回调函数中都会有一个参数pCookie,该参数就可以解决前面的博文Kinect+OpenNI学习笔记之7(OpenNI自带的类实现手部跟踪)
中提到的一个当时没有完美解决的问题:
即回调函数与类的静态函数,类的静态变量这3者之间使用相互矛盾的问题。
那个时候因为在回调函数中需要使用静态成员变量,所以类中普通的非静态成员变量是不能够使用的,否则程序会编译时会报错误。
但是如果我们把这些普通变量在类中定义成了静态变量后,这些静态变量就属于类本身了,并不属于类的对象。
因此该变量在类的其它成员函数中是不能够被使用的。
这样就产生了矛盾,当时的解决方法是将这些变量不放在类中,而放在类外称为整个工程的全局变量。
虽然理论上可以解决问题,不过一个跟类有关的变量竟然不能够放在类的内部,听起来就像是个大笑话!
这样的封装明显不合理。
幸运的是,现在因为回调函数传进来时有了pCookie这个变量,这样我们在回调函数中可以间接使用类的非静态成员变量了,使用这些变量既不需要定义为static类型,且也可以在类的成员函数中来进行初始化。
具体方法是将某个节点(比如说手部,人体,姿势等节点)的注册函数RegisterGestureCallbacks()中第3个参数设置为this指针,而不是null指针。
同时在具体的回调函数中,首先把pCookie指针强制转换成COpenNI这个类的指针,然后用转换过来的指针调用需要用到的类的成员变量。
C/C++知识点总结:
pair和map的区别:
map是一个容器,容器中的第一个元素表示的是键值key,其它元素分别表示以后用该容器存储数据时的数据类型。
因此map中的每一条记录的key值是不能重复的。
当map定义的时候只有2个集合的时候,里面的每一条记录可以用pair来存储。
因此可以简单的理解一个pair对应的是一条具体的记录,而一个map是一个存放pair的容器,并且map声明了容器的属性。
当在进行pair数据类型的定义时,如果其元素中的一个已经确定,另一个还不知道,则在定义的同时可以直接传入确定的那个元素,另一个用它的数据类型后面接一个空括号即可。
在使用vector时,必须是已存在的元素才能用下标操作符进行索引。
可以使用at和[]获取指定位置的数据或者给指定位置的数据赋值。
Qt知识点总结:
在QtCreator的使用中,有时候会出现两个尖括号在一起的情况,这时候没有语法错误,但是QtCreator这个编辑环境会在你的代码下出现个红色的波纹,让人看起来非常不舒服。
例如:
解决方法非常简单,即把两个尖括号中间不要紧挨着,用一个空格号隔开一下即可,这时候红色的波纹警告线就消失了。
实验结果
本工程可以对多个手部进行分割,分割效果取决于OpenNI中的手部跟踪效果。
其效果截图如下:
实验代码(附录有工程code下载链接)
copenni.cpp:
#ifndefCOPENNI_CLASS
#defineCOPENNI_CLASS
#include
#include
#include
usingnamespacexn;
usingnamespacestd;
classCOpenNI
{
public:
~COpenNI(){
context.Release();//释放空间
}
boolInitial(){
//初始化
status=context.Init();
if(CheckError("Contextinitialfailed!
")){
returnfalse;
}
context.SetGlobalMirror(true);//设置镜像
xmode.nXRes=640;
xmode.nYRes=480;
xmode.nFPS=30;
//产生颜色node
status=image_generator.Create(context);
if(CheckError("Createimagegeneratorerror!
")){
returnfalse;
}
//设置颜色图片输出模式
status=image_generator.SetMapOutputMode(xmode);
if(CheckError("SetMapOutputMdoeerror!
")){
returnfalse;
}
//产生深度node
status=depth_generator.Create(context);
if(CheckError("Createdepthgeneratorerror!
")){
returnfalse;
}
//设置深度图片输出模式
status=depth_generator.SetMapOutputMode(xmode);
if(CheckError("SetMapOutputMdoeerror!
")){
returnfalse;
}
//产生手势node
status=gesture_generator.Create(context);
if(CheckError("Creategesturegeneratorerror!
")){
returnfalse;
}
/*添加手势识别的种类*/
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("Createhandgeneraotrerror!
")){
returnfalse;
}
//产生人体node
status=user_generator.Create(context);
if(CheckError("Creategesturengeneratorerror!
")){
returnfalse;
}
//视角校正
status=depth_generator.GetAlternativeViewPointCap().SetViewPoint(image_generator);
if(CheckError("Can'tsetthealternativeviewpointondepthgenerator!
")){
returnfalse;
}
//设置与手势有关的回调函数
XnCallbackHandlegesture_cb;
gesture_generator.RegisterGestureCallbacks(CBGestureRecognized,CBGestureProgress,this,gesture_cb);
//设置于手部有关的回调函数
XnCallbackHandlehands_cb;
hands_generator.RegisterHandCallbacks(HandCreate,HandUpdate,HandDestroy,this,hands_cb);
//设置有人进入视野的回调函数
XnCallbackHandlenew_user_handle;
user_generator.RegisterUserCallbacks(CBNewUser,NULL,NULL,new_user_handle);
user_generator.GetSkeletonCap().SetSkeletonProfile(XN_SKEL_PROFILE_ALL);//设定使用所有关节(共15个)
//设置骨骼校正完成的回调函数
XnCallbackHandlecalibration_complete;
user_generator.GetSkeletonCap().RegisterToCalibrationComplete(CBCalibrationComplete,NULL,calibration_complete);
returntrue;
}
boolStart(){
status=context.StartGeneratingAll();
if(CheckError("Startgeneratingerror!
")){
returnfalse;
}
returntrue;
}
boolUpdateData(){
status=context.WaitNoneUpdateAll();
if(CheckError("Updatedateerror!
")){
returnfalse;
}
//获取数据
image_generator.GetMetaData(image_metadata);
depth_generator.GetMetaData(depth_metadata);
returntrue;
}
//得到色彩图像的node
ImageGenerator&getImageGenerator(){
returnimage_generator;
}
//得到深度图像的node
DepthGenerator&getDepthGenerator(){
returndepth_generator;
}
//得到人体的node
UserGenerator&getUserGenerator(){
returnuser_generator;
}
//得到手势姿势node
GestureGenerator&getGestureGenerator(){
returngesture_generator;
}
public:
DepthMetaDatadepth_metadata;
ImageMetaDataimage_metadata;
DepthGeneratordepth_generator;
HandsGeneratorhands_generator;
std:
:
map
map
private:
//该函数返回真代表出现了错误,返回假代表正确
boolCheckError(constchar*error){
if(status!
=XN_STATUS_OK){
cerr< "< returntrue; } returnfalse; } //手势某个动作已经完成检测的回调函数 staticvoidXN_CALLBACK_TYPECBGestureRecognized(xn: : GestureGenerator&generator,constXnChar*strGesture,constXnPoint3D*pIDPosition, constXnPoint3D*pEndPosition,void*pCookie){ COpenNI*openni=(COpenNI*)pCookie; openni->hands_generator.StartTracking(*pIDPosition); } //手势开始检测的回调函数 staticvoidXN_CALLBACK_TYPECBGestureProgress(xn: : GestureGenerator&generator,constXnChar*strGesture,constXnPoint3D*pPosition, XnFloatfProgress,void*pCookie){ COpenNI*openni=(COpenNI*)pCookie; openni->hands_generator.StartTracking(*pPosition); } //手部开始建立的回调函数 staticvoidXN_CALLBACK_TYPEHandCreate(HandsGenerator&rHands,XnUserIDxUID,constXnPoint3D*pPosition, XnFloatfTime,void*pCookie){ COpenNI*openni=(COpenNI*)pCookie; XnPoint3Dproject_pos; openni->depth_generator.ConvertRealWorldToProjective(1,pPosition,&project_pos); pair hand_point_pair.second=project_pos; openni->hand_points.insert(hand_point_pair);//将检测到的手部存入map类型的hand_points中。 pair hand_track_point.second.push_back(project_pos); openni->hands_track_points.insert(hand_track_point); } //手部开始更新的回调函数 staticvoidXN_CALLBACK_TYPEHandUpdate(HandsGenerator&rHands,XnUserIDxUID,constXnPoint3D*pPosition,XnFloatfTime, void*pCookie){ COpenNI*openni=(COpenNI*)pCookie; XnPoint3Dproject_pos; openni->depth_generator.ConvertRealWorldToProjective(1,pPosition,&project_pos); openni->hand_points.find(xUID)->second=project_pos; openni->hands_track_points.find(xUID)->second.push_back(project_pos); } //销毁手部的回调函数 staticvoidXN_CALLBACK_TYPEHandDestroy(HandsGenerator&rHands,XnUserIDxUID,XnFloatfTime, void*pCookie){ COpenNI*openni=(COpenNI*)pCookie; openni->hand_points.erase(openni->hand_points.find(xUID)); openni->hands_track_points.erase(openni->hands_track_points.find(xUID)); } //有人进入视野时的回调函数 staticvoidXN_CALLBACK_TYPECBNewUser(UserGenerator&generator,XnUserIDuser,void*p_cookie){ //得到skeleton的capability,并调用RequestCalibration函数设置对新检测到的人进行骨骼校正 generator.GetSkeletonCap().RequestCalibration(user,true); } //完成骨骼校正的回调函数 staticvoidXN_CALLBACK_TYPECBCalibrationComplete(SkeletonCapability&skeleton, XnUserIDuser,XnCalibrationStatuscalibration_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: XnStatusstatus; Contextcontext; ImageGeneratorimage_generator; UserGeneratoruser_generator; GestureGeneratorgesture_generator; XnMapOutputModexmode; }; #endif main.cpp: #include #include"opencv2/highgui/highgui.hpp" #include"opencv2/imgproc/imgproc.hpp" #include #include"copenni.cpp" #include #defineDEPTH_SCALE_FACTOR255./4096. #defineROI_HAND_WIDTH140 #defineROI_HAND_HEIGHT140 #defineMEDIAN_BLUR_K5 intXRES=640; intYRES=480; #defineDEPTH_SEGMENT_THRESH5 usingnamespacecv; usingnamespacexn; usingnamespacestd; intmain(intargc,char**argv) { COpenNIopenni; vector { color_array.push_back(Scalar(255,0,0)); color_array.push_back(Scalar(0,255,0)); color_array.push_back(Scalar(0,0,255)); color_array.push_back(Scalar(255,0,255)); color_array.push_back(Scalar(255,255,0)); color_array.push_back(Scalar(0,255,255)); color_array.push_back(Scalar(128,255,0)); color_array.push_back(Scalar(0,128,255)); color_array.push_back(Scalar(255,0,128)); color_array.push_back(Scalar(255,128,255)); } vector vector if(! openni.Initial()) return1; namedWindow("colorimage",CV_WINDOW_AUTOSIZE); namedWindow("depthimage",CV_WINDOW_AUTOSIZE); namedWindow("hand_segment",CV_WINDOW_AUTOSIZE);//显示分割出来的手的区域 if(! openni.Start()) return1; while (1){ if(! openni.UpdateData()){ return1; } /*获取并显示色彩图像*/ Matcolor_image_src(openni.image_metadata.YRes(),openni.image_metadata.XRes(), CV_8UC3,(char*)openni.image_metadata.Data()); Matcolor_image; cvtColor(color_image_src,color_image,CV_RGB2BGR); for(autoitUser=openni.hand_points.cbegin();itUser! =openni.hand_points.cend();++itUser){ circle(co
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Kinect OpenNI 学习 笔记 10 不需要 骨骼 跟踪 人体 多个手 部分
![提示](https://static.bdocx.com/images/bang_tan.gif)