中文第一计算机图形学社区OpenGPU 版权所有2007-2018

 找回密码
 注册

扫一扫,访问微社区

搜索
查看: 14873|回复: 11

【翻译】面向C++程序员的 Kinect for Windows V2 Developer Preview

[复制链接]
发表于 2014-12-1 22:10:12 | 显示全部楼层 |阅读模式
本帖最后由 trace 于 2014-12-2 23:33 编辑

应马肝之托翻译的Kinect v2的相关资料连载,全7篇,翻到一半才发现内容实在太水了,不过还是拿来做启蒙阅读好了= =
全7篇已经发完,还有一篇相关的要等以后了,这周有几篇ppt要翻,所以要pdf的话应该要等周末了

翻译:Trace
校对:千里马肝



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
 楼主| 发表于 2014-12-1 22:11:19 | 显示全部楼层
本帖最后由 trace 于 2014-12-1 23:30 编辑

Kinect v1和Kinect v2的彻底比较

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

关于本连载

  本连载主要是比较次世代型的Kinect for Windows(后面称作Kinect v2预览版)和现行型的Kinect for Windows(后面称作Kinect v1)的同时,介绍面向c++开发者而进化的硬件和软件。(本网站也发布了对应C#/Visual Basic开发者的内容,.NET开发者可以同时参考[新型Kinect for Windows v2 Developer Preview programing入门])

次世代型的Kinect for Windows
  2012年美国微软发售的Kinect v1,因为可以很方便就能取得Depth(深度)和 skeleton(人物姿势)等信息,被全世界的开发者和研究人员关注。

  2014年预定发售的Kinect v2,预测在硬件和软件上会做很大的进化,在销售前,开发者向的预览版的Kinect v2(传感器)和SDK v2(软件开发套件)很早就发布了出来。

  还有,因为这个开发者向的早期提供程序是必须签订NDA(密码保持契约),本稿有不能公布的事项也事先请各位谅解。

Kinect v1和Kinect v2预览版的外观比较

  Kinect v1(图1)和Kinect v2 预览版(图2)的外观的照片。


图1 Kinect for Windows v1(现行型)

  Kinect v1的Depth传感器,采用了「Light Coding」的方式,读取投射的红外线pattern,通过pattern的变形来取得Depth的信息。为此,Depth传感器分为投射红外线pattern的IR Projector(左)和读取的这个的IR Camera(右)。还有Depth传感器中间还搭载了Color Camera。

  Light Coding是以色列的PrimeSense公司的Depth传感器技术,于2013年被美国苹果公司收购。


图2 Kinect for Windows v2(次世代型)预览版

  Kinect V2预览版的Depth传感器,采用的是「Time of Flight(TOF)」的方式,通过从投射的红外线反射后返回的时间来取得Depth信息。Depth传感器看不到外观,不过Color Camera旁边是红外线Camera(左)和投射脉冲变调红外线的Porjector(右)。
   
  微软过去收购过使用TOF方式处理Depth传感器技术的公司(注:应该是指的3DV),已经在使用这个技术,不过没有详细的公布。

Kinect v1和Kinect v2预览版的配置比较

Kinect v1和Kinect v2预览版的传感器的配置比较在表1显示。

Kinect v1
Kinect v2预览版            
颜色(Color)
分辨率(Resolution)
640×480
1920×1080
fps
30fps
30fps
深度(Depth)
分辨率(Resolution)
320×240
512×424
fps
30fps
30fps
人物数量(Player)
6人
6人
人物姿势(Skeleton)
2人
6人
関節(Joint)
20関節/人
25関節/人
手的開閉状態(Hand State)
△(Developer Toolkit)
○(SDK)
检测範囲(Range of Detection)
0.8~4.0m
0.5~4.5m
角度(Angle)(Depth)
水平(Horizontal)
57度
70度
垂直(Vertical)
43度
60度
(Tilt Motor)
×(手動)
複数的App
×(単一的App)
表1是Kinect v1和Kinect v2预览版的传感器的配置比较

Kinect v1的Color Camera的分辨率是640x480较低,不能取得非常漂亮的图像,Kinect v2预览版的分辨率大幅提高,能取得1920×1080非常漂亮的图像(图3)。
(注:v1的要求是USB2.0理论传输速率是60MB/s,v2是USB3.0理论传输速率是500MB/s。可以计算一下,以XRGB Color为例,30fps,那么每秒所需传输的数据大小为640 x 480 x 4 x 30约为35M;再加上USHORT格式的Depth Color,30fps,大小为320 x 240 x 2 x 30约为4M。总计约为40MB/s,因为带宽有限,所以在保证画面帧率稳定的情况下,分辨率只能如此,而且基本上必须独占一个USB Controller。再算算v2的情况,Color = 1920 x 1080 x 4 x 30 约为237M,Depth = 512 x 424 x 2 x 30约为12M,总计约为250M/s。所以非USB3.0不可,否则传输不了这么大的数据量。显而易见,Color Map是最占带宽的,其实可以通过一些其他格式,比如I420或MJPG来减少数据量,然后通过CPU或GPU来进行解压和回放。)


图3 Kinect v1和Kinect v2预览版的Color

  Kinect v2预览版的Depth传感器的分辨率也提高到512×424,而Kinect v1是可以取640×480分辨率的Depth数据,乍一看规格好像下降了,其实Kinect v1的Depth传感器的物理分辨率是320x240,Up Sacling到640x480而已(注:猜测是Runtime处理的)。另外,Depth传感器的方式也是从Light Coding变更为Time of Flight(TOF)。
  
  不能详细叙述,不过Kinect V2预览版Depth数据的精度也提高了(图4),关于精度还敬请等待产品版。



图4 Kinect v1和Kinect v2预览版的Depth

   Kinect v1,v2预览版可以取得Player(可识别的人体)数量都是6人。Kinect v2预览版因为Depth传感器的分辨率提高了,用Player数据只需要简单的剪切就可以很漂亮得把背景和人物分离。
  
   Kinect v1可以取得全部关节(Joint)的skeleton的数量是2人,随着Depth传感器的分辨率上升和视角的宽广,Kinect v2预览版变得能取得6人。

    还有,Kinect v1能取得的Joint是20个Joint每人,Kinect v2预览版变为能取得25个Joint。具体的如图5所示,头(Neck),指尖(HAND_TIP_LEFT,HAND_TIP_RIGHT),大拇指(THUMB_LEFT,THUMB_RIGHT),增加了这5个Joint。不仅仅是手的位置,大拇指和指尖的细小信息也可以获取到。

   Hand State(手的开闭状态)的识别,Kinect v1是靠Developer Toolkit里的「Kinect Interaction」库来支持,不过在Kinect V2预览版SDK里是标准支持。
   


Kinect v1和Kinect v2预览版可以取得的Joint
  
  Kinect v1为了摇头装载了倾斜电机(Tilt motor),也有视角扩展,Kinect v2预览版没有搭载Tilt motor,靠手动来摇头。

  Kinect v1不能多个应用程序同时连接到一个传感器。Kinect v2预览版通过「Kinect Service」,可以让多个应用程序同时从传感器取得数据(参考图6)

  现在,Kinect Service作为常驻程序被提供, 一般认为产品版里会成为Windows的服务(Service)。


图6 通过Kinect Service,对应多个应用程序

  Kinect v1和Kinect v2 预览版的运行环境的比较表(表2)。

Kinect v1
Kinect v2预览版
OS
Windows 7以后
Windows 8以后
编译器(Compiler)
Visual Studio 2010以后
Visual Studio 2012以后
接続端子(Connector)
USB 2.0
USB 3.0
CPU
Dual-Core 2.66GHz
Dual-Core 2.66GHz
GPU
DirectX 9.0c
DirectX 11.0
RAM
2.0GBytes
2.0 GBytes
表2 Kinect v1和Kinect v2预览版的最小运行环境比較

  Kinect v1要在Windows 7以后的版本上运行,Kinect v2要求是在Windows 8 运行。关于Visual Studio也要求是2012以后的版本。

  Kinect v1要求USB 2.0(或更快的USB)来运行,因为Kinect 2预览版传感器的分辨率也提高了,需要更快的USB 3.0来运行。Kinect v1和Kinect v2预览版的专有USB总线带宽都没有变化。

  Kinect v1和Kinect v2预览版都有与部分USB Host Controller不兼容而导致不能正常运行的情况,现在是Renesas和Intel的USB 3.0 Host Controller可以运行。台式PC也可以增加USB3.0扩展卡来对应。

  CPU方面,和Kinect v1一样,要求Dual Core 2.66 GHz以上。「时钟频率较低」一类的运行环境也稍微下降了,不是特别差的情况都可以运行,不过注意传感器分辨率提高,取得的数据的处理消耗也上升了。

  Kinect v1要求的是支持DirectX 9.0c的GPU(Kinect Fusion除外),Kinect v2预览版要求支持DirectX 11.0以后的GPU,像笔记本这种没有装载NVIDIA GeForce和AMD Radeon外置GPU(独立显卡)的很多无法运行,而像有Intel HD Graphics这种支持DirectX 11.0以后的处理器内置的GPU(集成显卡)是可以运行的。

   如上展示了Kinect v2预览版的必要运行环境,和前述一样在产品版中有变更的可能性,现在还不需要着急准备对应环境。关于USB Host Controller的兼容性今后也有解决的可能,希望起到参考的作用。

总结
  这次彻底的比较了Kinect v1和Kinect v2预览版的传感器配置和必要运行环境,下一回是关于使用Kinect SDK v2.0预览版的C++的程序设计方法在v1和v2预览版上的比较和介绍。



 楼主| 发表于 2014-12-1 22:12:32 | 显示全部楼层
本帖最后由 trace 于 2014-12-2 00:47 编辑

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图像。关于Camera,Kinect v1的分辨率是640×480,Kinect v2分辨率大幅提升到1920×1080。这次,要介绍从Color Camer取得图像的方法。

数据取得的流程
  Kinect SDK v1和Kinect SDK v2预览版取得数据的基本流程。

  这里表示的是最基础的流程,在Kinect SDK 在v2预览版里,有把多个「Source」「Reader」一齐处理的API,和这里介绍的数据获取的流程也会有差异。


图1是Kinect SDK v1和Kinect SDK v2预览版的数据取得流程

  Kinect SDK v1,是从「Sensor」打开「Stream」,从「Stream」取得「Frame」,从「Frame」取得数据这样的流程。

  到了Kinect SDK v2预览版,是从「Sensor」取得「Source」,从「Source」打开「Reader」,从「Reader」取得「Frame」,从「Frame」取得数据这样的流程。

  每个Kinect SDK v2预览版的「Source」,都有一个从Kinect取得Color和Depth的1个数据流,这点和Kinect SDK v1的「Stream」是一样的。

  Kinect SDK v2预览版,追加了「Reader」的阶段。「Reader」能打开1个「Source」多次。通过这个配置,多线程的应用上,不需要把取得的数据拷贝到其他线程处理。也有多个应用可以从同一个传感器取得数据的优点。
(注:因为Color Camera和Depth Camera是分离的,所以Color、Depth和Skeleton数据流也是各自独立的,API通过Event来通知App是否有数据更新。通常为了效率,对每一个数据流都使用单独的线程来等待Event,然后处理数据。在之前的v1中,Frame是独立的,取出后数据就被Drop掉了,所以想在Depth里读取Color之类的操作,必须使用内存拷贝,而多线程读写数据又会需要互斥锁,十分影响效率;还有一个办法是通过NuiSetFrameEndEvent,也就是c#接口中的AllFrameReady事件,但是这样等待所有数据不仅太局限而且效率很低。)

示例程序
  Kinect SDK v2预览版取得Color画像的示例程序的展示,图1展示的是数据取得阶段的摘录解说。这个示例程序的全部内容,在下面的github里公开了。
  • https://github.com/UnaNancyOwen/Kinect2Sample

这个示例程序为了处理图像数据,使用了OpenCV。OpenCV的详细内容可以参考下面的信息。
  • http://docs.opencv.org/

「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「Sensor」的部分
1 处理Kinect v2预览版的Sensor接口。
2 取得默认的Sensor。
3 打开Sensor。

「Source」
 从「Sensor」取得「Source」。
  1. // Source
  2. IColorFrameSource* pColorSource;  ……1
  3. hResult = pSensor->get_ColorFrameSource( &pColorSource );  ……2
  4. if( FAILED( hResult ) ){
  5.   std::cerr << "Error : IKinectSensor::get_ColorFrameSource()" << std::endl;
  6.   return -1;
  7. }
复制代码
列表1.2 相当于图1「Source」的部分
1 获取Color Frame的Source接口。
2 从Sensor取得Source。

「Reader」
「Source」从打开「Reader」
  1. // Reader
  2. IColorFrameReader* pColorReader;  ……1
  3. hResult = pColorSource->OpenReader( &pColorReader );  ……2
  4. if( FAILED( hResult ) ){
  5.   std::cerr << "Error : IColorFrameSource::OpenReader()" << std::endl;
  6.   return -1;
  7. }
复制代码
列表1.3 相当于图1「Reader」的部分
1 获取Color Frame的Reader接口。
2 从Source打开Reader。

「Frame」~「Data」
从「Reader」取得最新的「Frame」。
  1. int width = 1920;   ……1
  2. int height = 1080;  ……1
  3. unsigned int bufferSize = width * height * 4 * sizeof( unsigned char );  ……2
  4. cv::Mat bufferMat( height, width, CV_8UC4 );  ……3
  5. cv::Mat colorMat( height / 2, width / 2, CV_8UC4 );  ……3
  6. cv::namedWindow( "Color" );
  7. while( 1 ){
  8.   // Frame
  9.   IColorFrame* pColorFrame=nullptr;  ……4
  10.   hResult=pColorReader->AcquireLatestFrame( &pColorFrame );  ……5
  11.   if( SUCCEEDED( hResult ) ){
  12.     hResult = pColorFrame->CopyConvertedFrameDataToArray( bufferSize, reinterpret_cast<BYTE*>( bufferMat.data ), ColorImageFormat_Bgra );  ……6
  13.     if( SUCCEEDED( hResult ) ){
  14.       cv::resize( bufferMat, colorMat, cv::Size(), 0.5, 0.5 );   ……7
  15.     }
  16.   }
  17.   SafeRelease( pColorFrame );
  18.   // Show Window
  19.   cv::imshow( "Color", colorMat );
  20.   if( cv::waitKey( 30 ) == VK_ESCAPE ){
  21.     break;
  22.   }
  23. }
复制代码
列表1.4 相当于图1「Frame」,「Data」的部分
1 Color图像的尺寸(1920×1080)。
   这里为了简化说明,画像尺寸用硬编码来设定,示例程序可以从Source取得着Frame信息。
2 Color图像的数据尺寸。
3 为了处理Color图像,准备OpenCV的cv::Mat。
「bufferMat」是原始的图像数据,「colorMat」是Resize图像数据的处理。
「CV_8UC4」,是无符号8bit整数(8U),4个channel(C4)并列来表现1个像素的数据格式。
4 取得Color图像的Frame接口。
5 从Reader取得最新的Frame。
6 从Frame取得Color图像。
   默认的格式是YUY2(亮度与色差表现的格式),不过可以经过简单处理变换为BGRA。
7 缩小为长宽各一半的尺寸(960×540)。

  从「Frame」取得Color图像的数据时,Kinect SDK v1是预先指定图像尺寸和格式,Kinect SDK v2不能指定图像尺寸。因此,取得数据后可以按任意形状来整理。

  取出的Color图像直接显示的话尺寸太大(1920×1080),在这里采用了OpenCV的resize命令(cv::resize()),缩小为长宽各一半的尺寸(960×540)。(注:阅读理解时不要受这一段缩放代码的干扰,仅仅就是为了考虑在显示器上显示的方便观察,没别的意义。)

  取出的Color图像的数据如果指定的是BGRA格式,就会像图2一样的排列着。蓝(B),绿(G),红(R),和无效值(A)的共计32bit构成1像素。


图2 Color图像的数据排列

运行结果
运行这个示例程序的话,就会像图3那样,显示从Kinect v2预览版中取得的Color图像。


总结
本节介绍了从Kinect SDK v2预览版中取得数据的基本流程和取得Color图像的示例程序,下一节将介绍取得Depth数据的示例程序。

 楼主| 发表于 2014-12-1 22:14:15 | 显示全部楼层
本帖最后由 trace 于 2014-12-2 00:48 编辑

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,可以读取投射的红外线pattern,从pattern的变形获取Depth的信息,搭载了「Light Coding」方式的Depth传感器。

  Kinect v2预览版,通过从投射的红外线脉冲反射回来的时间来获得Depth的信息,变更为「Time of Flight(ToF)」方式的Depth传感器。

「Light Coding」是以色列PrimeSense公司的Depth传感技术。详细请参照专利信息,美国申请专利公开(US 2010/0118123 A1)- Depth Mapping using Projected Patterns。

「Time of Flight(ToF)」是美国微软公司收购的拥有Time of Flight(ToF)方式的Depth传感技术的公司(3DV Systems公司,Canesta公司),一般认为使用的是这个技术。

  Depth数据的分辨率,Kinect v1是320×240,不过,Kinect v2预览版提升为512×424。另外,深度方向的分辨率也提高了。

  可以取得Depth的数据范围,Kinect v1是0.8~4.0[m]的范围, Kinect v2预览版可以取得0.5~4.5[m]的范围。

  上面说的是Default Mode的Depth数据范围。Kinect v1提供了取得近距离的Depth数据的Near Mode(0.4~3.0[m])和取得远距离Depth数据的Extended Depth(~约10.0[m])。但是,偏离Default Mode的范围的Depth数据的精度会下降。

  这节,介绍从Depth传感器取得Depth数据的方法。


图1「Light Coding」方式和「Time of Flight(ToF)」方式的差异(Depth传感器的工作原理的图像)

示例程序

  Kinect SDK v2预览版取得Depth数据,可视化展示的示例程序。上一节的介绍的数据取得阶段的摘录解说。这个示例程序的全部内容,在下面的github里全部公开了。

  https://github.com/UnaNancyOwen/Kinect2Sample


图2 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「Sensor」的部分(重发)
1 处理Kinect v2预览版的Sensor接口。
2 取得默认的Sensor。
3 打开Sensor。

「Source」
从「Sensor」取得「Source」。
  1. // Source
  2. IDepthFrameSource* pDepthSource;  ……1
  3. hResult = pSensor->get_DepthFrameSource( &pDepthSource );  ……2
  4. if( FAILED( hResult ) ){
  5.   std::cerr << "Error : IKinectSensor::get_DepthFrameSource()" << std::endl;
  6.   return -1;
  7. }
复制代码
列表1.2 相当于图1「Source」的部分
1 取得Depth Frame的Source接口。
2 从Sensor取得Source。

  Kinect SDK v1,要取得Depth数据主要是利用可以同时取得的Depth和Player(人体区域)的「Stream」。因此,必须要有Depth数据和Player数据的分割处理。(注:Kinect SDK v1提供2种方式来处理Depth和Player Index,老的方法返回一组USHORT,通过位移分离两者;新的方法返回各为2个USHORT的结构)

  Kinect SDK v2预览版,Depth和BodyIndex(相当于Kinect SDK v1的Player)分别作为「Source」取得,关于BodyIndex在下一节介绍。

  Kinect SDK v1也准备了取得Depth的「Stream」,因为获取Player和Skeleton(人体姿势)数据的情况也很多,主要可以同时取得Depth和Player的「Stream」。

「Reader」
「Source」从打开「Reader」。
  1. // Reader
  2. IDepthFrameReader* pDepthReader;  ……1
  3. hResult = pDepthSource->OpenReader( &pDepthReader );  ……2
  4. if( FAILED( hResult ) ){
  5.   std::cerr << "Error : IDepthFrameSource::OpenReader()" << std::endl;
  6.   return -1;
  7. }
复制代码
列表1.3 相当于图1「Reader」的部分
1 取得Depth Frame的Reader接口。
2 从Source打开Reader。

「Frame」~「Data」
从「Reader」取得最新的「Frame」。

  1. int width = 512;  ……1
  2. int height = 424;  ……1
  3. unsigned int bufferSize = width * height * sizeof( unsigned short );  ……2
  4. cv::Mat bufferMat( height, width, CV_16SC1 );  ……3
  5. cv::Mat depthMat( height, width, CV_8UC1 );  ……3
  6. cv::namedWindow( "Depth" );
  7. while( 1 ){
  8.   // Frame
  9.   IDepthFrame* pDepthFrame = nullptr;  ……4
  10.   hResult = pDepthReader->AcquireLatestFrame( &pDepthFrame );  ……5
  11.   if( SUCCEEDED( hResult ) ){
  12.     hResult = pDepthFrame->AccessUnderlyingBuffer( &bufferSize, reinterpret_cast<UINT16**>( &bufferMat.data ) );  ……6
  13.     if( SUCCEEDED( hResult ) ){
  14.       bufferMat.convertTo( depthMat, CV_8U, -255.0f / 4500.0f, 255.0f );  ……7
  15.     }
  16.   }
  17.   SafeRelease( pDepthFrame );
  18.   // Show Window
  19.   cv::imshow( "Depth", depthMat );
  20.   if( cv::waitKey( 30 ) == VK_ESCAPE ){
  21.     break;
  22.   }
  23. }
复制代码
列表1.4 相当于图1「Frame」,「Data」的部分
1 Depth数据的尺寸(512×424)。
   这里为了简化说明,画像尺寸用硬代码来设定,示例程序可以Source取得着Frame信息。
2 Depth数据的尺寸。
3 为了处理Depth数据而准备的OpenCV的cv::Mat类型。
「bufferMat」是16bit的原始的Depth数据,「depthMat」为了作为图像显示,把Depth数据储存到8bit的范围里的处理。
「CV_16SC1」,是把无符号16bit整数(16S) 放入1个channel(C1)并列来表现1个像素的数据格式。(注:应该是CV_16UC1才对)
「CV_8UC1」,是表现无符号8bit整数  (8U)的数据格式。
4 取得Depth数据的Frame接口。
5 从Reader取得最新的Frame。
6 从Frame取得Depth数据。
   取得Depth数据存储数组的指针。这里为了Depth数据可视化,方便变化处理,用cv::Mat类型来获取。
7 为了显示Depth数据图像,从16bit转换为8bit。

  如果得到「Frame」,就可以把取出Depth数据,作成图像来可视化。

  取出的Depth数据,像图3一样以16bit(0~4500)为1像素来构成。

  因为这样的图像不能显示(注:OpenCV只能显示8bit的图像数据),需要把格式转化为8bit(0~255)的范围。示例程序,使用cv::Mat的转换命令(cv::Mat::convertTo())把离传感器距离近的显示很白(255),远的显示为很黑(0)的方式来转化。


图3 Depth数据的排列

运行结果
运行这个示例程序的话,在Kinect v2预览版取得深度图像,就像图4一样。


图4 运行结果

总结
本节介绍了通过Kinect SDK v2预览版取得Depth数据的示例程序。下一节介绍取得BodyIndex数据的示例程序。


 楼主| 发表于 2014-12-1 22:17:06 | 显示全部楼层
本帖最后由 trace 于 2014-12-2 00:39 编辑

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)的Depth传感器的分辨率大幅提高,和Kinect v1相比,手指等细小部分的人体区域也变得可以准确的取得。但是,能检测出的人体区域的数量还是6个人这一点没有发生改变。

  关于人体区域,在Kinect SDK v1里被称为「Player」,不过到了Kinect SDK v2 预览版里更名为「BodyIndex」。

  这一节,介绍取得「BodyIndex」的方法。


图1 Kinect SDK v2预览版的示例程序(BodyBasics)
把BodyIndex在Color坐标的位置匹配截取,手指等细小部分都可以清晰得在人体身上保留下来了。
(注:因为Color和Depth的Camera位置不同,所以需要进行坐标空间的转换)

样品程序
使用Kinect SDK v2预览版取得BodyIndex,把每个人体用颜色区分出来并显示的示例程序展示。第2节有介绍的取得数据的阶段摘录解说。这个示例程序的全部内容,在下面的github里公开。

https://github.com/UnaNancyOwen/Kinect2Sample


图2 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. IBodyIndexFrameSource* pBodyIndexSource;  ……1
  3. hResult = pSensor->get_BodyIndexFrameSource( &pBodyIndexSource );  ……2
  4. if( FAILED( hResult ) ){
  5.   std::cerr << "Error : IKinectSensor::get_BodyIndexFrameSource()" << std::endl;
  6.   return -1;
  7. }
复制代码
列表1.2 相当于图1「Source」的部分
1 取得BodyIndex Frame的Source接口。
2 从Sensor取得Source。

「Reader」
「Source」从打开「Reader」。
  1. // Reader
  2. IBodyIndexFrameReader* pBodyIndexReader;  ……1
  3. hResult = pBodyIndexSource->OpenReader( &pBodyIndexReader );  ……2
  4. if( FAILED( hResult ) ){
  5.   std::cerr << "Error : IBodyIndexFrameSource::OpenReader()" << std::endl;
  6.   return -1;
  7. }
复制代码
列表1.3 相当于图1「Reader」的部分
1 取得BodyIndex  Frame的Reader接口。
2 从Source打开Reader。

「Frame」~「Data」
从「Reader」取得最新的「Frame」。
  1. int width = 512;  ……1
  2. int height = 424;  ……1
  3. cv::Mat bodyIndexMat( height, width, CV_8UC3 );  ……2
  4. cv::namedWindow( "BodyIndex" );
  5. // Color Table
  6. cv::Vec3b color[6];  ……3
  7. color[0] = cv::Vec3b( 255,   0,   0 );
  8. color[1] = cv::Vec3b(   0, 255,   0 );
  9. color[2] = cv::Vec3b(   0,   0, 255 );
  10. color[3] = cv::Vec3b( 255, 255,   0 );
  11. color[4] = cv::Vec3b( 255,   0, 255 );
  12. color[5] = cv::Vec3b(   0, 255, 255 );
  13. while( 1 ){
  14.   // Frame
  15.   IBodyIndexFrame* pBodyIndexFrame = nullptr;  ……4
  16.   hResult = pBodyIndexReader->AcquireLatestFrame( &pBodyIndexFrame );  ……5
  17.   if( SUCCEEDED( hResult ) ){
  18.     unsigned int bufferSize = 0;
  19.     unsigned char* buffer = nullptr;
  20.     hResult = pBodyIndexFrame->AccessUnderlyingBuffer( &bufferSize, &buffer );  ……6
  21.     if( SUCCEEDED( hResult ) ){
  22.       for( int y = 0; y < height; y++ ){
  23.         for( int x = 0; x < width; x++ ){
  24.           unsigned int index = y * width + x;
  25.           if( buffer[index] != 0xff ){
  26.             bodyIndexMat.at<cv::Vec3b>( y, x ) = color[buffer[index]];  ……7
  27.           }
  28.           else{
  29.             bodyIndexMat.at<cv::Vec3b>( y, x ) = cv::Vec3b( 0, 0, 0 );  ……7
  30.           }
  31.         }
  32.       }
  33.     }
  34.   }
  35.   SafeRelease( pBodyIndexFrame );
  36.   // Show Window
  37.   cv::imshow( "BodyIndex", bodyIndexMat );
  38.   if( cv::waitKey( 30 ) == VK_ESCAPE ){
  39.     break;
  40.   }
  41. }
复制代码
列表1.4 相当于图1「Frame」,「Data」的部分
1 BodyIndex的尺寸(512×424)。
   这里为了简化说明,画像尺寸用硬代码来设定,示例程序可以Source取得着Frame信息。
2 为了从BodyIndex获得人体区域来绘制,使用OpenCV的cv::Mat。
3 绘制人体区域的color table。
4 取得BodyIndex用的Frame接口。
5 从Reader取得最新的Frame。
6 从Frame取得BodyIndex。
   取得保存BodyIndex数组的指针。
7 绘制BodyIndex的人体区域。
   每个BodyIndex参照color table着色。

如果可以从取得「Frame」的里获取BodyIndex的数据。

取出的BodyIndex的数据,像图3一样,把人体区域和非人体区域的按各自对应的值来填入。

Kinect SDK v1的「Player」是按人体区域是「1」~「6」(因为是6个人),非人体区域「0」来填入;Kinect SDK v2预览版的「BodyIndex」是按照人体区域「0」~「5」,非人体領域「255(0xff)」来填入(图1)。


图3 BodyIndex数据


Kinect SDK v1
Kinect SDK v2预览版
名称
Player
BodyIndex
检测支持人数
6人
6人
人体領域的値
1~6
0~5
非人体領域的値
0
255(0xff)
表1 Kinect SDK v1和Kinect SDK v2预览版的人体区域(Player,BodyIndex)的比较

示例程序是,把BodyIndex的值,在人体区域用color table的颜色(=「cv::Vec3b(B,G,R )」),在非人体区域用黑色(=「cv::Vec3b(0,0,0)」)进行着色来实现可视化。

运行结果
运行这个示例程序,就像图4一样,从v2预览版取得的人体区域被着色显示。

图4 运行结果
手指的细小形状可以清楚的分割取出。

总结
这一节是使用Kinect SDK v2预览版取得BodyIndex的示例程序的介绍,下一节是取得Body(人体姿势)的示例程序的介绍。

 楼主| 发表于 2014-12-1 22:20:25 | 显示全部楼层
本帖最后由 trace 于 2014-12-2 22:46 编辑

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;
复制代码
列表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. 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.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预览版有公开更新,本连载就会追加新的功能介绍。

 楼主| 发表于 2014-12-1 22:25:01 | 显示全部楼层
本帖最后由 trace 于 2014-12-2 23:06 编辑

Kinect Studio是?  三月 SDK Update的新机能
  Kinect应用软件开发支援工具「Kinect Studio」的功能和用法的说明。由于可以记录/再生数据,让开发和调试变得更加简单。

  Kinect SDK v2预览版的RTM版的预定在发布之前会有2~3次的更新,3月27日第1次的更新(March SDK Update),将提供给Developer Preview Program的参与者。

  这一节,是3月更新内容的介绍。

Kinect Studio

  所谓「Kinect Studio」,是Kinect应用面向开发者提供的开发支援工具。

  Kinect Studio,可以把「Color」和「Depth」这样的数据从Kinect取得并存储在文件中。可以通过保存的文件来播放,如果Kinect应用的源代码不做特殊变更的话,就可以接受从Kinect记录的数据来运行。

  通过这个「记录」「播放」的功能,Kinect应用的开发、调试都变得格外轻松。

  Kinect SDK v1也提供了「Kinect Studio」(后面称作,Kinect Studio v1),这次的更新是对Kinect SDK v2预览版提供的(后面称作Kinect Studio v2预览版)。

  这一节,主要介绍「Kinect Studio v2预览版」。

Kinect Studio v2预览版

  Kinect Studio v2预览版的记录、播放顺序的介绍。

  Kinect Studio v2预览版,作为开发中的工具,在使用方法上稍微有些复杂,承蒙谅解。

记录顺序
1 创建保存数据的文件夹。
  (例如∶「C:\clips」)。
2 启动Kinect Service(KinectService.exe)。
3 启动Cmd.exe,将current directory移动到安装Kinect Studio的文件夹中。
  (例如∶「cd  C:\Program Files\Microsoft SDKs\Kinectv2.0-DevPreview1403\Tools\KinectStudio"」)。
4 启动KStudioHostService,用参数指定保存数据的文件夹。
  (例如∶「KStudioHostService.exe /d C:\clips」)。
5 启动Kinect Studio v2预览版(KStudio.exe)。
6 点击[Connect]按钮(图1里,左上角的雷电标志),从绿色变成红色的话,与Kinect v2预览版的连接就完成了。
7 在[Live Control]Tab选择记录的数据。
8 [Record]按钮开始记录,用[Stop]按钮停止记录。停止记录的话,会在指定的文件夹中以xed形式的文件保存。


图1 Kinect Studio v2预览版

  把Kinect Studio v2预览版连接到Kinect v2预览版的话,实时取得的数据会在Kinect Studio v2预览版上显示。在[3D]tab上,Depth(深度)数据作为点云被显示。在[2D]tab上,显示的是Infrared(红外线)数据。

  其他的Body(人体姿势)和Hand State(手的状态)等的显示,可以利用建议的可视化工具。在下面的画面([Live Control]tab)中,可以一览能记录的数据。


图2 Kinect Studio v2预览版能记录的数据一览
[Record]标志是可以有效被记录的数据。

  记录的数据的一览部分,Kinect Studio v1不能记录·播放的Audio数据,而Kinect Studio v2预览版里可以记录·播放。(现在的SDK因为Audio功能未实现记录·播放所以不能确认)。

  能记录·播放Audio数据的话,利用Speech Recognition(语音识别)和Beamforming(水平面音源方向推算)实现的Kinect应用,对于利用人的语音进行开发的调试和试验等都非常有用。

  Kinect Studio v1不能记录·播放Audio数据。Kinect Studio v1在播放时,Kinect v1其实是实时地取得的Audio数据传输给Kinect应用。

  Kinect v1,不能多个应用同时连接传感器。因此Kinect Studio v1记录时,要连接Kinect应用(进程间通信)。

  就像连载第1次介绍的,Kinect v2预览版通过Kinect Service,可以让多个应用从同一个传感器取得数据(图3)。因此Kinect Studio v2预览版记录时不需要连接Kinect应用。


图3  通过Kinect Service与多个应用对应(重发)

播放顺序
1 启动Kinect Service(KinectService.exe)。
2 启动要加载再生数据的Kinect应用。
3 启动Cmd.exe,将current directory移动到安装Kinect Studio的文件夹
  (例如∶「cd  C:\Program Files\Microsoft SDKs\Kinectv2.0-DevPreview1403\Tools\KinectStudio"」)。
4 启动KStudioHostService,用参数指定保存数据的文件夹。
  (例如∶「KStudioHostService.exe /d C:\clips」)。
5 启动Kinect Studio v2预览版(KStudio.exe)。
6 点击[Connect]按钮(图1里,左上角的雷电标志),从绿色变成红色的话连接到Kinect v2预览版就完成了。
7 从菜单栏的[File]-[Open From Repository]选择再生文件(*.xed)。
8 在[File Control]tab选择再生的数据。
9 [Start]按钮,向Kinect应用传入数据。再生的数据,可以临时停止播放,还可以用slider调整播放的位置。


图4  把数据传入到Kinect应用

  Kinect Studio v2预览版由于支持数据再生,将输入到Kinect应用的数据实时取得并保存到文件,不改变源代码的前提下不需要再次Build。

  Kinect Studio v1,记录的数据传到应用再生时,必须要把Kinect v1和PC连接。

  Kinect Studio v2预览版,即使Kinect v2预览版没有连接到PC,记录的数据也可以传入应用来播放。

  根据这个,预先记录好数据,开发者就算没有连接传感器的环境,也可以进行开发和调试应用。例如,需要调试的地方没有传感器,或者没有传感器的供电环境,只要有安装好的开发环境PC,就可以进行开发和调试。

总结
  通过这次更新提供的Kinect Studio,Kinect应用的开发·调试变得轻松了,在正式版发布后应该会变得更加简便。

  下次的更新预定在4月。4月的更新(April SDK Update),预告的是实现Audio和Interaction功能。具体内容预定在微软的开发者向的会议「Build 2014」(以美国时间4月2~4日)中连续报告。

  一旦Kinect SDK v2预览版有公开更新,本连载就会追加新的功能介绍。


 楼主| 发表于 2014-12-1 22:35:38 | 显示全部楼层
本帖最后由 trace 于 2014-12-2 23:31 编辑

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除搭载了Color Camera,Depth传感器之外,还有Microphone Array。

  Microphone Array由4个Microphone构成,能进行水平面音源方向的推测(AudioBeam)和语音识别(Speech Recognition)等。

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


图1 Kinect v2预览版的Microphone Array


图2 Kinect SDK v2预览版的示例程序(AudioBasics)

示例程序

  用Kinect SDK v2取得AudioBeam,将结果显示在console上的示例程序。

  Audio的功能(AudioBeam,Speech Recognition)的数据取得流程,在「Sensor」~「Source」这一块与之前的Image(Color,Depth,BodyIndex,Body)的取得流程一样。不过在这之后还请注意Audio功能所特有的部分,这里主要是介绍与Image所同样的数据取得流程。

  这个示例程序的全部内容,在下面的github里全部公开了。

https://github.com/UnaNancyOwen/Kinect2Sample


图3 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「Sensor」的部分(重发)
1 处理Kinect v2预览版的Sensor接口。
2 取得默认的Sensor。
3 打开Sensor。

「Source」
从「Sensor」取得「Source」。
  1. // Source
  2. IAudioSource* pAudioSource;  //……1
  3. hResult = pSensor->get_AudioSource( &pAudioSource );  //……2
  4. if( FAILED( hResult ) ){
  5.   std::cerr << "Error : IKinectSensor::get_AudioSource()" << std::endl;
  6.   return -1;
  7. }
复制代码
列表1.2 相当于图1「Source」的部分
1 Audio功能的Source接口。
2 从Sensor取得Source。

「AudioBeamList」~「OpenAudioBeam」
从「Source」取得「AudioBeamList」,从List里打开指定的「AudioBeam」。
  1. // Get Audio Beam List
  2. IAudioBeamList* pAudioBeamList;   //……1
  3. hResult = pAudioSource->get_AudioBeams( &pAudioBeamList );  //……2
  4. if( FAILED( hResult ) ){
  5.   std::cerr << "Error : IAudioSource::get_AudioBeams()" << std::endl;
  6.   return -1;
  7. }
  8. // Open Audio Beam
  9. IAudioBeam* pAudioBeam;  //……3
  10. hResult = pAudioBeamList->OpenAudioBeam( 0, &pAudioBeam );  //……4
  11. if( FAILED( hResult ) ){
  12.   std::cerr << "Error : IAudioBeamList::OpenAudioBeam()" << std::endl;
  13.   return -1;
  14. }
复制代码
列表1.3 取得Microphone Array和AudioBeam
1 AudioBeamList接口。
2 从Source取得AudioBeam,然后取得Microphone Array的List。
3 AudioBeam接口。
4 从List里取得AudioBeam,打开Microphone Array。
   0代表第一个被找到的默认的Microphone Array。

「Get Angle and Confidence」
从「Stream」读入Audio数据,取得音源方向和推测的信赖值。
  1. while( 1 ){
  2.   // Get Angle and Confidence
  3.   FLOAT angle = 0.0f;
  4.   FLOAT confidence = 0.0f;
  5.   pAudioBeam->get_BeamAngle( &angle ); // radian [-0.872665f, 0.872665f]  ……1
  6.   pAudioBeam->get_BeamAngleConfidence( &confidence ); // confidence [0.0f, 1.0f]  ……2
  7.   // Show Result
  8.   // Convert from radian to degree : degree = radian * 180 / Pi
  9.   if( confidence > 0.5f ){
  10.     std::system( "cls" );
  11.     std::cout << "Angle : " << angle * 180.0f / M_PI << ", Confidence : " << confidence << std::endl;  //……3
  12.   }
  13.   // Input Key ( Exit ESC key )
  14.   if( GetKeyState( VK_ESCAPE ) < 0 ){
  15.     break;
  16.   }
  17. }
复制代码
列表1.5 取得音源方向和推测的信赖值
1 取得音源方向。
   角度单位是radian(弧度)。
2 取得音源方向的推测信赖值。
   取值范围是0.0f~1.0f,数值越大表示可信度更高。
3 把radian(弧度)转为dgree(度数)在Console上输出。
   只显示当前的数值,如果注释掉「std::system("cls");」的话,那么之前的值也会留在Cconsole上。

  可以取得的音源方向是Kinect v2的中心正面向水平方向左右+/-50°的范围。 


图4 音源方向的检测范围(+/-50°)

  因为取得的音源方向的角度单位是「radian(弧度)」要利用公式1转换为「degree(度数)」。

【公式1 adian(弧度)转换为(度数)】
弧度(radian)→角度(degree)∶ degree=radian×180÷π
角度(degree)→弧度(radian)∶ radian=degree×π÷180
运行结果
运行这个示例程序,就像图5一样,将显示出声音的音源角度(Angle)和推测的信赖值(Confidence)。

  如果Microphone Array的反应过度敏感或迟钝,可以通过调整操作系统的录音设备属性来改善(在[控制面板]-[声音]-[录制]的录音设备中的「麦克排列Xbox NUI Sensor」的属性里调整等级)。


图5 运行结果
  在Console上显示了音源方向的角度和推测的信赖值。

总结
  这一节是介绍如何使用Kinect SDK v2预览版取得AudioBeam。

  与Kinect SDK v1相比,从Microphone Array取得Audio数据的处理更加简单。
 楼主| 发表于 2014-12-2 00:42:49 | 显示全部楼层
备用资料留一楼
发表于 2014-12-2 09:11:39 | 显示全部楼层
  顶,不知可否放出PDF格式文件?
发表于 2014-12-2 14:25:46 | 显示全部楼层
感谢楼主的翻译!这真是绝佳的Kinect入门资料。
希望楼主放出全部的PDF版文件。
发表于 2015-9-18 13:40:58 | 显示全部楼层
挺有趣的原理
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|关于我们|小黑屋|Archiver|手机版|中文第一计算机图形学社区OpenGPU

GMT+8, 2019-1-18 08:29 , Processed in 0.068371 second(s), 20 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表