Kinect v2程序设计(C++) Body 篇

Kinect SDK v2预览版的主要功能的使用介绍,基本上完成了。这次,是关于取得Body(人体姿势)方法的说明。

上一节,是使用Kinect SDK v2预览版从Kinect v2预览版取得BodyIndex(人体区域)的方法。

这一节,介绍从Kinect取得Body(人体姿势)的方法。

Body

到目前为止,Kinect能取得Depth(通过传感器的距离信息)和BodyIndex(人体区域)。并且,基于这些数据可以取得人体姿势。

Kinect的人体姿势,是向学习了基于庞大数量的姿势信息的识别器里,输入人体区域的信息来推定的(注:因为男女老少高矮胖瘦体形各不相同,所以必须基于神经网络的数据库才能准确识别人体)。详细还请参考Microsoft Research发表的论文。

这个论文在IEEE CVPR 2011(计算机视觉及模式认识领域的首位会议)发表,获奖Best Paper。

Microsoft Research“Real-Time Human Pose Recognition in Parts from a Single Depth Image”

背景技术说不定很复杂,不过开发者通过Kinect SDK可以简单地取得和使用人体姿势。

人体的姿势数据,可以得到头,手,脚等3维的位置,基于这些可以实现姿势的识别。

这个人体区域,在Kinect SDK v1被称为「Skeleton」,不过,在Kinect SDK v2预览版里更名为「Body」。

这一节,介绍取得Body的方法。

示例程序

使用Kinect SDK v2预览版取得Body和Color图像叠加显示为「●(圆点)」的示例程序展示。还有,基于Body数据,Hand State(手的状态)也做了显示。第2节有介绍取得数据的阶段摘录解说,这个示例程序的全部内容,在下面的github里公开。

https://github.com/UnaNancyOwen/Kinect2Sample

图1 Kinect SDK v2预览版的数据取得流程(重发)

「Sensor」

取得「Sensor」

  1. // Sensor
  2. IKinectSensor* pSensor; ……1
  3. HRESULT hResult = S_OK;
  4. hResult = GetDefaultKinectSensor( &pSensor ); ……2
  5. if( FAILED( hResult ) ){
  6. std::cerr << "Error : GetDefaultKinectSensor" << std::endl;
  7. return -1;
  8. }
  9. hResult = pSensor->Open(); ……3
  10. if( FAILED( hResult ) ){
  11. std::cerr << "Error : IKinectSensor::Open()" << std::endl;
  12. return -1;
  13. }

列表1.1 相当于图1「Source」的部分

1 Kinect v2预览版的Sensor接口。

2 取得默认的Sensor。

3 打开Sensor。

「Source」

从「Sensor」取得「Source」。

  1. // Source
  2. IBodyFrameSource* pBodySource; ……1
  3. hResult = pSensor->get_BodyFrameSource( &pBodySource ); ……2
  4. if( FAILED( hResult ) ){
  5. std::cerr << "Error : IKinectSensor::get_BodyFrameSource()" << std::endl;
  6. return -1;
  7. }

列表1.2 相当于图1「Source」的部分

1 Body Frame的Source接口。

2 从Sensor取得Source。

这里只是关于取得Body的源代码解说,不过,为了案例程序的显示,也同时取得了Color。

「Reader」

「Source」从打开「Reader」。

  1. // Reader
  2. IBodyFrameReader* pBodyReader; ……1
  3. hResult = pBodySource->OpenReader( &pBodyReader ); ……2
  4. if( FAILED( hResult ) ){
  5. std::cerr << "Error : IBodyFrameSource::OpenReader()" << std::endl;
  6. return -1;
  7. }

列表1.3 相当于图1「Reader」的部分

1 Body  Frame的Reader接口。

2 从Source打开Reader。

「Frame」~「Data」

从「Reader」取得最新的「Frame」(列表1.5)。

在这之前,为了可以和从传感器取得的坐标匹配,取得ICoordinateMapper的接口(列表1.4),由于Color照相机和Depth传感器的位置是分开的,因此需要把body数据和Color图像的位置进行匹配。

  1. // Coordinate Mapper
  2. ICoordinateMapper* pCoordinateMapper; ……1
  3. hResult = pSensor->get_CoordinateMapper( &pCoordinateMapper ); ……2
  4. if( FAILED( hResult ) ){
  5. std::cerr << "Error : IKinectSensor::get_CoordinateMapper()" << std::endl;
  6. return -1;
  7. }

列表1.4,坐标匹配接口的取得

1 Frame之间的坐标匹配的接口。

2 从Sensor获取坐标匹配的接口。

