




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、基于Kinect-OpenNI-OpenCV-OpenGL的環境三維重構項目源碼詳見:http:前幾天剛入手了期待已久的Kinect,用于實驗室機器人項目的視覺導航與環境理解。首先要做的是破解->連接PC->獲取深度數據和圖像數據->三維點云顯示這么幾項基本工作。開始仿照的是飲水思源1博客的方法(使用VS2008在windows平臺上試用Kinect2),利用CL-NUI-Platform來破解,它的最新版是210,但我在XP上用會當機,后來換121版的就可以用了。CLNUI提供了十分簡便易用的接口,在OpenCV上調用很簡單,另外它還提供了Kin
2、ect底座馬達的控制接口和LED燈顏色的選擇接口,其例程中可以操控Kinect上下擺動。如果只需要獲取深度數據和圖像數據,CLNUI就夠用了。不過要做深入的應用,比如人體姿態識別、骨架提取、深度數據與圖像數據的合并等等,就該用到OpenNI了。國內的CNKINECT3是個不錯的Kinect開發論壇,版塊豐富,有很多資料可供借鑒。我通過論壇介紹的方法4成功配置了OpenNI+Kinect,先是用最新版的OpenNI+SensorKinect+NITE,但在XP下不能正常運行,可能跟.net平臺有關,老實按上面論壇的方法裝就成功了。另外用CMake+VS2008裝了最新的OpenCV_SVN,開始
3、試過在CMake里選擇WithTBB,但詭異的是TBB似乎只適用于VS2005,在VS2008編譯后試用里面的samples老是提示報錯找不到msvcp80.dll,重新用CMake配置取消了WithTBB,就一切正常了。編輯、深度攝像機的視角調整與深度/彩色圖像的合并通過研究OpenCV_SVN與OpenNI相關的代碼(cap_openni.cpp)發現,OpenCV目前只支持對Kinect的深度圖、視差圖和彩色/灰度圖及相關屬性的讀取,更進一步的設置還沒有實現。參考臺灣Heresy'spaces的博客文章透過OpneNI合并Kinect深度以及彩色影像資料6,想把深度圖和彩色圖合并
4、顯示,但是由于Kinect的深度攝像機和彩色攝像機是在不同的位置,而且鏡頭本身的參數也不完全相同,所以兩個攝像機所取得的畫面會有些微的差異(如圖1左下角子圖OpenGL三維點云顯示窗口所示,天花板的兩個日光燈對應深度圖和彩色圖的區域并沒有重合,而是錯位了)。圖1根據Heresy的分析,需要對深度攝像機的視角進行修正,在OpenNI下只需要一行代碼就可以實現:/6.correctviewportmDepthGenerator.GetAlternativeViewPointCap().SetViewPoint(mImageGenerator);不過在OpenCV中并沒有提供這一項設置,其源代碼mo
5、duleshighguisrccap_openni.cpp中setDepthGeneratorProperty并沒有任何實質的屬性設置o為此,需要改寫該函數,并且要在相應的頭文件moduleshighguiincludeopencv2highguihighgui_c.h中添加新的參數id,具體如下:1.將cap_openni.cpp第344行白SsetDepthGeneratorProperty改寫如下:boolCvCapture_OpenNI:setDepthGeneratorProperty(intpropIdx,doublepropValue)boolres=false;CV_Asser
6、t(depthGenerator.IsValid();switch(propIdx)caseCV_CAP_PROP_OPENNI_VIEW_POINT:depthGenerator.GetAlternativeViewPointCap().SetViewPoint(imageGenerator);res=true;break;default:CV_Error(CV_StsBadArg,"Depthgeneratordoesnotsupportsuchparameterforsetting.n");res=false;returnres;1.在highgui_c.h的第348
7、行下添加改變視角的參數ID號:CV_CAP_PROP_OPENNI_VIEW_POINT=24,然后在第352行下添加:CV_CAP_OPENNI_DEPTH_GENERATOR_VIEW_POINT=CV_CAP_OPENNI_DEPTH_GENERATOR+CV_CAP_PROP_OPENNI_VIEW_POINT從而使得OpenCV的VideoCapture屬性關于OpenNI的如下所示:/OpenNImapgeneratorsCV_CAP_OPENNI_DEPTH_GENERATOR=0,CV_CAP_OPENNI_IMAGE_GENERATOR=1<<31,CV_CAP_
8、OPENNI_GENERATORS_MASK=1<<31,/PropertiesofcamerasavaliblethroughOpenNIinterfacesCV_CAP_PROP_OPENNI_OUTPUT_MODE=20,CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH=21,/inmmCV_CAP_PROP_OPENNI_BASELINE=22,/inmmCV_CAP_PROP_OPENNI_FOCAL_LENGTH=23,/inpixels”'CV_CAP_PROP_OPENNI_VIEW_POINT=24,'''CV_
9、CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE=CV_CAP_OPENNI_IMAGE_GENERATOR+CV_CAP_PROP_OPENNI_OUTPUT_MODECV_CAP_OPENNI_DEPTH_GENERATOR_BASELINE=CV_CAP_OPENNI_DEPTH_GENERATOR+CV_CAP_PROP_OPENNI_BASELINE,CV_CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH=CV_CAP_OPENNI_DEPTH_GENERATOR+CV_CAP_PROP_OPENNI_FOCAL_LENGTH
10、”'CV_CAP_OPENNI_DEPTH_GENERATOR_VIEW_POINT=CV_CAP_OPENNI_DEPTH_GENERATOR+CV_CAP_PROP_OPENNI_VIEW_POINT'''改寫完上述源代碼后保存,并且用CMake和VS2008重新編譯一次OpenCV,我們就可以用OpenCV的接口來控制Kinect深度攝像頭的視角,使其深度數據和圖像數據能夠很好的重合起來,如圖2所示,注意與圖1相比,右上角的偽彩色視差圖四周出現了黑邊,這就是視角調整后的效果:圖2IplImage*CvCapture_OpenNI:retrievePoint
11、CloudMap()(.intcols=depthMetaData.XRes(),rows=depthMetaData.YRes();if(cols<=0|rows<=0)return0;cv:Matdepth;getDepthMapFromMetaData(depthMetaData,depth,noSampleValue,shadowValue);constfloatbadPoint=0;cv:MatpointCloud_XYZ(rows,cols,CV_32FC3,cv:Scalar:all(badPoint);for(inty=0;y<rows;y+)(for(int
12、x=0;x<cols;x+)(unsignedshortd=depth.at(y,x);/Checkforinvalidmeasurementsif(d=CvCapture_OpenNI:INVALID_PIXEL_VAL)/notvalidcontinue;XnPoint3Dproj,real;proj.X=x;proj.Y=y;proj.Z=d;depthGenerator.ConvertProjectiveToRealWorld(1,&proj,&real);pointCloud_XYZ.at(y,x)=cv:Point3f(real.X*0.001f,real.Y
13、*0.001f,real.Z*0.001f);/frommmtometers)outputMapsCV_CAP_OPENNI_POINT_CLOUD_MAP.mat=pointCloud_XYZ;returnoutputMapsCV_CAP_OPENNI_POINT_CLOUD_MAP.getIplImagePtr();)不過可以看到上面核心的代碼就一行:depthGenerator.ConvertProjectiveToRealWorld(1,&proj,&real);具體是怎樣實現的呢?我們可以進一步找OpenNI的源代碼來分析。不過這里我是從原來雙目視覺的經驗上自己編寫代
14、碼來實現三維點云坐標的計算。實際上Kinect的深度攝像頭成像也類似于普通的雙目立體視覺,只要獲取了兩個攝像頭之間的基線(baseline)和焦函數,也可以計算出三維坐標距(focallength)、以及視差數據,通過構造矩陣Q,利用OpenCV的reprojectimageTo3D下面我們通過以下代碼看看矩陣Q的構造過程:capture.set(CV_CAP_OPENNI_DEPTH_GENERATOR_VIEW_POINT1.0);/調整深度攝像頭視角doubleb=capture.get(CV_CAP_OPENNI_DEPTH_GENERATOR_BASELINE);/mmdoubleF
15、=capture.get(CV_CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH);/pixelsdoubleq口=1,0,0,-320.0,0,1,0,-240.0,0,0,0,F,0,0,1./b,0;MatmatQ(4,4,CV_64F,q);而三維點云坐標的計算,以及深度、視差、彩色圖像的讀取,則如下所示:/抓取數據if(!capture.grab()cout<<"Cannotgrabimages."<<endl;return-1;/讀取深度數據capture.retrieve(depthMap,CV_CAP_O
16、PENNI_DEPTH_MAP);minMaxLoc(depthMap,&mindepth,&maxdepth);/讀取視差數據capture.retrieve(disparityMap,CV_CAP_OPENNI_DISPARITY_MAP_32F);colorizeDisparity(disparityMap,colorDisparityMapmaxDisparity);colorDisparityMap.copyTo(validColorDisparityMap,disparityMap!=0);imshow("colorizeddisparitymap&quo
17、t;,validColorDisparityMap);/讀取彩色圖像數據capture.retrieve(bgrImage,CV_CAP_OPENNI_BGR_IMAGE);imshow("Colorimage",bgrImage);/利用視差數據計算三維點云坐標cv二reprojectImageTo3D(disparityMap,xyzMap,matQ,true);這里值得注意的是,在計算視差時,如果視差圖是采用默認的CV_8UC1格式(參數ID是CV_CAP_OPENNI_DISPARITY_MAP),由于視差被限制在0-255整數范圍內,造成一定的誤差,所得到的三維坐
18、標數據會出現分層,如圖3和圖4所示:圖3Matlab繪制的三維點云,不同深度上有明顯分層圖4左為直接得到白深度數據Mesh圖,中為由8位視差數據計算得到的深度數據,右為對應的視差數據而采用32位浮點格式來獲取視差數據(參數ID:CV_CAP_OPENNI_DISPARITY_MAP_32F),則消除了這種因視差誤差造成深度數值分層的現象,如圖5、6所示:圖5深度數值的分層現象基本消除圖6兩種方式得到的深度數據一致編輯三、利用OpenGL顯示三維點云數據這方面主要是基于學習筆記(15)7的內容,不過當時是通過另設OpenCV窗口設置Trackbar來調整OpenGL的視點位置和攝像機位置。在這里
19、則主要參考了OpenCV論壇的帖子HQOpenCV和OpenGL編程:關于顯示點云數據-StereoVision源碼分享8中villager5提供的方法來調整攝像機位置,做了一定的修改,使得鼠標左鍵拖曳能夠實現對上下左右的視角變換,鼠標右鍵拖曳能夠實現視距遠近的變換,不再需要用Trackbar來調整。下面是相關的代碼:#defineSIGN(x)(x)<0?-1:(x)>0?1:0)/-OpenGL全局變量floatxyzdata4806403;floattexture4806403;intglWinWidth=640,glWinHeight=480;intwidth=640,he
20、ight=480;doubleeyex,eyey,eyez,atx,aty,atz;/eye*-攝像機位置,at*-注視點位置boolleftClickHold=false,rightClickHold=false;intmx,my;/鼠標按鍵時在OpenGL窗口的坐標intry=90,rx=90;/攝像機相對注視點的觀察角度doublemindepth,maxdepth;/深度數據的極值doubleradius=6000.0;/攝像機與注視點的距離/*/*OpenGL響應函數*/*/鼠標按鍵響應函數voidmouse(intbutton,intstate,intx,inty)(if(butt
21、on=GLUT_LEFT_BUTTON)(if(state=GLUT_DOWN(leftClickHold=true;)else(leftClickHold=false;)if(button=GLUT_RIGHT_BUTTON)(if(state=GLUT_DOWN(rightClickHold=true;)else(rightClickHold=false;)/鼠標運動響應函數voidmotion(intx,inty)(intrstep=5;if(leftClickHold=true)(if(abs(x-mx)>abs(y-my)(rx+=SIGN(x-mx)*rstep;)else(
22、ry-=SIGN(y-my)*rstep;)mx=x;my=y;glutPostRedisplay();)if(rightClickHold=true)(radius+=SIGN(y-my)*100.0;radius=std:max(radius,100.0);mx=x;my=y;glutPostRedisplay();)/三維圖像顯示響應函數voidrenderScene(void)(/clearscreenanddepthbufferglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);/Resetthecoordinatesystembefor
23、emodifyingglLoadIdentity();/setthecamerapositionatx=0.0f;aty=0.0f;atz=(mindepth-maxdepth)/2.0f;eyex=atx+radius*sin(CV_PI*ry/180.0f)*cos(CV_PI*rx/180.0f);eyey=aty+radius*cos(CV_PI*ry/180.0f);eyez=atz+radius*sin(CV_PI*ry/180.0f)*sin(CV_PI*rx/180.0f);gluLookAt(eyex,eyey,eyez,atx,aty,atz,0.0,1.0,0.0);gl
24、Rotatef(0,0,1,0);glRotatef(-180,1,0,0);/對點云數據進行三角化/參考自:/wearegoingtoloopthroughallofourterrain'sdatapoints,/butweonlywanttodrawonetrianglestripforeachsetalongthex-axis.for(inti=0;i<height;i+)(glBegin(GL_TRIANGLE_STRIP);for(intj=0;j<width;j+)(/foreachvertex,wecalculatethevertexcolor,/wesett
25、hetexturecoordinate,andwedrawthevertex./*thevertexesaredrawninthisorder:0>1/2>3*/drawvertex0glTexCoord2f(0.0f,0.0f);glColor3f(textureij0/255.0f,textureij1/255.0f,textureij2/255.0f);glVertex3f(xyzdataij0,xyzdataij1.xyzdataij2);/drawvertex1glTexCoord2f(1.0f,0.0f);glColor3f(texturei+1j0/255.0f,te
26、xturei+1j1/255.0f,texturei+1j2/255.0f);glVertex3f(xyzdatai+1j0,xyzdatai+1j1,xyzdatai+1j2);/drawvertex2glTexCoord2f(0.0f,1.0f);glColor3f(textureij+10/255.0f,textureij+11/255.0f,textureij+12/255.0f);glVertex3f(xyzdataij+10,xyzdataij+11,xyzdataij+12);/drawvertex3glTexCoord2f(1.0f,1.0f);glColor3f(textur
27、ei+1j+10/255.0f,texturei+1j+11/255.0f,texturei+1j+12/255.0f);glVertex3f(xyzdatai+1j+10,xyzdatai+1j+11,xyzdatai+1j+12);glEnd();/enableblendingglEnable(GL_BLEND);/enableread-onlydepthbufferglDepthMask(GL_FALSE);/settheblendfunctiontowhatweusefortransparencyglBlendFunc(GL_SRC_ALPHA,GL_ONE);/setbacktonormaldepthbuffermode(writable)glDepthMask(GL_TRUE);/disableblendingglDisable(GL_BLEND);/*floatx,y,z;/繪制圖像點云glPointSize(1.0);glBegin(GL_POINTS);for(inti
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 礦石浮選工藝優化-石墨滑石選礦考核試卷
- 畜禽繁殖力與遺傳改良研究考核試卷
- 紡織材料與纖維的研究與發展考核試卷
- 電腦系統優化與提速技巧考核試卷
- 筆的制造生產計劃編制與執行考核試卷
- 嘉興南湖學院《Python數據分析與應用》2023-2024學年第二學期期末試卷
- 昆明理工大學津橋學院《CAD制圖》2023-2024學年第二學期期末試卷
- 咸陽市2025年三年級數學第二學期期末學業水平測試試題含解析
- 日照職業技術學院《國際商務創業策劃案例分析》2023-2024學年第二學期期末試卷
- 寧德市周寧縣2024-2025學年數學四年級第二學期期末考試試題含解析
- 大部分分校:地域文化形考任務三-國開(CQ)-國開期末復習資料
- 2024年全國中學生生物學聯賽試題含答案
- 《人工智能基礎》課件-AI的前世今生:她從哪里來
- 數獨題目高級50題(后附答案)
- 全媒體運營師-國家職業標準(2023年版)
- 崩塌易發程度數量化評分表
- 年產10000噸耐高溫α-淀粉酶發酵車間設計
- 機組黑啟動方案
- 平衡計分卡及戰略地圖
- 《觀潮》學歷案案例
- 附件:湖北省重點水利水電工程施工招標投標評分標準-鄂水
評論
0/150
提交評論