【 OpenGL】高斯模糊

阅读: 评论:0

【 OpenGL】高斯模糊

【 OpenGL】高斯模糊

[video(video-83qMkG9M-1628401078616)(type-bilibili)(url-.html?aid=762197327)(image-.png)(title-【opengl】高斯模糊)]

  • 高斯模糊原理
    高斯模糊(高斯滤波)的原理与算法
  • OpenGL环境搭建
    glut+glew+linux开发环境搭建
  • 实验效果:
    原图:


6+6次水平垂直高斯模糊效果:

12+12次水平垂直高斯模糊效果:

50+50次水平垂直高斯模糊效果:

  • gles中的算法实现:
#version 130out vec4 FragColor;
in vec2 TexCoords;uniform sampler2D image;uniform bool horizontal;uniform float weight[5] = float[] (0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);void main()
{     //模糊步长,最精细为像素级,补偿越小颗粒感越低,同时每次模糊的效果也越低        vec2 tex_offset = 2.0 / textureSize(image, 0); // gets size of single texelvec3 result = texture(image, TexCoords).rgb * weight[0]; // current fragment's contributionif(horizontal){for(int i = 1; i < 5; ++i){result += texture(image, TexCoords + vec2(tex_offset.x * i, 0.0)).rgb * weight[i];result += texture(image, TexCoords - vec2(tex_offset.x * i, 0.0)).rgb * weight[i];}}else{for(int i = 1; i < 5; ++i){result += texture(image, TexCoords + vec2(0.0, tex_offset.y * i)).rgb * weight[i];result += texture(image, TexCoords - vec2(0.0, tex_offset.y * i)).rgb * weight[i];}}FragColor = vec4(result, 1.0);
}

片段着色器中只是对所有像素乘以高斯核,完成一次水平或者垂直的模糊,要想控制模糊程度需要CPU代码进行多次模糊。
对应的顶点着色器程序:

#version 130
in vec3 aPos; // 位置变量的属性位置值为0
in vec3 aColor;
in vec2 aTexCoord;out vec3 ourColor;
out vec2 TexCoords;void main()
{gl_Position = vec4(aPos, 1.0);ourColor = aColor;TexCoords = vec2(aTexCoord.x, aTexCoord.y);
}
  • OpenGL乒乓离线帧缓存:
    参考:LearnOpenGL CN专栏 作者:JoeyDeVries
    基本思想是:申请两块帧缓存,第一次对原图纹理做一次水平高斯模糊,将结果放入其中一块帧缓存对应的纹理内存。第二次对上一步完成渲染纹理再做垂直高斯模糊,结果放入另一块纹理内存。如此交替进行,类似乒乓球过程,整个过程不进行显示双缓冲的交换,不会显示到屏幕,因此也叫离屏渲染。
    生成乒乓帧缓存片段:
	glGenFramebuffers(2, pingpongFBO);glGenTextures(2, pingpongBuffers);for (unsigned int i = 0; i < 2; i++){glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[i]);glBindTexture(GL_TEXTURE_2D, pingpongBuffers[i]);//大坑!!!这里的纹理尺寸需要与屏幕(视口)像素尺寸一致,当图片尺寸大于屏幕尺寸时,会导致纹理内存填不满glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL);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_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pingpongBuffers[i], 0);// also check if framebuffers are complete (no need for depth buffer)if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)std::cout << "Framebuffer not complete!" << std::endl;}

进行乒乓渲染片段:

void blur()
{GLboolean horizontal = true;GLboolean first_iteration = true;GLuint amount = 100;mshader.use();for (GLuint i = 0; i < amount; i++){glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[horizontal]); glUniform1i(glGetUniformLocation(mshader.ID, "horizontal"), horizontal);glBindTexture(GL_TEXTURE_2D, first_iteration ? texture1 : pingpongBuffers[!horizontal]); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);///*  测试单步效果glBindFramebuffer(GL_FRAMEBUFFER, 0);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);glutSwapBuffers();usleep(500 * 1000 );//*/horizontal = !horizontal;if (first_iteration)first_iteration = false;}//可以实现GPU渲染完成再返回,类似linux的barrier机制glFinish();
}

