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里公开。
 
 
图1 Kinect SDK v2预览版的数据取得流程(重发)

「Sensor」
取得「Sensor」
// Sensor
IKinectSensor* pSensor; ……
HRESULT hResult = S_OK;
hResult = GetDefaultKinectSensor( &pSensor ); ……
if( FAILED( hResult ) ){
std::cerr << "Error : GetDefaultKinectSensor" << std::endl;
return -;
}
hResult = pSensor->Open(); ……
if( FAILED( hResult ) ){
std::cerr << "Error : IKinectSensor::Open()" << std::endl;
return -;
}
列表1.1 相当于图1「Source」的部分
1 Kinect v2预览版的Sensor接口。
2 取得默认的Sensor。
3 打开Sensor。
 
「Source」
从「Sensor」取得「Source」。
// Source
IBodyFrameSource* pBodySource; ……
hResult = pSensor->get_BodyFrameSource( &pBodySource ); ……
if( FAILED( hResult ) ){
std::cerr << "Error : IKinectSensor::get_BodyFrameSource()" << std::endl;
return -;
}
列表1.2 相当于图1「Source」的部分
1 Body Frame的Source接口。
2 从Sensor取得Source。
 
  这里只是关于取得Body的源代码解说,不过,为了案例程序的显示,也同时取得了Color。
「Reader」
「Source」从打开「Reader」。
// Reader
IBodyFrameReader* pBodyReader; ……
hResult = pBodySource->OpenReader( &pBodyReader ); ……
if( FAILED( hResult ) ){
std::cerr << "Error : IBodyFrameSource::OpenReader()" << std::endl;
return -;
}
列表1.3 相当于图1「Reader」的部分
1 Body  Frame的Reader接口。
2 从Source打开Reader。
 
「Frame」~「Data」
从「Reader」取得最新的「Frame」(列表1.5)。
 
在这之前,为了可以和从传感器取得的坐标匹配,取得ICoordinateMapper的接口(列表1.4),由于Color照相机和Depth传感器的位置是分开的,因此需要把body数据和Color图像的位置进行匹配。
// Coordinate Mapper
ICoordinateMapper* pCoordinateMapper; ……
hResult = pSensor->get_CoordinateMapper( &pCoordinateMapper ); ……
if( FAILED( hResult ) ){
std::cerr << "Error : IKinectSensor::get_CoordinateMapper()" << std::endl;
return -;
}
列表1.4,坐标匹配接口的取得
1 Frame之间的坐标匹配的接口。
2 从Sensor获取坐标匹配的接口。
接下来的列表1.5,是和连载第2节一样的方法,表示的是Color图形的取得。
int width = ;
int height = ;
unsigned int bufferSize = width * height * * sizeof( unsigned char );
cv::Mat bufferMat( height, width, CV_8UC4 );
cv::Mat bodyMat( height / , width / , CV_8UC4 );
cv::namedWindow( "Body" );
// Color Table
cv::Vec3b color[];
color[] = cv::Vec3b( , , );
color[] = cv::Vec3b( , , );
color[] = cv::Vec3b( , , );
color[] = cv::Vec3b( , , );
color[] = cv::Vec3b( , , );
color[] = cv::Vec3b( , , );
while( ){
// Color Frame ……1
IColorFrame* pColorFrame = nullptr;
hResult = pColorReader->AcquireLatestFrame( &pColorFrame );
if( SUCCEEDED( hResult ) ){
hResult = pColorFrame->CopyConvertedFrameDataToArray( bufferSize, reinterpret_cast<BYTE*>( bufferMat.data ), ColorImageFormat_Bgra );
if( SUCCEEDED( hResult ) ){
cv::resize( bufferMat, bodyMat, cv::Size(), 0.5, 0.5 );
}
}
SafeRelease( pColorFrame );
/* Body部分在列表1.6 */
// Show Window
cv::imshow( "Body", bodyMat );
if( cv::waitKey( ) == VK_ESCAPE ){
break;
}
}

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

