OpenGL(十五) OpenCV+OpenGL实现水面倒影

    xiaoxiao2021-08-15  136

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

    在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://ju.6miu.com/read-676394.html

    最新回复(0)