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

刚开始学习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:   initShaders
input:   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;
}



处理前的图像为:


高斯滤波后的图像为:



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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值