1 为了显示Body数据取得Color图像,详细见第2节。
  
列表1.5中的Body部分的代码,在下面的列表1.6里显示。
// Body Frame
IBodyFrame* pBodyFrame = nullptr; ……
hResult = pBodyReader->AcquireLatestFrame( &pBodyFrame ); ……
if( SUCCEEDED( hResult ) ){
IBody* pBody[BODY_COUNT] = { }; ……
hResult = pBodyFrame->GetAndRefreshBodyData( BODY_COUNT, pBody ); ……
if( SUCCEEDED( hResult ) ){
for( int count = ; count < BODY_COUNT; count++ ){
BOOLEAN bTracked = false; ……
hResult = pBody[count]->get_IsTracked( &bTracked ); ……
if( SUCCEEDED( hResult ) && bTracked ){
Joint joint[JointType::JointType_Count]; ……
hResult = pBody[count]->GetJoints( JointType::JointType_Count, joint ); ……
if( SUCCEEDED( hResult ) ){
// Left Hand State
HandState leftHandState = HandState::HandState_Unknown; ……
hResult = pBody[count]->get_HandLeftState( &leftHandState ); ……
if( SUCCEEDED( hResult ) ){
ColorSpacePoint colorSpacePoint = { }; ……
hResult = pCoordinateMapper->MapCameraPointToColorSpace( joint[JointType::JointType_HandLeft].Position, &colorSpacePoint ); ……
if( SUCCEEDED( hResult ) ){
int x = static_cast<int>( colorSpacePoint.X );
int y = static_cast<int>( colorSpacePoint.Y );
if( ( x >= ) && ( x < width ) && ( y >= ) && ( y < height ) ){
if( leftHandState == HandState::HandState_Open ){ ……
cv::circle( bufferMat, cv::Point( x, y ), , cv::Scalar( , , ), , CV_AA );
}
else if( leftHandState == HandState::HandState_Closed ){ ……
cv::circle( bufferMat, cv::Point( x, y ), , cv::Scalar( , , ), , CV_AA );
}
else if( leftHandState == HandState::HandState_Lasso ){ ……
cv::circle( bufferMat, cv::Point( x, y ), , cv::Scalar( , , ), , CV_AA );
}
}
}
}
// Right Hand State
/* 和左手一样,获取右手Hand State绘制状态。 */
// Joint ……9
for( int type = ; type < JointType::JointType_Count; type++ ){
ColorSpacePoint colorSpacePoint = { };
pCoordinateMapper->MapCameraPointToColorSpace( joint[type].Position, &colorSpacePoint );
int x = static_cast< int >( colorSpacePoint.X );
int y = static_cast< int >( colorSpacePoint.Y );
if( ( x >= ) && ( x < width ) && ( y >= ) && ( y < height ) ){
cv::circle( bufferMat, cv::Point( x, y ), , static_cast<cv::Scalar>( color[count] ), -, CV_AA );
}
}
}
}
}
cv::resize( bufferMat, bodyMat, cv::Size(), 0.5, 0.5 );
}
}
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预览版有公开更新,本连载就会追加新的功能介绍。

