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


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



倒影效果:





转载于:https://www.cnblogs.com/mtcnn/p/9411912.html

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值