完整代码:
main.cpp

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"#include <shader.h>
#include <GL/glut.h>
#include <stdlib.h>#include <string>
#include <fstream>
#include <sstream>
#include <iostream>#include <unistd.h>
#include <sys/time.h>
#include<stdio.h>// settings
const unsigned int SCR_WIDTH = 960;
const unsigned int SCR_HEIGHT = 540;
static Shader mshader;
unsigned int texture1;
unsigned int VBO, VAO, EBO;
GLboolean horizontal = true;
GLuint pingpongFBO[2];
GLuint pingpongBuffers[2];void reshape(int w, int h);
void display();
void resourceready();
void blur();
int main(int argc, char **argv)
{#define MILLION 1000000struct timeval tv1,tv2;long sec,usec;glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);glutInitWindowPosition(100, 100);glutInitWindowSize(SCR_WIDTH, SCR_HEIGHT);glutCreateWindow("SHADER_RECTANGLE");glewInit();const GLubyte* name = glGetString(GL_VENDOR); //返回负责当前OpenGL实现厂商的名字const GLubyte* biaoshifu = glGetString(GL_RENDERER); //返回一个渲染器标识符,通常是个硬件平台const GLubyte* OpenGLVersion =glGetString(GL_VERSION); //返回当前OpenGL实现的版本号const GLubyte* GLESVersion =glGetString(GL_SHADING_LANGUAGE_VERSION); //返回当前OpenGL实现的版本号printf("OpenGL实现厂商的名字:%sn", name);printf("渲染器标识符:%sn", biaoshifu);printf("OpenGL实现的版本号:%sn",OpenGLVersion );printf("GLES语法的版本号:%sn",GLESVersion );mshader= Shader("shader.vs", "shader.fs"); resourceready();gettimeofday(&tv1, NULL);blur();gettimeofday(&tv2, NULL);sec = (tv2.tv_sec - tv1.tv_sec);usec = (tv2.tv_usec - tv1.tv_usec);std::cout << "---------tmie cost---------------" << sec <<"(s)  "<< usec<<"(us) " << std::endl;glutReshapeFunc(&reshape);glutDisplayFunc(&display);glutMainLoop();// optional: de-allocate all resources once they've outlived their purpose:// ------------------------------------------------------------------------//glDeleteVertexArrays(1, &VAO);//glDeleteBuffers(1, &VBO);//glDeleteBuffers(1, &EBO);return 0;
}void reshape(int w, int h)
{glViewport(0, 0,(GLsizei)w, (GLsizei)h);
}void resourceready()
{// set up vertex data (and buffer(s)) and configure vertex attributes// ------------------------------------------------------------------float vertices[] = {// positions          // colors           // texture coords1.0f,  1.0f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // top right1.0f, -1.0f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // bottom right-1.0f, -1.0f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left-1.0f,  1.0f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f  // top left };unsigned int indices[] = {  0, 1, 3, // first triangle1, 2, 3  // second triangle};glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1, &EBO);glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);// position attributeglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);// color attributeglVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);// texture coord attributeglVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));glEnableVertexAttribArray(2);// load and create a texture // -------------------------glGenTextures(1, &texture1);glBindTexture(GL_TEXTURE_2D, texture1); // all upcoming GL_TEXTURE_2D operations now have effect on this texture object// set the texture wrapping parametersglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);	// set texture wrapping to GL_REPEAT (default wrapping method)glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);// set texture filtering parametersglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// load image, create texture and generate mipmapsint width, height, nrChannels;stbi_set_flip_vertically_on_load(true);	unsigned char *data = stbi_load("1080.jpeg", &width, &height, &nrChannels, 0);if (data){glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);glGenerateMipmap(GL_TEXTURE_2D);std::cout << "texture1 width  " <<width << "  hight   " << height  <<"  nrChannels  " << nrChannels<< std::endl;}else{std::cout << "Failed to load texture" << std::endl;}stbi_image_free(data);glGenFramebuffers(2, pingpongFBO);glGenTextures(2, pingpongBuffers);for (unsigned int i = 0; i < 2; i++){glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[i]);glBindTexture(GL_TEXTURE_2D, pingpongBuffers[i]);//大坑!!!这里的纹理尺寸需要与屏幕(视口)像素尺寸一致,当图片尺寸大于屏幕尺寸时,会导致纹理内存填不满glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL);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_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pingpongBuffers[i], 0);// also check if framebuffers are complete (no need for depth buffer)if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)std::cout << "Framebuffer not complete!" << std::endl;}}void blur()
{GLboolean first_iteration = true;GLuint amount = 100;mshader.use();for (GLuint i = 0; i < amount; i++){glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[horizontal]); glUniform1i(glGetUniformLocation(mshader.ID, "horizontal"), horizontal);glBindTexture(GL_TEXTURE_2D, first_iteration ? texture1 : pingpongBuffers[!horizontal]); //std::cout << "---------------------------loop:" << i << std::endl;glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);///*  测试单步效果glBindFramebuffer(GL_FRAMEBUFFER, 0);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);glutSwapBuffers();usleep(500 * 1000 );//*/horizontal = !horizontal;if (first_iteration)first_iteration = false;}glFinish();
}void display()
{glBindFramebuffer(GL_FRAMEBUFFER, 0);// render// ------glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// bind TextureglActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, pingpongBuffers[!horizontal]);// render containermshader.use();glBindVertexArray(VAO);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);//glDisableVertexAttribArray(0);glutSwapBuffers();
}

依赖库:

stb_image.h下载
stb_image.h使用

实验步骤:

  1. 编译
    g++ main.cpp -o test -lGL -lglut -lGLEW -I.
  2. 对应目录放图片,命名1080.jpeg
  3. ./test
  4. 耗时情况:
OpenGL实现厂商的名字:VMware, Inc.
渲染器标识符:SVGA3D; build: RELEASE;  LLVM;
OpenGL实现的版本号:3.0 Mesa 18.0.5
GLES语法的版本号:1.30
texture1 width  1920  hight   1080  nrChannels  3
---------time cost---------------0(s)  72273(us) 

本文发布于:2024-01-28 06:29:35,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/17063945795464.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:高斯   模糊   OpenGL
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23