GLSL实现图像处理
来源:互联网 发布:保密式网络机柜 编辑:程序博客网 时间:2024/05/15 00:04
今天晚上没事将以前弄的OPENGL着色语言实现滤镜效果的实现和大家分享一下,滤镜主要包括图像的对比度调整、浮雕效果、彩色图片灰度化、卷积等操作。
这些操作其本质上是属于图像处理的东西,OpenGL实现图像处理主要是用到了GLSL着色语言。具体到着色器就是片段着色器。
说白了就是如何用OpenGL做通用GPU计算,OpenGL做通用计算的步骤主要如下:
读取数据->顶点着色器->片段着色器->渲染到纹理->从纹理读写数据。
步骤具体细化如下:
(1)初始化。
初始化窗口系统。
void InitGLUT(int argc,char**argv)
{
glutInit(&argc,argv);
glutWindow = glutCreateWindow("GPGPU");
}
初始化FBO。在此阶段还需要将投影设置为正摄投影的方式,视口与图像的幅宽一样大,并且还要讲纹理重采样方式设置为最邻近采样,这样就保证了片段操作的时候取得每个数据都是原始数据。
void InitFBO(int nWidth,intnHeight,GLuint*pFb)
{
//创建FBO并绑定
glewInit();
GLuint fb;
glGenFramebuffersEXT(1,&fb);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fb);
*pFb = fb;
//用绘制来调用
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,nWidth,0,nHeight);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0,0,nWidth,nHeight);
}
初始化shader,包括从文件中读取数据以及编译等操作。
void InitGLSL()
{
//创建顶点shader
vertShader = glCreateShader(GL_VERTEX_SHADER);
if( 0 == vertShader)
{
fprintf(stderr,"Error creating vertex shader.\n");
exit(1);
}
GLint result;
//加载片元着色器
fragShader = glCreateShader(GL_FRAGMENT_SHADER);
if( 0 == fragShader)
{
fprintf(stderr,"片元着色器创建失败.\n");
exit(1);
}
//c拷贝shader源码
const GLchar *shaderCode2 = loadShaderAsString("BrightNess.glsl");
glShaderSource( fragShader,1, &shaderCode2, NULL );
delete []shaderCode2;
//编译shader
glCompileShader(fragShader);
//检查编译状态
glGetShaderiv( fragShader,GL_COMPILE_STATUS, &result );
if (GL_FALSE ==result)
{
fprintf( stderr,"片元着色器编译失败!\n" );
GLint logLen;
glGetShaderiv( fragShader,GL_INFO_LOG_LENGTH, &logLen );
if( logLen > 0)
{
char * log = (char *)malloc(logLen);
GLsizei written;
glGetShaderInfoLog(fragShader,logLen, &written,log);
fprintf(stderr,"Shaderlog:\n%s",log);
free(log);
}
}
//创建程序对象
programHandle = glCreateProgram();
if( 0 == programHandle)
{
fprintf(stderr,"Error creating program object.\n");
exit(1);
}
//将着色器链接到程序对象
glAttachShader(programHandle,fragShader);
//链接程序
glLinkProgram(programHandle);
//检查链接状态
GLint status;
glGetProgramiv( programHandle,GL_LINK_STATUS, &status );
if( GL_FALSE == status )
{
fprintf( stderr,"链接失败!\n" );
GLint logLen;
glGetProgramiv(programHandle,GL_INFO_LOG_LENGTH,
&logLen);
if( logLen > 0)
{
char * log = (char *)malloc(logLen);
GLsizei written;
glGetProgramInfoLog(programHandle,logLen,
&written, log);
fprintf(stderr,"Program log: \n%s",log);
free(log);
}
glDeleteProgram(programHandle);
}
else
{
glUseProgram(programHandle);
}
}
(2)创建纹理对象以及设置参数
这里需要创建两个纹理对象,一个用于输入图像,另外一个用于保存输出的结果,即将保存结果的纹理对象绑定到帧缓存对象上,即实现渲染到纹理的目标。
//创建纹理对象并绑定
GLuint xTexID,yTexID;
glGenTextures(1,&xTexID);
glGenTextures(1,&yTexID);
设置纹理属性如下:
void SetupTexture(stTextureParatextureParameters,constGLuinttexID,intnWidth,int nHeight)
{
glBindTexture(textureParameters.texTarget,texID);
//设置纹理参数
glTexParameteri(textureParameters.texTarget,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(textureParameters.texTarget,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(textureParameters.texTarget,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(textureParameters.texTarget,GL_TEXTURE_WRAP_T,GL_CLAMP);
//定义纹理数据单元类型
glTexImage2D(textureParameters.texTarget,0,textureParameters.texInternalFormat,nWidth,nHeight,0,
textureParameters.texFormat,GL_FLOAT,0);
}
然后将输入数据加载到输入纹理缓存上面
//传入输入数据
glBindTexture(textureParameters.texTarget,xTexID);
glTexSubImage2D(textureParameters.texTarget,0,0,0,nWidth,nHeight,textureParameters.texFormat,GL_FLOAT,pfInput);
//设置映射参数,替换原来的数据
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
最后是将输出纹理绑定到帧缓存对象上并激活输入纹理对象。
//绑定输出纹理缓存
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,textureParameters.texTarget,yTexID,0);
//激活当前输入的纹理单元
glActiveTexture(GL_TEXTURE0);
绑定的关联点就是GL_COLOR_ATTACHMENT0_EXT,它代表是帧缓存中的一个颜色缓存。
(3)设置渲染的对象
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
glPolygonMode(GL_FRONT,GL_FILL);
(4)通过绘制来调用“核函数”
这里是一个形象的比喻,就是通过绘制操作来实现对图像的处理,类似于CUDA和opencl里面的核函数调用。
//用绘制进行调用
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex2f(0,0);
glTexCoord2f(nWidth,0);
glVertex2f(nWidth,0);
glTexCoord2f(nWidth,nHeight);
glVertex2f(nWidth,nHeight);
glTexCoord2f(0,nHeight);
glVertex2f(0,nHeight);
glEnd();
glFinish();
(5)读取结果数据以及进一步处理
//从当前纹理缓存拷贝数据
void TransformFromTex(intnWidth,intnHeight,float *pfData)
{
//读取数据
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glReadPixels(0,0,nWidth,nHeight,GL_RGB,GL_FLOAT,pfData);
}
这相当于将数据从显存拷贝到主机内存,然后可以写入文件等。
说了这么多,最后还剩下一个片段着色器的编写。上面相当于把框架已经搭建好,然后只需要更改片段着色器实现不同的图像处理效果了。
这边就以一副风景画为例子实现集中不同的效果。
原图如下:
1、对比度调整,代码如下:
- #version 400 compatibility
- #extension GL_ARB_texture_rectangle : enable
- uniform sampler2DRect uImageUint;
- float uT = 0.5;
- out vec4 outColor;
- //图像对比度增强
- void main()
- {
- vec2 pos = gl_TexCoord[0].st;
- vec3 irgb = texture(uImageUint,pos).rgb;
- //vec3 target = vec3(128.0,128.0,128.0);
- vec3 target = vec3(0.0,0.0,0.0);
- outColor = vec4(mix(target,irgb,uT),1.0);
- }
处理后效果如下:
2、浮雕效果代码如下:
- #version 400 compatibility
- #extension GL_ARB_texture_rectangle : enable
- uniform sampler2DRect tex;
- out vec4 outColor;
- //浮雕效果
- void main()
- {
- vec2 pos = gl_TexCoord[0].st;
- //获得纹理的尺寸
- ivec2 vecSize = textureSize(tex);
- float ResS = float(vecSize.s);
- float ResT = float(vecSize.t);
- vec3 irgb = texture(tex,pos).rgb;
- vec2 stpp = vec2(-1.0,-1.0);
- vec3 c00 = texture(tex,pos).rgb;
- vec3 cp1p1 = texture(tex,pos+stpp).rgb;
- vec3 diffs = c00 - cp1p1;
- float maxV = diffs.r;
- if(abs(diffs.g) > abs(maxV)) maxV = diffs.g;
- if(abs(diffs.b) > abs(maxV)) maxV = diffs.b;
- float gray = clamp(maxV + 128,0.0,255.0);
- outColor = vec4(gray,gray,gray,1.0);
- }
3、颠倒显示
- #version 400 compatibility
- #extension GL_ARB_texture_rectangle : enable
- uniform sampler2DRect tex;
- out vec4 outColor;
- //图像翻转效果
- void main()
- {
- vec2 pos = gl_TexCoord[0].st;
- //获得纹理的尺寸
- ivec2 vecSize = textureSize(tex);
- int nWidth = (vecSize.s);
- int nHeight = (vecSize.t);
- pos = vec2(nWidth- pos.x-1,nHeight - pos.y - 1);
- vec3 irgb = texture(tex,pos).rgb;
- outColor = vec4(irgb,1.0);
- }
处理后效果如下:
- #version 400 compatibility
- #extension GL_ARB_texture_rectangle : enable
- uniform sampler2DRect tex;
- const vec3 W = vec3(0.2125,0.7154,0.0721);
- out vec4 outColor;
- void main()
- {
- vec2 pos = gl_TexCoord[0].st;
- vec3 color = texelFetch(tex,ivec2(pos.x+0.5,pos.y+0.5)).rgb;
- float luminace = dot(color,W);
- outColor = vec4(luminace,luminace,luminace,1.0);
- //gl_FragColor = fResult;
- }
5、图像的卷积,这个稍微复杂一点,其实也很简单,基本图像处理的东西。
- #version 400 compatibility
- #extension GL_ARB_texture_rectangle : enable
- uniform sampler2DRect tex;
- float fRadius = 2;
- out vec4 outColor;
- void main()
- {
- vec2 pos = gl_TexCoord[0].st;
- vec4 fSum = vec4(0.0,0.0,0.0,0.0);
- vec4 fTotal = vec4(0.0,0.0,0.0,0.0);
- vec4 fResult = vec4(0.0,0.0,0.0,0.0);
- ivec2 vecSize = textureSize(tex);
- for (float i = pos.x - fRadius; i < pos.x + fRadius + 0.5; i += 1.0)
- for (float j = pos.y - fRadius; j < pos.y + fRadius + 0.5; j += 1.0)
- {
- if (i >=0 && j >= 0 && i < vecSize.x && j < vecSize.y)
- {
- fSum += texture2DRect(tex,vec2(i+0.5,j+0.5));
- fTotal += vec4(1.0,1.0,1.0,1.0);
- }
- }
- vec4 color = texelFetch(tex,ivec2(pos.x+0.5,pos.y+0.5));
- fResult = fSum/fTotal;
- outColor = fResult;
- //gl_FragColor = fResult;
- }
- GLSL实现图像处理
- GLSL实现图像处理
- GLSL实现图像处理
- GLSL实现图像处理
- GLSL 图像处理
- glsl实现图像2DFFT
- Shader特效——“Voronoi 图像”的实现 【GLSL】
- 图像处理qt实现
- MapReduce实现图像处理
- GLSL核心课程---纹理图像
- GLSL核心课程---纹理图像
- GLSL实现Glow效果
- GLSL实现Ambient Occlusion
- GLSL实现Image Filter
- GLSL实现HDR Rendering
- GLSL实现Interactive Fluid
- GLSL实现Glow效果
- GLSL实现Ambient Occlusion
- 幸福取决于有意识的思维方式
- 题目1198:a+b(九度OJ)
- CSS3中惊艳的gradient
- 题目1206:字符串连接(九度OJ)
- linux_查找相同文件名的文件批量删除
- GLSL实现图像处理
- 题目1196:成绩排序
- linux_rm -rf删除文件夹
- Aix ibm linux详解
- 第一个Python脚本之:Hello World
- 咪蒙:所谓情商高,就是懂得好好说话
- SUSE 11 sp3 下安装异系统共享Samba服务
- 基于物理的渲染 – 实现篇
- 浏览器缓存机制剖析http