OpenGL將二維圖形顯示爲三維點雲圖

全文參考: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正方向爲從電腦向人的指向)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章