OpenCV学习笔记(15)使用OpenGL显示双目视觉三维重构效果上一篇笔记中使用Matlab初步显示了双目视觉重构出的环境三维效果图,不过并没有加上纹理信息。在OpenCV中文论坛里,大象的帖子(=1&t=8722&sid=02986dcffb5ebcedf299833e7cbf457c)给出了利用OpenGL显示视差数据的三维点云图,这是一个学习OpenGL和OpenCV混合编程的好帖子,里面的讨论跟帖也很有参考意义,我下面的代码也是参考这个帖子的,感谢大象和论坛上的朋友们。在大象的帖子中,所显示的三维点云是基于视差图来绘制的,视差越大,点云就越靠近摄像机的近面,但要显示环境的三维重构数据,则还需结合摄像机定标和双目校正(cvStereoRectify)获得的参数来计算出三维坐标(cvReprojectImageTo3D);另一方面,要动态显示实时的三维重构数据,还需要用到一个FreeGlut()的函数库,因为原本的glut函数库的glutMainLoop在调用之后就不会返回、实现不了循环,而FreeGlut则有一个glutMainLoopEvent函数,每循环一次就会返回。下面结合着代码里分步讲述,主要参考来源包括:[1]大象帖子:=1&t=8722&sid=02986dcffb5ebcedf299833e7cbf457c[2]李颖等.OpenGL函数与范例解析手册.国防工业出版社,2002年1月.[3]EdwardAngel著.段菲译.OpenGL编程基础(第3版).清华大学出版社,2008年3月.[4]Nehe教程Lesson6:=06[5]博客“守护地下铁”:[6]FreeGlut主页:一、FreeGlut的安装(1)在VC的安装目录(例如D:\MicrosoftVisualStudio9.0\VC)新建一个文件夹freeglut;(2)将下载的FreeGlut(freeglut2.6.0-3forMSVC)解压后,把include和lib文件夹复制到文件夹freeglut,把freeglut.dll复制到系统文件夹system32;(3)在VS2008的Tools–Options的VC++Directories中加入freeglut的include和lib路径;(4)在项目Properties的Link–input中加入opengl32.libglu32.libfreeglut.lib;viewplaincopytoclipboardprint?#includestdafx.h#includeMemLeakDetect.h//内存泄漏检测工具,下载地址:{STEREO_BM=0,STEREO_SGBM=1};intalg=STEREO_BM;intstereo_rectify=1,adaptThresh=1;intSADWindowSize=15,numberOfDisparities=64,SADWS_alpha=8,MaxDisp_beta=4,uniqRatio=25,thresRatio=60;intsaveFrames=1;boolfullDP=false;doublem_ObjectWidth[10]={0.0};//目标宽度doublem_ObjectHeight[10]={0.0};//目标高度doublem_ObjectDisparity[10]={0.0};//视差doublem_ObjectDistance[10]={0.0};//距离charimg1name[100],img2name[100],dispImgName[100],dispDataName[100];//---OpenGLfloatimgdata[500][500][3];//存放三维坐标数据floattexture[500][500][3];//存放纹理数据intwidth=0,height=0,rx=0,ry=0;inteyex=115,eyez=115,atx=100,atz=50;floatscalar=1;//scalarofconvertingpixelcolortofloatcoordinates二、OpenGL响应函数在大象帖子的跟帖中,villager5综合了一小段代码,随着鼠标移动,可以从多个视角观看生成的三维点云图,我在其基础上做了修改。为了与OpenCV循环同步,去掉了鼠标移动的响应函数(villager5的代码里用了定时器),改为使用OpenCV的TrackBar来调整OpenGL函数glLookAt的视角。另外,对于纹理映射,我暂时用一种简化的方式来实现,即直接把帧画面的纹理数据(RGB值)赋值到点云的颜色中glColor3f,这样的做法缺点是显示的三维点云是分块、不连续的,前方的点云块后面是黑色空洞。接下来会继续尝试按正常的纹理映射方法来实现,最终实现的效果应该是类似大象帖子中提到的StructureFromMotion软件所实现的效果:viewplaincopytoclipboardprint?/************************************************************************//*OpenGL响应函数*//************************************************************************/////////////////////////////////////////////////////////////////////////////功能键(方向键)响应函数voidspecial(intkey,intx,inty){switch(key){caseGLUT_KEY_LEFT:ry-=5;glutPostRedisplay();break;caseGLUT_KEY_RIGHT:ry+=5;glutPostRedisplay();break;caseGLUT_KEY_UP:rx+=5;glutPostRedisplay();break;caseGLUT_KEY_DOWN:rx-=5;glutPostRedisplay();break;}}////////////////////////////////////////////////////////////////////////////三维图像显示响应函数voidrenderScene(void){glClear(GL_COLOR_BUFFER_BIT);glLoadIdentity();//ResetthecoordinatesystembeforemodifyinggluLookAt(eyex-100,0.0,eyez-100.0,atx-100.0,0.0,atz-100.0,0.0,1.0,0.0);//根据滑动块位置变换OpenGL摄像机视角glRotatef(ry,0.0,1.0,0.0);//rotateaboutthezaxis//根据键盘方向键按键消息变换摄像机视角glRotatef(rx-180,1.0,0.0,0.0);//rotateabouttheyaxisfloatx,y,z;glPointSize(1.0);glBegin(GL_POINTS);//GL_POINTSfor(inti=0;iheight;i++){for(intj=0;jwidth;j++){glColor3f(texture[i][j][0]/255,texture[i][j][1]/255,texture[i][j][2]/255);//将图像纹理赋值到点云上x=-imgdata[i][j][0]/scalar;//添加负号以获得正确的左右上下方位y=-imgdata[i][j][1]/scalar;z=imgdata[i][j][2]/scalar;glVertex3f(x,y,z);}}glEnd();glFlush();}////////////////////////////////////////////////////////////////////////////窗口变化图像重构响应函数voidreshape(intw,inth){glViewport(0,0,(GLsizei)w,(GLsizei)h);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(60,(GLfloat)w/(GLfloat)h,1.0,500.0);//显示1-500距离单位(这里是cm)内的点云glMatrixMode(GL_MODELVIEW);}////////////////////////////////////////////////////////////////////////////载入三维坐标数据voidload3dDataToGL(IplImage*img3d){CvScalars;//accessingtheimagepixelsfor(inti=0;iheight;i++){for(intj=0;jwidth;j++){s=cvGet2D(img3d,i,j);//s.val[0]=x,s.val[1]=y,s.val[2]=zimgdata[i][j][0]=s.val[0];imgdata[i][j][1]=s.val[1];imgdata[i][j][2]=fabs(s.val[2]);}}}////////////////////////////////////////////////////////////////////////////载入左视图纹理数据voidloadTextureToGL(IplImage*img){//intind=0;CvScalarss;//accessingtheimagepixelsfor(inti=0;iheight;i++){for(intj=0;jwidth;j++){//OpenCV是默认BGR格式存储彩色图像ss=cvGet2D(img,i,j);//ss.val[0]=blue,ss.val[1]=green,ss.val[2]=redtextu