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

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

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

倒影效果:

OpenGL(十五) OpenCV+OpenGL实现水面倒影的更多相关文章

  1. NeHe OpenGL教程 第四十五课:顶点缓存

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  2. NeHe OpenGL教程 第三十五课:播放AVI

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  3. NeHe OpenGL教程 第二十五课:变形

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  4. NeHe OpenGL教程 第十五课:纹理图形字

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  5. OpenCV开发笔记(六十五):红胖子8分钟带你深入了解ORB特征点(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  6. OpenCV+OpenGL 双目立体视觉三维重建

    0.绪论 这篇文章主要为了研究双目立体视觉的最终目标--三维重建,系统的介绍了三维重建的整体步骤.双目立体视觉的整体流程包括:图像获取,摄像机标定,特征提取(稠密匹配中这一步可以省略),立体匹配,三维 ...

  7. 【OpenCV新手教程之十五】水漫金山:OpenCV漫水填充算法(Floodfill)

    本系列文章由@浅墨_毛星云 出品,转载请注明出处.    文章链接: http://blog.csdn.net/poem_qianmo/article/details/28261997 作者:毛星云( ...

  8. Android平台OpenGL ES/Assimp/OpenCV/GLM集成说明

    Android平台OpenGL ES/Assimp/OpenCV/GLM集成说明 本文代码见: https://github.com/jiangxincode/OpenGLDemo 集成Assimp ...

  9. 深入理解OpenGL拾取模式(OpenGL Picking)

    深入理解OpenGL拾取模式(OpenGL Picking) 本文转自:http://blog.csdn.net/zhangci226/article/details/4749526 在用OpenGL ...

  10. Coding and Paper Letter(十五)

    资源整理. 1.Nature Climate Change论文"Higher temperatures increase suicide rates in the United States ...

随机推荐

  1. Win10安装后必做的优化,解决磁盘100%占用

    Win10安装后必做的优化,解决磁盘100%占用 01关闭家庭组 控制面板–管理工具–服务– HomeGroup Listener和HomeGroup Provider禁用. 02关闭磁盘碎片整理.自 ...

  2. Json入门 分类: C_OHTERS 2014-04-23 16:20 601人阅读 评论(0) 收藏

    参考<疯狂android讲义>>730页 JSON的基础请参考W3SCHOOL的教程: http://www.w3school.com.cn/json/index.asp 例子: h ...

  3. js导出报表

    原文链接:https://blog.csdn.net/qq_37936542/article/details/78376156 需求:项目中有一个学生签到模块需要导出每天的签到数据,一开始用poi在后 ...

  4. 博客搬家啦! -----> http://ronghaopger.github.io/

    新地方: http://ronghaopger.github.io/ 以后这里就不更新了,感谢博客园!

  5. jsvc 启动java 在linux下的实现原理

    http://blog.csdn.net/raintungli/article/details/8265009 JSVC:http://commons.apache.org/proper/common ...

  6. Android使用READ_CONTACTS读取手机联系人

    实例代码: package com.example.readcontacts; import java.io.InputStream; import java.util.ArrayList; impo ...

  7. 【codeforces 546E】Soldier and Traveling

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  8. spring security之httpSecurity 专题

    37.5.2 Resolving the CsrfToken Spring Security provides CsrfTokenArgumentResolver which can automati ...

  9. win10下安装docker步骤(一)

    一.启用Hyper-V 打开控制面板 - 程序和功能 - 启用或关闭Windows功能,勾选Hyper-V,然后点击确定即可,如图: 请注意电脑默认的Hyper-V虚拟机监控程序是不能进行勾选的,需要 ...

  10. module.exports输出的属性被ES6如何引用的

    阮一峰的ES6教程里有讲: import 命令加载 CommonJS 模块 Node 采用 CommonJS 模块格式,模块的输出都定义在module.exports这个属性上面.在 Node 环境中 ...