細心的朋友肯定已經發現Kinect上長了三隻眼睛,其中一個是彩色網路攝影機,另外兩個深度網路攝影機,一個負責發射紅外光,一個負責接收,這樣,我們便能通過Kinect得到一幅彩色映像和一幅深度映像。如果大家對Kniect眼睛的技術細節感興趣,請點擊這裡。
小斤的第一個範例,便是通過OpenNI得到彩色和深度映像咯,代碼不長,其中一部分參考了Heresky童鞋的文章《透過
OpneNI 合併 Kinect 深度以及彩色影像資料》,此外,小斤補充了OpenCV的顯示部分,使範例更為直觀。
#include <stdlib.h>#include <iostream>#include <string>//【1】#include <XnCppWrapper.h>#include "opencv/cv.h"#include "opencv/highgui.h"using namespace std;using namespace cv;void CheckOpenNIError( XnStatus result, string status ){ if( result != XN_STATUS_OK ) cerr << status << " Error: " << xnGetStatusString( result ) << endl;}int main( int argc, char** argv ){XnStatus result = XN_STATUS_OK; xn::DepthMetaData depthMD;xn::ImageMetaData imageMD;//OpenCVIplImage* imgDepth16u=cvCreateImage(cvSize(640,480),IPL_DEPTH_16U,1);IplImage* imgRGB8u=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);IplImage* depthShow=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);IplImage* imageShow=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);cvNamedWindow("depth",1);cvNamedWindow("image",1);char key=0;//【2】// context xn::Context context; result = context.Init(); CheckOpenNIError( result, "initialize context" ); // creategenerator xn::DepthGenerator depthGenerator; result = depthGenerator.Create( context ); CheckOpenNIError( result, "Create depth generator" ); xn::ImageGenerator imageGenerator;result = imageGenerator.Create( context ); CheckOpenNIError( result, "Create image generator" );//【3】//map mode XnMapOutputMode mapMode; mapMode.nXRes = 640; mapMode.nYRes = 480; mapMode.nFPS = 30; result = depthGenerator.SetMapOutputMode( mapMode ); result = imageGenerator.SetMapOutputMode( mapMode ); //【4】// correct view port depthGenerator.GetAlternativeViewPointCap().SetViewPoint( imageGenerator ); //【5】//read dataresult = context.StartGeneratingAll(); //【6】result = context.WaitNoneUpdateAll(); while( (key!=27) && !(result = context.WaitNoneUpdateAll( )) ) { //get meta datadepthGenerator.GetMetaData(depthMD); imageGenerator.GetMetaData(imageMD);//【7】//OpenCV outputmemcpy(imgDepth16u->imageData,depthMD.Data(),640*480*2);cvConvertScale(imgDepth16u,depthShow,255/4096.0,0);memcpy(imgRGB8u->imageData,imageMD.Data(),640*480*3);cvCvtColor(imgRGB8u,imageShow,CV_RGB2BGR);cvShowImage("depth", depthShow);cvShowImage("image",imageShow);key=cvWaitKey(20);}//destroycvDestroyWindow("depth");cvDestroyWindow("image");cvReleaseImage(&imgDepth16u);cvReleaseImage(&imgRGB8u);cvReleaseImage(&depthShow);cvReleaseImage(&imageShow);context.StopGeneratingAll();context.Shutdown();return 0;}
這邊小斤由上到下解釋一把:
【1】<XnCppWrapper.h>便是OpenNI的檔案頭了,使用OpenNI的話,目前只要include這個就行。
【2】DepthGenerator和ImageGenerator,小斤稱之為映像產生器,前者負責深度映像,後者負責彩色映像。建立一個產生器非常簡單,首先我們要初始化一個Context上下文,然後把Context作為Create函數的參數,便可以建立產生器了。
【3】XnMapOutputMode是用來設定產生器的參數的,這邊小斤設定了解析度為640*480(標準),30fps採樣。
【4】depthGenerator.GetAlternativeViewPointCap().SetViewPoint( imageGenerator)這句話也許會讓大家疑惑,它是用來調整視角的。為什麼要調整呢?因為Kinect的三隻眼長在不同的地方,所以畫幅一致的深度網路攝影機和彩色網路攝影機,它們看出來的景物是有偏差的,這裡OpenNI提供了函數進行對齊。這裡,小斤把深度產生器的視角,設定為彩色產生器的視角。
【5】調用StartGeneratingAll()後,產生器們便開始上班了,如果要結束,就StopGeneratingAll()函數。
【6】儘管產生器們在工作了,但他們一直忙著各讀各的,沒有人協調,自己不會乖乖把最新的資料給我們。我們調用getMetaData()方法前,需要使用WaitAnyUpdateAll()、WaitOneUpdateAll()、WaitNoneUpdateAll()和WiatAndUpdateAll()中的一種。功能如其名,這邊小斤使用的是WaitNoneUpdateAll()函數,它比較暴力,不管產生器有沒有讀到新資料,我這邊先更新了再說。大家可以試試其它三個,看看效果。
【7】這邊使用OpenNI獲得映像MetaData資料後,小斤通過一系列函數,轉換為OpenCV的IplImage映像類型,然後輸出。主要參考了這篇文章。
對於深度MetaData,這邊使用cvConvertScale轉換尺度,成為灰階值[0,255]的灰階圖。對於彩色MetaData,使用cvCvtColor轉換色彩空間即可。按ESC鍵可以退出迴圈,結束程式。
最終效果如下:
在灰階圖中灰階值0顯示為黑色,255為白色,所以,離Kinect近的地方(案頭)顯示為黑色,中間為不同程度的灰色,遠處(天花板)顯示為白色。
----------------------------------
作者:小斤(陳忻)
本文屬於原創文章,如需轉載引用請註明原文作者和連結,謝謝。