接下来的列表1.5,是和连载第2节一样的方法,表示的是Color图形的取得。

  1. int width = 1920;
  2. int height = 1080;
  3. unsigned int bufferSize = width * height * 4 * sizeof( unsigned char );
  4. cv::Mat bufferMat( height, width, CV_8UC4 );
  5. cv::Mat bodyMat( height / 2, width / 2, CV_8UC4 );
  6. cv::namedWindow( "Body" );
  7. // Color Table
  8. cv::Vec3b color[6];
  9. color[0] = cv::Vec3b( 255, 0, 0 );
  10. color[1] = cv::Vec3b( 0, 255, 0 );
  11. color[2] = cv::Vec3b( 0, 0, 255 );
  12. color[3] = cv::Vec3b( 255, 255, 0 );
  13. color[4] = cv::Vec3b( 255, 0, 255 );
  14. color[5] = cv::Vec3b( 0, 255, 255 );
  15. while( 1 ){
  16. // Color Frame ……1
  17. IColorFrame* pColorFrame = nullptr;
  18. hResult = pColorReader->AcquireLatestFrame( &pColorFrame );
  19. if( SUCCEEDED( hResult ) ){
  20. hResult = pColorFrame->CopyConvertedFrameDataToArray( bufferSize, reinterpret_cast<BYTE*>( bufferMat.data ), ColorImageFormat_Bgra );
  21. if( SUCCEEDED( hResult ) ){
  22. cv::resize( bufferMat, bodyMat, cv::Size(), 0.5, 0.5 );
  23. }
  24. }
  25. SafeRelease( pColorFrame );
  26. /* Body部分在列表1.6 */
  27. // Show Window
  28. cv::imshow( "Body", bodyMat );
  29. if( cv::waitKey( 10 ) == VK_ESCAPE ){
  30. break;
  31. }
  32. }

列表1.5,相当于图1「Frame」,「Data」的部分(第1部分)

1 为了显示Body数据取得Color图像,详细见第2节。

列表1.5中的Body部分的代码,在下面的列表1.6里显示。

  1. // Body Frame
  2. IBodyFrame* pBodyFrame = nullptr; ……1
  3. hResult = pBodyReader->AcquireLatestFrame( &pBodyFrame ); ……2
  4. if( SUCCEEDED( hResult ) ){
  5. IBody* pBody[BODY_COUNT] = { 0 }; ……3
  6. hResult = pBodyFrame->GetAndRefreshBodyData( BODY_COUNT, pBody ); ……3
  7. if( SUCCEEDED( hResult ) ){
  8. for( int count = 0; count < BODY_COUNT; count++ ){
  9. BOOLEAN bTracked = false; ……4
  10. hResult = pBody[count]->get_IsTracked( &bTracked ); ……4
  11. if( SUCCEEDED( hResult ) && bTracked ){
  12. Joint joint[JointType::JointType_Count]; ……5
  13. hResult = pBody[count]->GetJoints( JointType::JointType_Count, joint ); ……5
  14. if( SUCCEEDED( hResult ) ){
  15. // Left Hand State
  16. HandState leftHandState = HandState::HandState_Unknown; ……6
  17. hResult = pBody[count]->get_HandLeftState( &leftHandState ); ……6
  18. if( SUCCEEDED( hResult ) ){
  19. ColorSpacePoint colorSpacePoint = { 0 }; ……7
  20. hResult = pCoordinateMapper->MapCameraPointToColorSpace( joint[JointType::JointType_HandLeft].Position, &colorSpacePoint ); ……7
  21. if( SUCCEEDED( hResult ) ){
  22. int x = static_cast<int>( colorSpacePoint.X );
  23. int y = static_cast<int>( colorSpacePoint.Y );
  24. if( ( x >= 0 ) && ( x < width ) && ( y >= 0 ) && ( y < height ) ){
  25. if( leftHandState == HandState::HandState_Open ){ ……8
  26. cv::circle( bufferMat, cv::Point( x, y ), 75, cv::Scalar( 0, 128, 0 ), 5, CV_AA );
  27. }
  28. else if( leftHandState == HandState::HandState_Closed ){ ……8
  29. cv::circle( bufferMat, cv::Point( x, y ), 75, cv::Scalar( 0, 0, 128 ), 5, CV_AA );
  30. }
  31. else if( leftHandState == HandState::HandState_Lasso ){ ……8
  32. cv::circle( bufferMat, cv::Point( x, y ), 75, cv::Scalar( 128, 128, 0 ), 5, CV_AA );
  33. }
  34. }
  35. }
  36. }
  37. // Right Hand State
  38. /* 和左手一样,获取右手Hand State绘制状态。 */
  39. // Joint ……9
  40. for( int type = 0; type < JointType::JointType_Count; type++ ){
  41. ColorSpacePoint colorSpacePoint = { 0 };
  42. pCoordinateMapper->MapCameraPointToColorSpace( joint[type].Position, &colorSpacePoint );
  43. int x = static_cast< int >( colorSpacePoint.X );
  44. int y = static_cast< int >( colorSpacePoint.Y );
  45. if( ( x >= 0 ) && ( x < width ) && ( y >= 0 ) && ( y < height ) ){
  46. cv::circle( bufferMat, cv::Point( x, y ), 5, static_cast<cv::Scalar>( color[count] ), -1, CV_AA );
  47. }
  48. }
  49. }
  50. }
  51. }
  52. cv::resize( bufferMat, bodyMat, cv::Size(), 0.5, 0.5 );
  53. }
  54. }
  55. SafeRelease( pBodyFrame );