【翻译】Kinect v2程序设计(C++) Body 篇的更多相关文章

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

    Kinect v2,Microphone Array可以用来对于水平面音源方向的推测(AudioBeam)和语音识别(Speech Recognition).这一节是介绍如何取得AudioBeam. ...

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

    通过Kinect SDK v2预览版,取得BodyIndex(人体区域)的方法和示例代码. 上一节,介绍了从Kinect v2预览版用Kinect SDK v2预览版获取Depth数据的方法.   这 ...

  3. 【翻译】Kinect v2程序设计(C++) Color篇

    Kinect SDK v2预览版,获取数据的基本流程的说明.以及取得Color图像的示例程序的介绍. 上一节,是关于当前型号Kinect for Windows(后面称作Kinect v1)和次世代型 ...

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

    Kinect SDK v2预览版,取得Depth数据的方法说明. 上一节,介绍了通过使用Kinect for Windows SDK v2预览版(以下简称为,Kinect SDK v2预览版)从Kin ...

  5. 【翻译】Kinect v1和Kinect v2的彻底比较

      本连载主要是比较Kinect for Windows的现行版(v1)和次世代型的开发者预览版(v2),以C++开发者为背景介绍进化的硬件和软件.本文主要是对传感的配置和运行条件进行彻底的比较.   ...

  6. 【计算机视觉】深度相机(五)--Kinect v2.0

    原文:http://blog.csdn.NET/qq1175421841/article/details/50412994 ----微软Build2012大会:Kinect for Windows P ...

  7. Kinect v2.0 for windows开发环境说明

    官方文档里是这些: Supported Operating Systems and Architectures The following operating systems and architec ...

  8. Kinect v2(Microsoft Kinect for Windows v2 )配置移动电源解决方案

    Kinect v2配置移动电源解决方案 Kinect v2如果用于移动机器人上(也可以是其他应用场景),为方便有效地展开后续工作,为其配置移动电源是十分必要的. 一.选择移动电源 Kinect v2原 ...

  9. Ubuntu_ROS中应用kinect v2笔记

    Ubuntu_ROS中应用kinect v2笔记 个人觉得最重要的资料如下: 1. Microsoft Kinect v2 Driver Released http://www.ros.org/new ...

随机推荐

  1. rds材资收集

    rds:简称云数据库(Relational Database Service) RDS目前支持的数据库类型有两种:mysql,sqlserver. 阿里云RDS数据库教程菜鸟如何玩转阿里云RDS?:h ...

  2. mysql-关于Unix时间戳(unix_timestamp)

    unix_timestamp时间戳是自 1970 年 1 月 1 日(00:00:00 GMT)以来的秒数.它也被称为 Unix 时间戳(Unix Timestamp). Unix时间戳(Unix t ...

  3. callsession新功能版

    可以getopt解析参数. 也实现了将参数用空格分隔,来传给进程. 注意string和LPSTR数据类型的转换方法: LPSTR(lpCmdLine.c_str()) #include <win ...

  4. 亿条数据在PHP中实现Mysql数据库分表100张

    当数据量猛增的时候,大家都会选择库表散列等等方式去优化数据读写速度.笔者做了一个简单的尝试,1亿条数据,分100张表.具体实现过程如下: 首先创建100张表: $i=0; while($i<=9 ...

  5. hdu 3507 斜率dp

    不好理解,先多做几个再看 此题是很基础的斜率DP的入门题. 题意很清楚,就是输出序列a[n],每连续输出的费用是连续输出的数字和的平方加上常数M 让我们求这个费用的最小值. 设dp[i]表示输出前i个 ...

  6. String.split使用竖线做为分隔符

    String.split使用竖线做为分隔符时会发现得到的数组不对,每个字符都被拆分成数组里的一个值: 解决办法:竖线需要转义才可以作为split的参数,String.split("\\|&q ...

  7. hadoop本地库无法加载

    (1)设置环境变量 export HADOOP_HOME=/your/own/hadoop/home  export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME ...

  8. SparkStreaming+Flume出现ERROR ReceiverTracker: Deregistered receiver for stream 0: Error starting receiver 0 - org.jboss.netty.channel.ChannelException

    文章发自http://www.cnblogs.com/hark0623/p/4204104.html ,转载请注明 我发现太多太多的坑要趟了… 向yarn提交sparkstreaming了,提交脚本如 ...

  9. WPF的Presenter(ContentPresenter)(转)

    这是2年前写了一篇文章 http://www.cnblogs.com/Clingingboy/archive/2008/07/03/wpfcustomcontrolpart-1.html 我们先来看M ...

  10. node基础 --全局

    全局对象: global:永远使用var 定义变量以避免引入全局变量; process:所有全局执行上下文的内容都在process对象中: 模块和包: 模块:一个Node.js 文件就是一个模块,这个 ...