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;  
    }  


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



    倒影效果:





  • 相关阅读:
    使用EntityFramework之Code First开发与MySql数据库问题一例
    使用Emit创建DBContext对象
    一个实用的Metro滚屏效果示例
    合理使用EntityFramework数据验证的异常错误提示信息
    Metro app中使用内存流压缩和解压
    64位的windows操作系统上运行32位asp.net web应用程序的时候,出现试图加载格式不正确的程序的解决方法
    VSTO中自定义XML功能区实现Ribbon控件互相更新
    基于任务并行库实现多线程下载示例
    Android系统刷机成功后网络信号显示“无服务”修正
    Solution Explorer中显示依赖文件和链接文件
  • 原文地址:https://www.cnblogs.com/mtcnn/p/9411912.html
Copyright © 2011-2022 走看看