列表1.6,相当于图1「Frame」,「Data」的部分(第2部分)

1 Body的Frame接口。

2 从Reader里取得最新的Frame。

3 从Frame取得Body。

后面,是从人体取得数据。

4 确认能着追踪到人体。

5 取得人体Joint(关节)。

6 取得Hand State。

7 为了绘制,把Body座標向Color座標的坐标匹配。

匹配的坐标是否超出绘制范围(这里Color图像的尺寸是1920×1080)的检查。

(注:因为两个Camera位置、FOV和分辨率的不同,在匹配时不可能完全一一对应,所以必须检查坐标的有效性)

8 对应状态绘制相应颜色的○(圆型)做Hand State的可视化。

用各自对应Open(打开:布),Closed(关闭:拳),Lasso(套索:剪)的颜色绘制。如果检查不出状态就不绘制。

9 对应人体的Joint参照color table的颜色做绘制。

和Hand State一样,Body坐标向Color坐标坐标匹配来绘制●(圆点)。

使用Kinect SDK v1从人体区域中检测获取的详细人体姿势最多支持2个人。Kinect SDK v2预览版可以检测获取全部人体区域(6人)的详细人体姿势。

另外,Kinect SDK v1能取得的Joint是全身20个,Kinect SDK v2预览版是追加了「脖子(=NECK)」,「指尖(=HAND_TIP_LEFT,HAND_TIP_RIGHT)」,「大拇指(=THUMB_LEFT,THUMB_RIGHT)」5个,一共25个Joint。

示例程序里,根据Joint位置参考color table的颜色绘制成「●(圆点)」来可视化。

Kinect SDK v1(Kinect Developer Toolkit/Kinect Interaction)可以取得的Hand State,有「Open(打开)」和「Closed(关闭)」的2种类型。

Kinect SDK v2预览版,在「Open」「Closed」基础上又增加了「Lasso(=套索)」这个状态的取得。「Lasso」能检查出竖起两个手指的状态。想象为「猜拳的(拳头,剪刀,布)」就好了。这里还有一个链接扩展阅读,我之后会翻译。

现在,6个人中可以同时获取其中2个人的Hand State。

示例程序里,可以通过手的Joint位置的状态来着色「○(圆环)」的绘制做可视化。「Open」绿色(=「cv::Scalar(0,128,0)」),「Closed」是红色(=「cv::Scalar(0,0,128)」),「Lasso」用淡蓝色(=「cv::Scalar(128,128,0)」)表现。

Kinect SDK v1 Kinect SDK v2预览版
名称 Skeleton Body
人体姿勢可以取得的人数 2人 6人
Joint(关节) 20处 25处
Hand State(手的状態) 2種類 3種類
Hand State可以取得的人数 2人 2人

表1 Kinect SDK v1和Kinect SDK v2预览版的人体姿势(Skeleton,Body)的比较

图2 Kinect v1和Kinect v2预览版的可以取得的Joint

运行结果

运行这个示例程序,就像图3一样,从v2预览版取得的人体姿势和手的状态被可视化了。

图3 运行结果

Joint用●(圆点)来显示,Hand State用来○(圆环)来显示。

图4 Hand State的识别结果

「Open」是绿色,「Closed」是红色,「Lasso」浅蓝色的○(圆环)来显示。 手的状态可以清晰的识别。

总结

这一节是使用Kinect SDK v2预览版取得Body的示例程序的介绍。现在,Kinect SDK v2预览版实现的主要功能基本上都被介绍了。

不过,Kinect SDK v2预览版,在RTM版的发布之前预计会有2~3次的更新。近日,第1次更新被预定公开给早期提供程序的参与者。一旦SDK v2预览版有公开更新,本连载就会追加新的功能介绍。

时间: 2024-12-25 23:12:56

Kinect v2程序设计(C++) Body 篇的相关文章

【翻译】Kinect v2程序设计(C++-) AudioBeam篇

