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

在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. 远离“精神乞丐”(IBM的前CEO郭士纳把员工分为四种类型)

    语音丨吴伯凡 乞丐与其说是一种身份, 不如说是一种精神状态, 习惯性索取且心安理得, 习惯性寻求安慰,习惯性抱怨, 与之截然对立的, 是“操之在我”(Proactive)的精神, 乞丐型员工是公司内部 ...

  2. php模拟post提交文件图片等

    <?php /** * Email net.webjoy@gmail.com * author jackluo * 2014.11.21 * */ //* function curl_post( ...

  3. C#生成6位随机验证码

    private string VerifyCode() { Random random = new Random(); , ).ToString(); }

  4. hibernate级联保存问题

    异常:org.hibernate.TransientObjectException: object references an unsaved transient instance 解决方法: XML ...

  5. <Linux> Xen虚拟机镜像的安装

    了解系统安装在哪个磁盘上:fdisk -l 建立存放虚拟机镜像的目录:mkdir /mnt/vmx 更改文件系统格式: mkfs -t ext4 /dev/sda或者/dev/sdb(系统不在的那个硬 ...

  6. zzuli OJ 1128: 课程平均分

    Description 期末考试结束,班主任拿到了本班学生的成绩汇总表.由m行n列组成(本班共同拥有m名学生,本学期有n门课程),每行是一个同学的n门课程成绩,请编敲代码,计算并输出每门课的平均分.结 ...

  7. [CSS] Change the auto-placement behaviour of grid items with grid-auto-flow

    We can change the automatic behaviour of what order our grid items appear. We can even re-order the ...

  8. 忙里偷闲( ˇˍˇ )闲里偷学【C语言篇】——(3)输入输出函数

    一.基本的输入和输出函数的用法 1.printf()  //屏幕输出 用法: (1)printf("字符串\n"); (2)printf("输出控制符", 输出 ...

  9. 【9102】&&【a102】求a/b的高精度值

    Time Limit: 10 second Memory Limit: 2 MB 问题描述 计算a/b的精度值,设a,b以一般整数输入,计算结果精确到小数后20位(结果四舍五入). Input 文件输 ...

  10. Java数组定义学习的一些随笔

    //一维数组的定义 int[] arr1 = new int[3];//arr1 = {1,2,3}: 错误 int[] arr2 = new int[]{1,2,3};//int[] arr2 = ...