GLSL着色器实现高斯滤波代码

来源:互联网 发布:js table tbody 编辑:程序博客网 时间:2024/06/06 19:46

刚开始学习GLSL的时候,感觉非常痛苦,资料非常少是一个原因,更重要的原因就是没有现成的可运行的代码可以,后来在ARC公司实习花了一个月吧,终于对GLSL作为加速计算的方面的知识有了一定的了解。感谢ARC,感谢我的师傅兼师兄孙XX!

请不要将将此代码用于商业用途,如转载,请注明出处:http://blog.csdn.net/gningh/article/details/9615631

我所做的工作并不是用GLSL实现各种绚丽的图形渲染,而是用它做图像处理和加速运算。

这里有一些小的注意事项,

1.我们处理图像的时候一般是把图像载入纹理缓冲,当做纹理来处理,这样可以加快速度。

2.纹理坐标默认的是归一化的坐标形式,我们这里用的是原始的图像坐标,这样可以更加容易写代码。可以了解一下texture2DRect与textu2D的区别

3.代码中使用了一个LoadBMP函数,这个函数在<LoadBMP.h>中定义的。这个函数是公司的,所以我不能侵权把它贴出来,大家可以自己从网上搜索读取BMP的函数,一搜一大片,这个函数主要的目的就是取得BMP图像的数据的指针,而且这个函数功能有点弱,只能读取24位的BMP。

4.高斯模板我用的是


下面就是代码了:

