【翻译】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里全部公开了。
 
图2 Kinect SDK v2预览版的数据取得流程(重发)
 
「Sensor」
取得「Sensor」
// Sensor
IKinectSensor* pSensor;   ……1
HRESULT hResult = S_OK;
hResult = GetDefaultKinectSensor( &pSensor );  ……2
if( FAILED( hResult ) ){
  std::cerr << "Error : GetDefaultKinectSensor" << std::endl;
  return -1;
}
hResult = pSensor->Open();  ……3
if( FAILED( hResult ) ){
  std::cerr << "Error : IKinectSensor::Open()" << std::endl;
  return -1;
}
列表1.1 相当于图1「Sensor」的部分(重发)
1 处理Kinect v2预览版的Sensor接口。
2 取得默认的Sensor。
3 打开Sensor。
 
「Source」
从「Sensor」取得「Source」。
// Source
IDepthFrameSource* pDepthSource;  ……1
hResult = pSensor->get_DepthFrameSource( &pDepthSource );  ……2
if( FAILED( hResult ) ){
  std::cerr << "Error : IKinectSensor::get_DepthFrameSource()" << std::endl;
  return -1;
}
列表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」。
// Reader
IDepthFrameReader* pDepthReader;  ……1
hResult = pDepthSource->OpenReader( &pDepthReader );  ……2
if( FAILED( hResult ) ){
  std::cerr << "Error : IDepthFrameSource::OpenReader()" << std::endl;
  return -1;
}
列表1.3 相当于图1「Reader」的部分
1 取得Depth Frame的Reader接口。
2 从Source打开Reader。
 
「Frame」~「Data」
从「Reader」取得最新的「Frame」。
int width = 512;  ……1
int height = 424;  ……1
unsigned int bufferSize = width * height * sizeof( unsigned short );  ……2
cv::Mat bufferMat( height, width, CV_16SC1 );  ……3
cv::Mat depthMat( height, width, CV_8UC1 );  ……3
cv::namedWindow( "Depth" );
while( 1 ){
  // Frame
  IDepthFrame* pDepthFrame = nullptr;  ……4
  hResult = pDepthReader->AcquireLatestFrame( &pDepthFrame );  ……5
  if( SUCCEEDED( hResult ) ){
    hResult = pDepthFrame->AccessUnderlyingBuffer( &bufferSize, reinterpret_cast<UINT16**>( &bufferMat.data ) );  ……6
    if( SUCCEEDED( hResult ) ){
      bufferMat.convertTo( depthMat, CV_8U, -255.0f / 4500.0f255.0f );  ……7
    }
  }
  SafeRelease( pDepthFrame );
  // Show Window
  cv::imshow( "Depth", depthMat );
  if( cv::waitKey( 30 ) == VK_ESCAPE ){
    break;
  }
}
列表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数据的示例程序。
posted @ 2014-12-02 00:04  Trace0429  阅读(3842)  评论(0编辑  收藏  举报