Kinect+OpenNI学习笔记之9不需要骨骼跟踪的人体手部分割.docx

上传人:b****5 文档编号:6787861 上传时间:2023-01-10 格式:DOCX 页数:16 大小:90.98KB
下载 相关 举报
Kinect+OpenNI学习笔记之9不需要骨骼跟踪的人体手部分割.docx_第1页
第1页 / 共16页
Kinect+OpenNI学习笔记之9不需要骨骼跟踪的人体手部分割.docx_第2页
第2页 / 共16页
Kinect+OpenNI学习笔记之9不需要骨骼跟踪的人体手部分割.docx_第3页
第3页 / 共16页
Kinect+OpenNI学习笔记之9不需要骨骼跟踪的人体手部分割.docx_第4页
第4页 / 共16页
Kinect+OpenNI学习笔记之9不需要骨骼跟踪的人体手部分割.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

Kinect+OpenNI学习笔记之9不需要骨骼跟踪的人体手部分割.docx

《Kinect+OpenNI学习笔记之9不需要骨骼跟踪的人体手部分割.docx》由会员分享,可在线阅读,更多相关《Kinect+OpenNI学习笔记之9不需要骨骼跟踪的人体手部分割.docx(16页珍藏版)》请在冰豆网上搜索。

Kinect+OpenNI学习笔记之9不需要骨骼跟踪的人体手部分割.docx

Kinect+OpenNI学习笔记之9不需要骨骼跟踪的人体手部分割

Kinect+OpenNI学习笔记之9(不需要骨骼跟踪的人体手部分割)

  

  前言

  手势识别非常重要的一个特点是要体验要好,即需要以用户为核心。

而手势的定位一般在手势识别过程的前面,在上一篇博文Kinect+OpenNI学习笔记之8(RobertWalter手部提取代码的分析) 中已经介绍过怎样获取手势区域,且取得了不错的效果,但是那个手势部位的提取有一个大的缺点,即需要人站立起来,当站立起来后才能够分隔出手。

而手势在人之间的交流时,并不一定要处于站立状态,所以这不是一个好的HCI。

因此本文介绍的手势部位的提取并不需要人处于站立状态,同样取得了不错的效果。

 

  实验说明

  其实,本实验实现的过程非常简单。

首先通过手部的跟踪来获取手所在的坐标,手部跟踪可以参考本人前面的博文:

Kinect+OpenNI学习笔记之7(OpenNI自带的类实现手部跟踪)。

当定位到手所在的坐标后,因为该坐标是3D的,因此在该坐标领域的3维空间领域内提取出手的部位即可,整个过程的大概流程图如下:

  

 

  OpenCV知识点总结:

  调用Mat:

:

copyTo()函数时,如果需要有mask操作,则不管源图像是多少通道的,其mask矩阵都要定义为单通道,另外可以对一个mask矩阵画一个填充的矩形来达到使mask矩阵中对应ROI的位置的值为设定值,这样就不需要去一一扫描赋值了。

  在使用OpenCV的Mat矩阵且需要对该矩阵进行扫描时,一定要注意其取值顺序,比如说列和行的顺序,如果弄反了,则经常会报内存错误。

 

 

  实验结果

  本实验并不要求人的手一定要放在人体的前面,且也不需要人一定是处在比较简单的背景环境中,本实验结果允许人处在复杂的背景环境下,且手可以到处随便移动。

当然了,环境差时有时候效果就不太好。

  下面是3张实验结果的截图,手势分隔图1:

  

 

  手势分隔图2:

  

 

  手势分隔图3:

  

 

  实验主要部分代码即注释(附录有工程code下载链接):

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;

inthand_depth;

Rectroi;

roi.x=XRES/2;

roi.y=YRES/2;

roi.width=ROI_HAND_WIDTH;

roi.height=ROI_HAND_HEIGHT;

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);

circle(color_image,Point(hand_point.X,hand_point.Y),5,Scalar(255,0,0),3,8);

imshow("colorimage",color_image);

 

