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正方向为从电脑向人的指向)。

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页