Kinect v2,Microphone Array可以用来对于水平面音源方向的推测(AudioBeam)和语音识别(Speech Recognition).这一节是介绍如何取得AudioBeam. 上一节,介绍如何使用通过Kinect SDK v2预览版,从Kinect v2预览版的Color Camera和Depth 传感器中获取数据的方法. 本节,将介绍从Kinect的Microphone Array中取得AudioBeam(水平面音源方向的推测)的方法. Microphone Array

Kinect V2程序设计(C++) Color篇

Kinect SDK v2预览版,获取数据的基本流程的说明.以及取得Color图像的示例程序的介绍. 上一节,是关于当前型号Kinect for Windows(后面称作Kinect v1)和次世代型的Kinect for Windows的开发者预览版(后面称作Kinect v2 预览版)的配置比较和介绍. 从这一节开始,是Kinect的各种数据的取得方法的比较和介绍. Color Camera Kinect和通常的Web摄像头一样,搭载了 Color Camera,可以取得Color图像.关于

【翻译】Kinect v2程序设计(C++) BodyIndex篇

通过Kinect SDK v2预览版,取得BodyIndex(人体区域)的方法和示例代码. 上一节,介绍了从Kinect v2预览版用Kinect SDK v2预览版获取Depth数据的方法. 这一节,介绍从Kinect取得BodyIndex(人体区域)的方法. BodyIndex 基于从Kinect取得的Depth数据(传感器的距离信息)获取人体区域. 因为人体区域基于Depth数据,同时也依赖Depth传感器的分辨率.像上一节介绍的一样,因为Kinect v2 预览版(512×424)的De

【翻译】Kinect v2程序设计(C++) Depth编

Kinect SDK v2预览版,取得Depth数据的方法说明. 上一节,介绍了通过使用Kinect for Windows SDK v2预览版(以下简称为,Kinect SDK v2预览版)从Kinect for Windows v2开发者预览版(后面称,Kinect v2 预览版)取得Color的方法. 这一节,介绍的是从Kinect取得Depth数据的方法. Depth传感器 Kinect搭载Depth传感器,可以取得Depth数据(和传感器的距离信息). Kinect v1,可以读取投射

Kinect v1和Kinect v2的彻底比较

本连载主要是比较Kinect for Windows的现行版(v1)和次世代型的开发者预览版(v2),以C++开发者为背景介绍进化的硬件和软件.本文主要是对传感的配置和运行条件进行彻底的比较. 本连载介绍的Kinect for Windows Developer Preview是暂定的,软件.硬件以及API有可能因为最终的产品版发生变更,还请谅解. 关于本连载 本连载主要是比较次世代型的Kinect for Windows(后面称作Kinect v2预览版)和现行型的Kinect for Win

标定Kinect v2彩色摄像头:使用iai_kinect2,采用qhd(960*540)大小的彩色图像

开篇一作,这篇博文是纯应用的,没有任何理论说明,就当是一个实践提醒啦. 安装kinect v2相机驱动和标定程序得益于下面二位前辈的引荐工作: http://www.cnblogs.com/gaoxiang12/p/5161223.html http://www.cnblogs.com/hitcm/p/5118196.html 十分感谢! 请读者先按照上面前辈的博文安装好libfreenect2和iai_kinect2. 在iai_kinect2标定步骤中(https://github.com/

Linux C 程序设计多线程基础篇

   Linux C 程序设计多线程基础篇 题记:因为 Linux 网络入侵检测系统的设计与实现希望使用多线程,因此希望系统的学习一下 Linux C程序设计多线程的知识 注意事项:因为 pthraed 库不是 Linux 系统默认的库,因此在进行多线程开发的时候,需要加上头文件#include <pthread.h>,编译时要加参数 -lpthread;了:gcc thread.c -o thread -lpthread. 进程和线程: 进程是程序执行,资源分配的基本单位,每个进程都拥有自己

ubuntu14.04下 Kinect V2+Ros接口安装

1. 首先git下载代码,放到主文件夹下面 git clone https://github.com/OpenKinect/libfreenect2.git 2. 然后安装依赖项如下,最好事先编译安装好OpenCV sudo apt-get install build-essential cmake pkg-config libturbojpeg libjpeg-turbo8-dev mesa-common-dev freeglut3-dev libxrandr-dev libxi-dev 3.

ubuntu连接kinect v2

经过这个过程才悟到,有的时候不是方法不对,也不是问题解决的不对,只是因为配置问题,如果配置不对,自然会出现各种各样问题,不如一开始就确定配置.不过,如果不是经历了这个过程,我也不知道是因为我的配置问题导致的问题,哎. 我用的是ubuntu14.04LTS,ROS 版本是indigo,kinect v2,我是用双系统装的ubuntu,用虚拟机装的ubuntu是不行的,会出现各种各样问题,因为虚拟机用的是它自带的驱动器,这显然是不行的. 下面正式进入安装 1.安装libfreenect2,这个lib