全文參考:http://blog.csdn.net/sky_freebird/article/details/6695059
運用OpenGL實現二維圖像的三維點雲圖顯示。
#include <iostream>
#include <stdlib.h>
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
//#include <math.h>
//#include <gl/glut.h>
#include <gl/freeglut.h>
using namespace std;
float imgdata[480][640]; //注意維度,第一維表示高度,第二維表示寬度
int w=0;
int h=0;
float scalar=50;//scalar of converting pixel color to float coordinates
#define pi 3.1415926
bool mouseisdown=false;
bool loopr=false;
int mx,my;
int ry=10;
int rx=10;
void timer(int p)
{
ry-=5;
//marks the current window as needing to be redisplayed.
glutPostRedisplay();
if (loopr)
glutTimerFunc(200,timer,0);
}
void mouse(int button, int state, int x, int y)
{
if(button == GLUT_LEFT_BUTTON)
{
if(state == GLUT_DOWN)
{
mouseisdown=true;
loopr=false;
}
else
{
mouseisdown=false;
}
}
if (button== GLUT_RIGHT_BUTTON)
if(state == GLUT_DOWN)
{
loopr=true;
glutTimerFunc(200,timer,0);
}
}
void motion(int x, int y)
{
if(mouseisdown==true)
{
ry+=x-mx;
rx+=y-my;
mx=x;
my=y;
glutPostRedisplay();
}
}
void special(int key, int x, int y)
{
switch(key)
{
case GLUT_KEY_LEFT:
ry-=5;
glutPostRedisplay();
break;
case GLUT_KEY_RIGHT:
ry+=5;
glutPostRedisplay();
break;
case GLUT_KEY_UP:
rx+=5;
glutPostRedisplay();
break;
case GLUT_KEY_DOWN:
rx-=5;
glutPostRedisplay();
break;
}
}
void renderScene(void) {
glClear (GL_COLOR_BUFFER_BIT);
glLoadIdentity();// Reset the coordinate system before modifying
//gluLookAt (0.0, 0.0, 7.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0);
gluLookAt (0.0, 0.0, 7.0, -0.5, 0.5, 0.0, 0.0, 1.0, 0.0);
//該函數定義一個視圖矩陣,並與當前矩陣相乘。
//第一組eyex, eyey,eyez 相機(觀察者眼睛)在世界座標的位置
//第二組centerx,centery,centerz 相機鏡頭對準的物體在世界座標的位置(觀察者觀察的方向)
//第三組upx,upy,upz 相機向上的方向在世界座標中的方向
//http://www.cnblogs.com/chengmin/archive/2011/09/12/2174004.html
//to invert the image
glRotatef(ry,0,1,0);
glRotatef(rx-180,1,0,0);
float imageCenterX=w*.5;
float imageCenterY=h*.5;
float x,y,z;
glPointSize(1.0);
glBegin(GL_POINTS);//GL_POINTS
for (int i=0;i<h;i++){
for (int j=0;j<w;j++){
// color interpolation
glColor3f(imgdata[i][j]/255, 1-imgdata[i][j]/255, 1-imgdata[i][j]/255);//red,green,blue
x=((float)j-imageCenterX)/scalar;
y=((float)i-imageCenterY)/scalar;
z=(255-imgdata[i][j])/scalar;
glVertex3f(x,y,z);
}
}
glEnd();
glFlush();
}
void reshape (int w, int h) {
glViewport (0, 0, (GLsizei)w, (GLsizei)h);//set viewpoint
glMatrixMode (GL_PROJECTION);//specify which matrix is the current matrix
glLoadIdentity ();//replace the current matrix with the identity matrix
gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
glMatrixMode (GL_MODELVIEW);
}
void displayDisparity(IplImage* disparity){
//double xyscale=100;
int j=0;
int i=0;
CvScalar s;
//accessing the image pixels
for (i=0;i<h;i++){
for (j=0;j<w;j++){
s=cvGet2D(disparity,i,j); //獲取disparity圖像中座標爲(i,j)的像素點的值
imgdata[i][j]=s.val[0]; //s.val[0] 代表src圖像BGR中的B通道的值
//cout << imgdata[i][j]<<endl;
}
}
}
int main(int argc, char *argv[])
{
cout << "OpenCV and OpenGL works together!"<<endl;
//char* filename=argv[1];
//IplImage* imgGrey = cvLoadImage(filename,0);
//IplImage* imgGrey = cvLoadImage("fusimg.png",1); //第二個參數:1,顯示RGB;0,顯示gray;缺省爲1
IplImage* imgGrey = cvLoadImage("22.png",1);
if (imgGrey==NULL){
cout << "No valid image input."<<endl;
return 1;
}
w=imgGrey->width;
h=imgGrey->height;
displayDisparity(imgGrey);
cvNamedWindow("3D disparity image", CV_WINDOW_AUTOSIZE );
cvShowImage( "3D disparity image", imgGrey );
//------------------OpenGL-------------------------
glutInit(&argc, argv);//initialize the GLUT library
glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA); //設置初始化顯示模式
//GLUT_RGBA顏色模式;GLUT_SINGLE單緩存模式,GLUT_DEPTH深度緩存模式
//單緩衝,實際上就是將所有的繪圖指令在窗口上執行,就是直接在窗口上繪圖,這樣的繪圖效率是比較慢的,如果使用單緩衝,而電腦比較慢,你會看到屏幕的閃爍。
//雙緩衝,實際上的繪圖指令是在一個緩衝區完成,這裏的繪圖非常的快,在繪圖指令完成之後,再通過交換指令把完成的圖形立即顯示在屏幕上,這就避免了出現繪圖的不完整,同時效率很高。
//一般用OpenGL繪圖都是用雙緩衝,單緩衝一般只用於顯示單獨的一副非動態的圖像。
//深度緩衝:http://zh.wikipedia.org/wiki/%E6%B7%B1%E5%BA%A6%E7%BC%93%E5%86%B2
glutInitWindowPosition(600,200); //設置初始化窗口位置
glutInitWindowSize(640,480); //設置初始化窗口大小
glutCreateWindow("3D disparity image"); //創建窗口
glutDisplayFunc(renderScene);
//glutDisplayFunc函數用於註冊一個繪圖函數, 這樣操作系統在必要時刻就會對窗體進行重新繪製操作。類似於windows程序設計中處理WM_PAINT消息。
glutReshapeFunc (reshape);
//glutReshapeFunc瞭解:http://zhidao.baidu.com/link?url=K_GPs7mXbe6H1M_OA-YibtC7-1GNqv8efOKC_jMDxiK7kRSHt_zBzH5eIQaao0tK9RQGegwX2r_CH2N5nSsufK
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutSpecialFunc(special);
glutMainLoop(); //glutMainLoop進入GLUT事件處理循環,讓所有的與“事件”有關的函數調用無限循環。
//glutMainLoopEvent();
//cvWaitKey(0);
//release opencv stuff.
//system("pause");
cvReleaseImage(&imgGrey);
cvDestroyWindow("3D disparity image");
return 0;
}
要實現二維圖像的三維顯示,需要把相關的地方改一下。
RGB圖像,需要將數組定義爲3維數組。
float imgdata[480][640][3];
相關函數需要改一下:
void displayDisparity(IplImage* disparity){
//double xyscale=100;
int j=0;
int i=0;
CvScalar s;
//accessing the image pixels
for (i=0;i<h;i++){
for (j=0;j<w;j++){
s=cvGet2D(disparity,i,j); //獲取disparity圖像中座標爲(i,j)的像素點的值
//imgdata[i][j]=s.val[0]; //s.val[0] 代表src圖像BGR中的B通道的值
imgdata[i][j][2]=s.val[0];
imgdata[i][j][1]=s.val[1];
imgdata[i][j][0]=s.val[2];
//cout << imgdata[i][j]<<endl;
}
}
}
glColor3f(imgdata[i][j][0]/255, imgdata[i][j][1]/255, imgdata[i][j][2]/255);//red,green,blue
glBegin(GL_POINTS);//GL_POINTS
for (int i=0;i<h;i++){
for (int j=0;j<w;j++){
// color interpolation
//glColor3f(imgdata[i][j]/255, 1-imgdata[i][j]/255, 1-imgdata[i][j]/255);//red,green,blue
glColor3f(imgdata[i][j][0]/255, imgdata[i][j][1]/255, imgdata[i][j][2]/255);//red,green,blue
//三維圖像中各點座標的設置
x=((float)j-imageCenterX)/scalar; //x座標的設置
y=((float)i-imageCenterY)/scalar; //y座標的設置;以二維圖像的中心位置爲原點,旋轉時繞原點旋轉
z=(imgdata[i][j][1])/scalar; //設置z座標,<strong><span style="font-size:14px;color:#ff0000;">如果有掃描到的物體表面高度信息,可以在此處賦高度信息</span></strong>;此處以blue分量作爲z座標
/*z=(imgdata[i][j])/scalar;*/
glVertex3f(x,y,z); //座標視角函數
}
}
glEnd();
下圖旋轉了一定角度,可以看出blue分量值越大,Z座標值越大,blue的位置越靠前(右手座標系,Z正方向爲從電腦向人的指向)。