在《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++接口進行操作。
- /*************************
- OpenNI2 Deep, Color and Fusion Image
- Author: Xin Chen, 2013.2
- Blog: http://blog.csdn.net/chenxin_130
- *************************/
- #include <stdlib.h>
- #include <iostream>
- #include <string>
- #include "OpenNI.h"
- #include "opencv2/core/core.hpp"
- #include "opencv2/highgui/highgui.hpp"
- #include "opencv2/imgproc/imgproc.hpp"
- using namespace std;
- using namespace cv;
- using namespace openni;
- void CheckOpenNIError( Status result, string status )
- {
- if( result != STATUS_OK )
- cerr << status << " Error: " << OpenNI::getExtendedError() << endl;
- }
- int main( int argc, char** argv )
- {
- Status result = STATUS_OK;
- //OpenNI2 image
- VideoFrameRef oniDepthImg;
- VideoFrameRef oniColorImg;
- //OpenCV image
- cv::Mat cvDepthImg;
- cv::Mat cvBGRImg;
- cv::Mat cvFusionImg;
- cv::namedWindow("depth");
- cv::namedWindow("image");
- cv::namedWindow("fusion");
- char key=0;
- //【1】
- // initialize OpenNI2
- result = OpenNI::initialize();
- CheckOpenNIError( result, "initialize context" );
- // open device
- Device device;
- result = device.open( openni::ANY_DEVICE );
- //【2】
- // create depth stream
- VideoStream oniDepthStream;
- result = oniDepthStream.create( device, openni::SENSOR_DEPTH );
- //【3】
- // set depth video mode
- VideoMode modeDepth;
- modeDepth.setResolution( 640, 480 );
- modeDepth.setFps( 30 );
- modeDepth.setPixelFormat( PIXEL_FORMAT_DEPTH_1_MM );
- oniDepthStream.setVideoMode(modeDepth);
- // start depth stream
- result = oniDepthStream.start();
- // create color stream
- VideoStream oniColorStream;
- result = oniColorStream.create( device, openni::SENSOR_COLOR );
- // set color video mode
- VideoMode modeColor;
- modeColor.setResolution( 640, 480 );
- modeColor.setFps( 30 );
- modeColor.setPixelFormat( PIXEL_FORMAT_RGB888 );
- oniColorStream.setVideoMode( modeColor);
- //【4】
- // set depth and color imge registration mode
- if( device.isImageRegistrationModeSupported(IMAGE_REGISTRATION_DEPTH_TO_COLOR ) )
- {
- device.setImageRegistrationMode( IMAGE_REGISTRATION_DEPTH_TO_COLOR );
- }
- // start color stream
- result = oniColorStream.start();
- while( key!=27 )
- {
- // read frame
- if( oniColorStream.readFrame( &oniColorImg ) == STATUS_OK )
- {
- // convert data into OpenCV type
- cv::Mat cvRGBImg( oniColorImg.getHeight(), oniColorImg.getWidth(), CV_8UC3, (void*)oniColorImg.getData() );
- cv::cvtColor( cvRGBImg, cvBGRImg, CV_RGB2BGR );
- cv::imshow( "image", cvBGRImg );
- }
- if( oniDepthStream.readFrame( &oniDepthImg ) == STATUS_OK )
- {
- cv::Mat cvRawImg16U( oniDepthImg.getHeight(), oniDepthImg.getWidth(), CV_16UC1, (void*)oniDepthImg.getData() );
- cvRawImg16U.convertTo( cvDepthImg, CV_8U, 255.0/(oniDepthStream.getMaxPixelValue()));
- //【5】
- // convert depth image GRAY to BGR
- cv::cvtColor(cvDepthImg,cvFusionImg,CV_GRAY2BGR);
- cv::imshow( "depth", cvDepthImg );
- }
- //【6】
- cv::addWeighted(cvBGRImg,0.5,cvFusionImg,0.5,0,cvFusionImg);
- cv::imshow( "fusion", cvFusionImg );
- key = cv::waitKey(20);
- }
- //cv destroy
- cv::destroyWindow("depth");
- cv::destroyWindow("image");
- cv::destroyWindow("fusion");
- //OpenNI2 destroy
- oniDepthStream.destroy();
- oniColorStream.destroy();
- device.close();
- OpenNI::shutdown();
- return 0;
- }
小斤由上到下解釋一把:
【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)。
----------------------------------
作者:小斤(陳忻)
新浪圍脖:@小斤陳
本文屬於原創文章,如需轉載引用請註明原文作者和鏈接,謝謝。