• 【翻译】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数据的示例程序。
  • 相关阅读:
    [luogu4053 JSOI2007] 建筑抢修 (贪心 优先队列)
    [luogu2272 ZJOI2007] 最大半连通子图 (tarjan缩点 拓扑排序 dp)
    20180705 考试记录
    [luogu4310] 绝世好题 (递推)
    [luogu2765 网络流24题] 魔术球问题 (dinic最大流)
    [luogu4151 WC2011] 最大XOR和路径 (线性基)
    [luogu3232 HNOI2013] 游走 (高斯消元 期望)
    [luogu3726 HNOI2017] 抛硬币 (拓展lucas)
    20180703 考试记录
    [spoj] HIGH
  • 原文地址:https://www.cnblogs.com/TracePlus/p/4136357.html
Copyright © 2020-2023  润新知