【翻譯】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數據的示例程序。下一節介紹取得B odyIndex數據的示例程序。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM