OpenNI2顯示深度、彩色及融合圖像

 在《Kinect開發教程二:OpenNI讀取深度圖像與彩色圖像並顯示》中,小斤介紹了OpenNI讀取深度與彩色圖像數據的方法,並且藉助OpenCV進行顯示。

      OpenNI2在接口上與OpenNI有了較大變化,具體更新可以查看《OpenNI Migration Guide》。從獲取深度,彩色傳感器的數據而言,小斤覺得調用更爲直觀,但對於Kinect,一大缺憾是不支持OpenNI2提供的深度與彩色圖像配準的方法(體現在下文中的device.isImageRegistrationModeSupported()方法)。

      但使用Kinect的童鞋也不必沮喪,在OpenNI2.1 beta中,小斤看到了新增的convertDepthToColorCoordinates()方法可以做一些深度與彩色座標數據的轉化,它的效果應該是與device.setImageRegistrationMode( IMAGE_REGISTRATION_DEPTH_TO_COLOR )類似的,有興趣的童鞋可以嘗試一下。

      在顯示方面,小斤還是使用OpenCV,這次是使用OpenCV的C++接口進行操作。

  1. /************************* 
  2. OpenNI2 Deep, Color and Fusion Image 
  3. Author: Xin Chen, 2013.2 
  4. Blog: http://blog.csdn.net/chenxin_130 
  5. *************************/  
  6.   
  7. #include <stdlib.h>  
  8. #include <iostream>  
  9. #include <string>  
  10. #include "OpenNI.h"  
  11. #include "opencv2/core/core.hpp"  
  12. #include "opencv2/highgui/highgui.hpp"  
  13. #include "opencv2/imgproc/imgproc.hpp"  
  14. using namespace std;  
  15. using namespace cv;  
  16. using namespace openni;  
  17.   
  18. void CheckOpenNIError( Status result, string status )  
  19. {   
  20.     if( result != STATUS_OK )   
  21.         cerr << status << " Error: " << OpenNI::getExtendedError() << endl;  
  22. }  
  23.   
  24. int main( int argc, char** argv )  
  25. {  
  26.     Status result = STATUS_OK;    
  27.       
  28.     //OpenNI2 image  
  29.     VideoFrameRef oniDepthImg;  
  30.     VideoFrameRef oniColorImg;  
  31.   
  32.     //OpenCV image  
  33.     cv::Mat cvDepthImg;  
  34.     cv::Mat cvBGRImg;  
  35.     cv::Mat cvFusionImg;  
  36.       
  37.     cv::namedWindow("depth");  
  38.     cv::namedWindow("image");  
  39.     cv::namedWindow("fusion");  
  40.     char key=0;  
  41.   
  42.     //【1】  
  43.     // initialize OpenNI2  
  44.     result = OpenNI::initialize();  
  45.     CheckOpenNIError( result, "initialize context" );    
  46.   
  47.     // open device    
  48.     Device device;  
  49.     result = device.open( openni::ANY_DEVICE );  
  50.   
  51.     //【2】  
  52.     // create depth stream   
  53.     VideoStream oniDepthStream;  
  54.     result = oniDepthStream.create( device, openni::SENSOR_DEPTH );  
  55.   
  56.     //【3】  
  57.     // set depth video mode  
  58.     VideoMode modeDepth;  
  59.     modeDepth.setResolution( 640, 480 );  
  60.     modeDepth.setFps( 30 );  
  61.     modeDepth.setPixelFormat( PIXEL_FORMAT_DEPTH_1_MM );  
  62.     oniDepthStream.setVideoMode(modeDepth);  
  63.     // start depth stream  
  64.     result = oniDepthStream.start();  
  65.    
  66.     // create color stream  
  67.     VideoStream oniColorStream;  
  68.     result = oniColorStream.create( device, openni::SENSOR_COLOR );  
  69.     // set color video mode  
  70.     VideoMode modeColor;  
  71.     modeColor.setResolution( 640, 480 );  
  72.     modeColor.setFps( 30 );  
  73.     modeColor.setPixelFormat( PIXEL_FORMAT_RGB888 );  
  74.     oniColorStream.setVideoMode( modeColor);  
  75.       
  76. //【4】  
  77.     // set depth and color imge registration mode  
  78.     if( device.isImageRegistrationModeSupported(IMAGE_REGISTRATION_DEPTH_TO_COLOR ) )  
  79.     {  
  80.         device.setImageRegistrationMode( IMAGE_REGISTRATION_DEPTH_TO_COLOR );  
  81.     }  
  82.     // start color stream  
  83.     result = oniColorStream.start();    
  84.   
  85.     while( key!=27 )   
  86.     {    
  87.         // read frame  
  88.         if( oniColorStream.readFrame( &oniColorImg ) == STATUS_OK )  
  89.         {  
  90.             // convert data into OpenCV type  
  91.             cv::Mat cvRGBImg( oniColorImg.getHeight(), oniColorImg.getWidth(), CV_8UC3, (void*)oniColorImg.getData() );  
  92.             cv::cvtColor( cvRGBImg, cvBGRImg, CV_RGB2BGR );  
  93.             cv::imshow( "image", cvBGRImg );  
  94.         }  
  95.     
  96.         if( oniDepthStream.readFrame( &oniDepthImg ) == STATUS_OK )  
  97.         {  
  98.             cv::Mat cvRawImg16U( oniDepthImg.getHeight(), oniDepthImg.getWidth(), CV_16UC1, (void*)oniDepthImg.getData() );  
  99.             cvRawImg16U.convertTo( cvDepthImg, CV_8U, 255.0/(oniDepthStream.getMaxPixelValue()));  
  100.             //【5】  
  101.             // convert depth image GRAY to BGR  
  102.             cv::cvtColor(cvDepthImg,cvFusionImg,CV_GRAY2BGR);  
  103.             cv::imshow( "depth", cvDepthImg );  
  104.         }  
  105.         //【6】  
  106.         cv::addWeighted(cvBGRImg,0.5,cvFusionImg,0.5,0,cvFusionImg);  
  107.         cv::imshow( "fusion", cvFusionImg );  
  108.         key = cv::waitKey(20);  
  109.     }  
  110.   
  111.     //cv destroy  
  112.     cv::destroyWindow("depth");  
  113.     cv::destroyWindow("image");  
  114.     cv::destroyWindow("fusion");  
  115.   
  116.     //OpenNI2 destroy  
  117.     oniDepthStream.destroy();  
  118.     oniColorStream.destroy();  
  119.     device.close();  
  120.     OpenNI::shutdown();  
  121.   
  122.     return 0;  
  123. }  

      小斤由上到下解釋一把:

      【1】使用OpenNI::initialize()方法進行初始化,對於錯誤處理,可以使用OpenNI::getExtendedError()方法。在這裏,Device對象打開任意一個可用設備。

      【2】在OpenNI2中,可以通過創建VideoStream視頻流對象來讀取設備的深度圖像和色彩圖像數據。

      【3】對於VideoStream視頻流對象,我們可以設備它的Mode,包括分辨率,FPS,像素格式等等。對於像素格式的類型,可以使用VideoStream的getSensorInfo()方法獲得,目前Kinect只有PIXEL_FORMAT_DEPTH_1_MM可供選擇。

      【4】如果設備支持深度與彩色圖像配準的話,小斤在這裏使用OpenNI2自帶的接口進行配準。在while循環中,各個VideoStream對象通過readFrame()來讀取對應的圖像數據。

      【5】將OpenNI的圖像數據轉換爲OpenCV可顯示的圖像格式。對於彩色圖像,可以先將數據塞入OpenCV三通道(8位)RGB對象,再轉換到BGR來顯示。對於深度圖像,先放入單通道(16位)對象(這是因爲深度數據的值域較大),最近將深度值等比例縮小到[0,255]的值域中,作爲灰度圖顯示。

      【6】最後的圖像融合,由於addWeighted()方法需要兩個輸入圖像是同一類型,所以小斤首先將深度灰度圖(單通道),轉化爲BGR圖像,這樣就與彩色圖像一致了。再通過該方法進行融合,小斤使用的比例是0.5,0.5,也就是融合圖像的每個像素點的值,都是(深度圖像該點的像素值*0.5)+ (彩色圖像該點的像素值*0.5)。


----------------------------------

作者:小斤(陳忻)

新浪圍脖:@小斤陳

本文屬於原創文章,如需轉載引用請註明原文作者和鏈接,謝謝。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章