/*获取并显示深度图像*/

Matdepth_image_src(openni.depth_metadata.YRes(),openni.depth_metadata.XRes(),

CV_16UC1,(char*)openni.depth_metadata.Data());//因为kinect获取到的深度图像实际上是无符号的16位数据

Matdepth_image;

depth_image_src.convertTo(depth_image,CV_8U,DEPTH_SCALE_FACTOR);

imshow("depthimage",depth_image);

/*下面的代码是提取手的轮廓部分*/

hand_depth=hand_point.Z*DEPTH_SCALE_FACTOR;

roi.x=hand_point.X-ROI_HAND_WIDTH/2;

roi.y=hand_point.Y-ROI_HAND_HEIGHT/2;

if(roi.x<=0)

roi.x=0;

if(roi.x>=XRES)

roi.x=XRES;

if(roi.y<=0)

roi.y=0;

if(roi.y>=YRES)

roi.y=YRES;

//取出手的mask部分

//不管原图像时多少通道的,mask矩阵声明为单通道就ok

Mathand_segment_mask(depth_image.size(),CV_8UC1,Scalar:

:

all(0));

for(inti=roi.x;i

:

min(roi.x+roi.width,XRES);i++)

for(intj=roi.y;j

:

min(roi.y+roi.height,YRES);j++){

hand_segment_mask.at(j,i)=((hand_depth-DEPTH_SEGMENT_THRESH)(j,i))

&((hand_depth+DEPTH_SEGMENT_THRESH)>depth_image.at(j,i));

}

medianBlur(hand_segment_mask,hand_segment_mask,MEDIAN_BLUR_K);

Mathand_segment(color_image.size(),CV_8UC3);

color_image.copyTo(hand_segment,hand_segment_mask);

imshow("hand_segment",hand_segment);

waitKey(20);

}

}

 

copenni,cpp:

#ifndefCOPENNI_CLASS

#defineCOPENNI_CLASS

#include

#include

#include

usingnamespacexn;

usingnamespacestd;

staticDepthGeneratordepth_generator;

staticHandsGeneratorhands_generator;

staticXnPoint3Dhand_point;

staticstd:

:

map>hands_track_points;

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,NULL,gesture_cb);

//设置于手部有关的回调函数

XnCallbackHandlehands_cb;

hands_generator.RegisterHandCallbacks(HandCreate,HandUpdate,HandDestroy,NULL,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;

//staticstd:

:

map>hands_track_points;

private:

//该函数返回真代表出现了错误,返回假代表正确

boolCheckError(constchar*error){

if(status!

=XN_STATUS_OK){

//QMessageBox:

:

critical(NULL,error,xnGetStatusString(status));

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);

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);

hands_generator.StartTracking(*pPosition);

}

//手部开始建立的回调函数

staticvoidXN_CALLBACK_TYPEHandCreate(HandsGenerator&rHands,XnUserIDxUID,constXnPoint3D*pPosition,

XnFloatfTime,void*pCookie){

//COpenNI*openni=(COpenNI*)pCookie;

XnPoint3Dproject_pos;

depth_generator.ConvertRealWorldToProjective(1,pPosition,&project_pos);

//openni->hand_point=project_pos;//返回手部所在点的位置

hand_point=project_pos;

pair>hand_track_point(xUID,vector());

hand_track_point.second.push_back(project_pos);

hands_track_points.insert(hand_track_point);

}

//手部开始更新的回调函数

staticvoidXN_CALLBACK_TYPEHandUpdate(HandsGenerator&rHands,XnUserIDxUID,constXnPoint3D*pPosition,XnFloatfTime,

void*pCookie){

//COpenNI*openni=(COpenNI*)pCookie;

XnPoint3Dproject_pos;

depth_generator.ConvertRealWorldToProjective(1,pPosition,&project_pos);

//openni->hand_point=project_pos;//返回手部所在点的位置

hand_point=project_pos;

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_point.clear();//返回手部所在点的位置

hands_track_points.erase(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;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 法律文书 > 调解书

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1