// //#include "stdafx.h"#include <windows.h>#include <stdio.h>#include <stdlib.h>#include <GL/glew.h>#include <GL/glut.h>#include "LoadBMP.h"//纹理的编号static GLuint texture;    #define printOpenGLError() printOglError(__FILE__, __LINE__)//纹理图像的高和宽const GLint imgHeight = 512, imgWidth = 512;//顶点着色器const char *vShader = {"#version 110  \n ""void main()""{""gl_TexCoord[0] = gl_MultiTexCoord0;"    "gl_Position = ftransform();""}"};/***************片元着色器代码**************************注意代码中的pos变量代表的是实际的坐标,因为读入bmp图像的**数据后,数据是从下往上存放的,这里要将坐标纠正一下。加入\n**是为了在编译着色器代码时可以准确找到出错的行数,否则**显示的都是一行**********************************************************/const char *fShader = {"#version 100                                                       \n ""#extension GL_ARB_texture_rectangle : enable                       \n""const int KernelSize = 9;                                          \n""uniform vec2 Offset[KernelSize];                                   \n""uniform vec4 KernelValue[KernelSize];                              \n"    "uniform sampler2DRect  LenaTexture;                                \n""void main()                                                        \n""{                                                                  \n""vec2 pos = vec2(gl_TexCoord[0].s,512.0-gl_TexCoord[0].t);\n""int i;                                                         \n""vec4 sum = vec4(0.0);                                          \n""for ( i = 0; i < KernelSize; ++i )                             \n""{                                                        \n""   vec4 tmp = texture2DRect(LenaTexture,pos + Offset[i]);      \n""   sum += tmp * KernelValue[i];                                \n""}                                                              \n"         "gl_FragColor = sum;                                    \n""}                                                                  \n"};//打印错误信息int printOglError(char *file, int line){GLenum glErr;int retCode = 0;glErr = glGetError();while (glErr != GL_NO_ERROR){printf("glError in file %s @ line %d: %s\n", file, line, gluErrorString(glErr));retCode = 1;glErr = glGetError();}return retCode;}//打印openGL出错信息void printInfoLog(GLhandleARB obj){int infologLength = 0;int charsWritten = 0;GLcharARB *infoLog;printOpenGLError();glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infologLength);printOpenGLError();if(infologLength > 0){infoLog = (GLcharARB*)malloc(infologLength);if(infoLog == NULL){printf("ERROR: Could not allocate InfoLog buffer\n");exit(1);}glGetInfoLogARB(obj,infologLength,&charsWritten,infoLog);printf("InfoLog:\n%s\n\n",infoLog);free(infoLog);}printOpenGLError();}/*************************************************************function name:   initShadersinput:   1.    const char *vShaderCode,             2.     const char *fShaderCode,output:  1.    -1   compile error         2.    -2    link  error     3.     progHandle    description:编译连接并使用着色器程序,输入为上面定义的char*型数组             输出就是一个可用的着色器句柄,返回的句柄主要为了初始化 内置的uniform变量,检查内部错误的用途                  *****************************************************************/GLhandleARB initShaders( const char *vShaderCode, const char *fShaderCode )    //改为初始化的函数{GLhandleARB vertHandle, fragHandle, progHandle;   //对象句柄GLint vertCompiled, fragCompiled;//状态值GLint linked;//创建顶点着色器对象和片元着色器对象vertHandle = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);fragHandle = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);//将源代码字符串加载到着色器中glShaderSource( vertHandle, 1, &vShaderCode, NULL );glShaderSource( fragHandle, 1, &fShaderCode, NULL );printf("编译码块顶点着色器并打印编译器日志文件:\n");//编译码块顶点着色器并打印编译器日志文件glCompileShaderARB(vertHandle);printOpenGLError();//检查opengl错误glGetObjectParameterivARB(vertHandle,GL_OBJECT_COMPILE_STATUS_ARB, &vertCompiled);printInfoLog(vertHandle);printf("编译码块片元着色器并打印编译器日志文件:\n");//编译码块片元着色器并打印编译器日志文件glCompileShaderARB(fragHandle);printOpenGLError();             //检查opengl错误glGetObjectParameterivARB(fragHandle,GL_OBJECT_COMPILE_STATUS_ARB, &fragCompiled);printInfoLog(fragHandle);if(!vertCompiled || !fragCompiled)return -1;//创建一个程序对象并附加两个编译好的着色器progHandle = glCreateProgramObjectARB();glAttachObjectARB(progHandle, vertHandle);glAttachObjectARB(progHandle, fragHandle);printf("链接程序对象并打印信息日志:\n");//链接程序对象并打印信息日志glLinkProgramARB(progHandle);printOpenGLError();             //检查opengl错误glGetObjectParameterivARB(progHandle, GL_OBJECT_LINK_STATUS_ARB, &linked);printInfoLog(progHandle);if(!linked)return -2;//将程序对象安装为当前状态的一部分glUseProgramObjectARB(progHandle);     //改为运行的函数,用于测试该算法的时间    return progHandle;}//读入一个bmp图像作为纹理,对bmp图像的高斯滤波就是对这个纹理做滤波int LoadBmpAsTexture(char *textureFilePath, GLuint &texID ){unsigned char *pTexData = NULL;//指向数据的指针long bitCnt =  0;long iw =0;long ih = 0;long status = LoadBMP( textureFilePath, &pTexData,&iw, &ih, &bitCnt );    glGenTextures( 1, &texID );glBindTexture(GL_TEXTURE_RECTANGLE_ARB,texID);//当卷积内核超过了图像边界时使用图像边缘的像素值glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );//纹理过滤的方式不应该设置为线性插值glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_NEAREST);glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_NEAREST);glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, imgWidth, imgHeight,           0,GL_RGB,GL_UNSIGNED_BYTE,pTexData );    glTexEnvi( GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE );   return 0;}void init(){glShadeModel( GL_FLAT );glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );glViewport(0,0, imgWidth, imgHeight );glEnable ( GL_DEPTH_TEST );}void display( void ){glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );// glEnable( GL_TEXTURE_2D);//注意:要想使用着色器,一定不能激活纹理!!glBindTexture(GL_TEXTURE_2D,texture);//纹理坐标的设置glBegin( GL_QUADS );     glTexCoord2f( 0.0, 0.0);  glVertex2f( -1.0, -1.0);   glTexCoord2f( 0.0, imgHeight);  glVertex2f( -1.0, 1.0 );glTexCoord2f( imgWidth, imgHeight );  glVertex2f( 1.0, 1.0 );glTexCoord2f( imgWidth, 0.0 ); glVertex2f ( 1.0, -1.0 );glEnd( );glFlush();}void PerformComputation(){LoadBmpAsTexture("texture.bmp",texture );display();}int _tmain(int argc, char* argv[]){GLhandleARB progHandle = 0;//偏移数组float offset[18]={-1,-1,-1,0,1,1,-1,0,0,0,1,0,1,-1,1,0,1,1};//高斯核float kernelValue[36]={0.0625,0.0625,0.0625,0.0625,0.125,0.125,0.125,0.125,0.0625,0.0625,0.0625,0.0625,0.125,0.125,0.125,0.125,0.25,0.25,0.25,0.25,0.125,0.125,0.125,0.125,0.0625,0.0625,0.0625,0.0625,0.125,0.125,0.125,0.125,0.0625,0.0625,0.0625,0.0625};glutInit( &argc, argv );glutInitDisplayMode( GLUT_SINGLE| GLUT_LUMINANCE);glutInitWindowSize ( imgWidth, imgHeight);glutInitWindowPosition( 100, 100 );glutCreateWindow(" gningh高斯滤波  ");glewInit();init();progHandle = initShaders(vShader, fShader); if ( progHandle <= 0 )printf("Failed to run shader.\n");else{//设置初始一致变量glUniform1i( glGetUniformLocation( progHandle, "LenaTexture" ), 0 );   //0 是纹理的句柄glUniform4fv( glGetUniformLocation( progHandle, "KernelValue"),9,kernelValue);glUniform2fv( glGetUniformLocation( progHandle, "Offset"),9,offset);}PerformComputation();    glutMainLoop();return 0;}



处理前的图像为:


高斯滤波后的图像为:



其实高斯滤波的模板可以换为拉普拉斯的模板,均值的模板等等~~这样就可以并行处理图像了

原创粉丝点击