zoukankan      html  css  js  c++  java
  • OpenGL(十五) OpenCV+OpenGL实现水面倒影


    有两幅原始图片,一个是景物图像,一个是水面图像,尝试生成景物在水中的倒影:






    在OpenGL中,加载并显示这个景物图像可以把这个图像作为纹理载入即可,把图像直接选择180度的效果就相当于是在镜面中倒影的效果,剩下水纹的效果本来也想作为纹理叠加上去的,但是试了一下没有成功,干脆直接把水面和景物先融合一下,作为倒影的图像,一次加入到倒影平面的纹理中。融合使用了OpenCV。


    OpenCV两幅图像融合代码:

    #include "core/core.hpp"  
    #include "highgui/highgui.hpp"  
    #include "imgproc/imgproc.hpp"  
    #include <iostream>  
    
    using namespace cv;  
    
    Mat image,image1,image2;  
    char* windowName="Image Fusion";  
    char* trackBarName="TrackBar";  
    int trackBarValue=0;  
    int trackBarMax=50;  
    
    //控制条回调函数  
    void TrackBarFunc(int ,void(*));  
    int main(int argc,char *argv[])  
    {  
    	image1=imread("shanghai.bmp");  
    	image2=imread("water.bmp");  
    	//判断读入是否成功  
    	if(!image1.data|!image2.data)  
    	{  
    		std::cout<<"打开图片失败,请检查路径!"<<std::endl;  
    		return 0;  
    	}  
    	//调整image2的大小与image1的大小一致,融合函数addWeighted()要求输入的两个图形尺寸相同  
    	resize(image2,image2,Size(image1.cols,image1.rows));  
    	//建立显示窗口  
    	namedWindow(windowName,0);  
    	//在图像窗口上创建控制条  
    	createTrackbar(trackBarName,windowName,&trackBarValue,trackBarMax,TrackBarFunc);  
    	TrackBarFunc(0,0);  
    	waitKey(); 
    	imwrite("E:\water.bmp",image);
    	return 0;  
    }  
    void TrackBarFunc(int ,void(*))  
    {  
    	//转换成融合比例  
    	float rate=(float)trackBarValue/trackBarMax;  
    	addWeighted(image1,rate,image2,1-rate,0,image);  
    	//	namedWindow(windowName,0);
    	imshow(windowName,image);     
    }  


    调节水面图像和景物图像的融合比例:



    最后选的这一张作为倒影纹理:





    使用OpenGL把这两幅图像作为纹理载入,实现倒影效果,OpenGL代码:


    #define WindowWidth  600  
    #define WindowHeight 600  
    #define WindowTitle  "OpenGL水面倒影"  
    
    #include <glut.h>  
    #include <stdio.h>  
    #include <stdlib.h>  
    
    //定义两个纹理对象编号  
    GLuint shanghai;  
    GLuint water;  
    
    #define BMP_Header_Length 54  //图像数据在内存块中的偏移量  
    
    
    // 函数power_of_two用于判断一个整数是不是2的整数次幂  
    int power_of_two(int n)  
    {  
    	if( n <= 0 )  
    		return 0;  
    	return (n & (n-1)) == 0;  
    }  
    
    /* 函数load_texture 
    * 读取一个BMP文件作为纹理 
    * 如果失败,返回0,如果成功,返回纹理编号 
    */  
    GLuint load_texture(const char* file_name)  
    {  
    	GLint width, height, total_bytes;  
    	GLubyte* pixels = 0;  
    	GLuint last_texture_ID=0, texture_ID = 0;  
    
    	// 打开文件,如果失败,返回  
    	FILE* pFile = fopen(file_name, "rb");  
    	if( pFile == 0 )  
    		return 0;  
    
    	// 读取文件中图象的宽度和高度  
    	fseek(pFile, 0x0012, SEEK_SET);  
    	fread(&width, 4, 1, pFile);  
    	fread(&height, 4, 1, pFile);  
    	fseek(pFile, BMP_Header_Length, SEEK_SET);  
    
    	// 计算每行像素所占字节数,并根据此数据计算总像素字节数  
    	{  
    		GLint line_bytes = width * 3;  
    		while( line_bytes % 4 != 0 )  
    			++line_bytes;  
    		total_bytes = line_bytes * height;  
    	}  
    
    	// 根据总像素字节数分配内存  
    	pixels = (GLubyte*)malloc(total_bytes);  
    	if( pixels == 0 )  
    	{  
    		fclose(pFile);  
    		return 0;  
    	}  
    
    	// 读取像素数据  
    	if( fread(pixels, total_bytes, 1, pFile) <= 0 )  
    	{  
    		free(pixels);  
    		fclose(pFile);  
    		return 0;  
    	}  
    
    	// 对就旧版本的兼容,如果图象的宽度和高度不是的整数次方,则需要进行缩放  
    	// 若图像宽高超过了OpenGL规定的最大值,也缩放  
    	{  
    		GLint max;  
    		glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);  
    		if( !power_of_two(width)  
    			|| !power_of_two(height)  
    			|| width > max  
    			|| height > max )  
    		{  
    			const GLint new_width = 1024;  
    			const GLint new_height = 1024; // 规定缩放后新的大小为边长的正方形  
    			GLint new_line_bytes, new_total_bytes;  
    			GLubyte* new_pixels = 0;  
    
    			// 计算每行需要的字节数和总字节数  
    			new_line_bytes = new_width * 3;  
    			while( new_line_bytes % 4 != 0 )  
    				++new_line_bytes;  
    			new_total_bytes = new_line_bytes * new_height;  
    
    			// 分配内存  
    			new_pixels = (GLubyte*)malloc(new_total_bytes);  
    			if( new_pixels == 0 )  
    			{  
    				free(pixels);  
    				fclose(pFile);  
    				return 0;  
    			}  
    
    			// 进行像素缩放  
    			gluScaleImage(GL_RGB,  
    				width, height, GL_UNSIGNED_BYTE, pixels,  
    				new_width, new_height, GL_UNSIGNED_BYTE, new_pixels);  
    
    			// 释放原来的像素数据,把pixels指向新的像素数据,并重新设置width和height  
    			free(pixels);  
    			pixels = new_pixels;  
    			width = new_width;  
    			height = new_height;  
    		}  
    	}  
    
    	// 分配一个新的纹理编号  
    	glGenTextures(1, &texture_ID);  
    	if( texture_ID == 0 )  
    	{  
    		free(pixels);  
    		fclose(pFile);  
    		return 0;  
    	}  
    
    	// 绑定新的纹理,载入纹理并设置纹理参数  
    	// 在绑定前,先获得原来绑定的纹理编号,以便在最后进行恢复  
    	GLint lastTextureID=last_texture_ID;  
    	glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastTextureID);  
    	glBindTexture(GL_TEXTURE_2D, texture_ID);  
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);  
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);  
    	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);  
    	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,  
    		GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);  
    	glBindTexture(GL_TEXTURE_2D, lastTextureID);  //恢复之前的纹理绑定  
    	free(pixels);  
    	return texture_ID;  
    }  
    
    
    void display(void)  
    {  
    	// 清除屏幕  
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  
    	// 设置视角  
    	glMatrixMode(GL_PROJECTION);  
    	glLoadIdentity();  
    	gluPerspective(70, 1, 1, 21);  
    	glMatrixMode(GL_MODELVIEW);  
    	glLoadIdentity();  
    	gluLookAt(0, 7,-1.5, 0, 0, 0, 0, 0, -1);    
    
    	// 绘制倒影
    	glBindTexture(GL_TEXTURE_2D, water);  
    	glBegin(GL_QUADS);  
    	glTexCoord2f(0.0f, 0.0f); glVertex3f(-6.0f, -3.0f, 0.0f);  
    	glTexCoord2f(0.0f, 1.0f); glVertex3f(-6.0f, -3.0f, 5.0f);  
    	glTexCoord2f(1.0f, 1.0f); glVertex3f(6.0f, -3.0f, 5.0f);  
    	glTexCoord2f(1.0f, 0.0f); glVertex3f(6.0f, -3.0f, 0.0f);  
    	glEnd(); 
    
    	//绘制真实场景
    	glBindTexture(GL_TEXTURE_2D, shanghai);  
    	glTranslatef(0,-6,0);
    	glRotatef(180,1,0,0);
    	glBegin(GL_QUADS);  
    	glTexCoord2f(0.0f, 0.0f); glVertex3f(-6.0f, -3.0f, 0.0f);  
    	glTexCoord2f(0.0f, 1.0f); glVertex3f(-6.0f, -3.0f, 5.0f);  
    	glTexCoord2f(1.0f, 1.0f); glVertex3f(6.0f, -3.0f, 5.0f);  
    	glTexCoord2f(1.0f, 0.0f); glVertex3f(6.0f, -3.0f, 0.0f);  
    	glEnd();  
    
    	glutSwapBuffers();    
    }  
    
    int main(int argc, char* argv[])  
    {  
    	// GLUT初始化  
    	glutInit(&argc, argv);  
    	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);  
    	glutInitWindowPosition(100, 100);  
    	glutInitWindowSize(WindowWidth, WindowHeight);  
    	glutCreateWindow(WindowTitle);    
    	glEnable(GL_DEPTH_TEST);      
    	glEnable(GL_TEXTURE_2D);    // 启用纹理  
    	shanghai = load_texture("shanghai.bmp");  //加载纹理  
    	water= load_texture("water.bmp");  
    	glutDisplayFunc(&display);   //注册函数     
    	glutMainLoop(); //循环调用  
    	return 0;  
    }  


    这个是没有使用倒影的效果:



    倒影效果:





  • 相关阅读:
    HTML元素解释
    Java命名规范
    HDU 1058 Humble Numbers(DP,数)
    HDU 2845 Beans(DP,最大不连续和)
    HDU 2830 Matrix Swapping II (DP,最大全1矩阵)
    HDU 2870 Largest Submatrix(DP)
    HDU 1421 搬寝室(DP)
    HDU 2844 Coins (组合背包)
    HDU 2577 How to Type(模拟)
    HDU 2159 FATE(二维完全背包)
  • 原文地址:https://www.cnblogs.com/mtcnn/p/9411912.html
Copyright © 2011-2022 走看看