天天看點

opengl 使用shader對圖像進行銳化處理

在之前的部落格中

opengl 在顯示的YUV視訊序列上畫多個框

如果我們要對輸入的視訊内容做一個銳化處理,或者其他特效,在shader中如何處理呢?

完整code如下,看到code就明白其中的道理了,還是很簡單的。

// VideoPlayer.cpp : Defines the entry point for the console application.
//
#include <stdio.h>

#include <GLTools.h>	// OpenGL toolkit
#include <GLShaderManager.h>

#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

#include <GL/glew.h>
#include <GL/freeglut.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>


//macro to write shader programs inline
#ifndef GLSL
#define GLSL(version, A) "#version " #version "\n" #A
#endif

//Select one of the Texture mode (Set '1'):
#define TEXTURE_DEFAULT   0
//Rotate the texture
#define TEXTURE_ROTATE    0
//Show half of the Texture
#define TEXTURE_HALF      1

const int screen_w = 640, screen_h = 480;
const int pixel_w = 640, pixel_h = 480;
//YUV 422 file
FILE *infile = NULL;
unsigned char buf[pixel_w*pixel_h * 2];
unsigned char *plane[3];


GLuint p;
GLuint id_y, id_u, id_v; // Texture id
GLuint textureUniformY, textureUniformU, textureUniformV;


GLShaderManager	shaderManager;
GLBatch	squareBatch;
GLBatch	squareBatch_v2;
GLfloat blockSize = 0.2f;
GLfloat vVerts[] = {
	-blockSize, -blockSize, 0.0f,
	blockSize, -blockSize, 0.0f,
	blockSize, blockSize, 0.0f,
	-blockSize, blockSize, 0.0f };

GLfloat blockSize_v2 = 0.3f;
GLfloat vVerts_v2[] = {
	-blockSize_v2, -blockSize_v2, 0.0f,
	blockSize_v2, -blockSize_v2, 0.0f,
	blockSize_v2, blockSize_v2, 0.0f,
	-blockSize_v2, blockSize_v2, 0.0f };


void add_rect_roi()
{

	GLfloat vRed[] = { 0.9f, 0.0f, 0.9f, 0.8f };
	//glEnable(GL_DEPTH_TEST);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	//glBlendFunc(GL_ZERO, GL_ZERO);
	shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
	squareBatch.Draw();
	glDisable(GL_BLEND);
}

void test_line()
{
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glLineWidth(5);
	//glBegin(GL_LINES);
	glBegin(GL_LINE_STRIP);
	//glBegin(GL_LINE_LOOP);
	glVertex3f(-0.4, 0.5, 0.0f);
	glVertex3f(0.4, 0.5, 0.0f);
	glVertex3f(-0.4, -0.5, 0.0f);
	glVertex3f(0.4, -0.5, 0.0f);
	glEnd();


	glLineWidth(10);
	glColor3f(0.0, 0.7, 0.0);
	glBegin(GL_LINE_STRIP);
	//glVertex3f(-0.4, 0.5, 0.0f);
	glVertex3f(0.4, 0.5, -0.5f);
	glVertex3f(-0.4, -0.5, -0.5f);
	glVertex3f(0.2, -0.5, -0.5f);
	glEnd();


	glDisable(GL_BLEND);
}


void add_rect_roi_v2()
{
	GLfloat vColor[] = { 0.0f, 1.0f, 0.9f, 0.5f };

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vColor);
	squareBatch_v2.Draw();

	glBegin(GL_TRIANGLES);
	glVertex3f(-0.5f, 0.0f, 0.0f);
	glVertex3f(-0.0f, 0.5f, 0.0f);
	glVertex3f(0.5f, 0.0f, 0.0f);

	glEnd();

	glDisable(GL_BLEND);
}


#define ATTRIB_VERTEX 3
#define ATTRIB_TEXTURE 4

void display(void)
{
	if (fread(buf, 1, pixel_w*pixel_h *  2, infile) != pixel_w*pixel_h * 2)
	{
		// Loop
		fseek(infile, 0, SEEK_SET);
		fread(buf, 1, pixel_w*pixel_h * 2, infile);
	}
	//add_rect_roi();
	//Clear
	glClearColor(255, 0, 0, 0.5f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glUseProgram(p); //每一幀都要調用該函數,不然視訊資料就不會顯示
	//Y
	//
	glActiveTexture(GL_TEXTURE0);

	glBindTexture(GL_TEXTURE_2D, id_y);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, pixel_w, pixel_h, 0, GL_RED, GL_UNSIGNED_BYTE, plane[0]);

	glUniform1i(textureUniformY, 0);

	//U
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, id_u);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, pixel_w / 2, pixel_h, 0, GL_RED, GL_UNSIGNED_BYTE, plane[1]);
	glUniform1i(textureUniformU, 1);

	//V
	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, id_v);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, pixel_w / 2, pixel_h, 0, GL_RED, GL_UNSIGNED_BYTE, plane[2]);
	glUniform1i(textureUniformV, 2);


	// Draw
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
	// Show

	
	add_rect_roi();
	add_rect_roi_v2();
	test_line();


	//Double
	glutSwapBuffers();
	//Single
	//glFlush();
}

void timeFunc(int value)
{
	display();
	// Timer: 40ms
	glutTimerFunc(40, timeFunc, 0);
}

//Init Shader
void InitShaders()
{
	GLint vertCompiled, fragCompiled, linked;

	GLint v, f;
	static const char *vs, *fs;
	//Shader: step1
	v = glCreateShader(GL_VERTEX_SHADER);
	f = glCreateShader(GL_FRAGMENT_SHADER);

	vs = GLSL(400,
		attribute vec4 vertexIn;
		attribute vec2 textureIn;
		varying vec2 textureOut;
		void main(void)
		{
			gl_Position = vertexIn;
			textureOut = textureIn;
		}
	);

	fs = GLSL(400,
		varying vec2 textureOut;
		uniform sampler2D tex_y;
		uniform sampler2D tex_u;
		uniform sampler2D tex_v;
		vec4 sharpen()
		{
			//給出卷積核心中各個元素對應像素相對于待處理像素的紋理坐标偏移量	
			ivec2 TexSize = textureSize(tex_y, 0);//紋理圖檔大小
			vec2 offset0 = vec2(-1.0 / TexSize.x, -1.0 / TexSize.y);
			vec2 offset1 = vec2(0.0 / TexSize.x, -1.0 / TexSize.y);
			vec2 offset2 = vec2(1.0 / TexSize.x, -1.0 / TexSize.y);
			vec2 offset3 = vec2(-1.0 / TexSize.x, 0.0 / TexSize.y);
			vec2 offset4 = vec2(0.0 / TexSize.x, 0.0 / TexSize.y);
			vec2 offset5 = vec2(1.0 / TexSize.x, 0.0 / TexSize.y);
			vec2 offset6 = vec2(-1.0 / TexSize.x, 1.0 / TexSize.y);
			vec2 offset7 = vec2(0.0 / TexSize.x, 1.0 / TexSize.y);
			vec2 offset8 = vec2(1.0 / TexSize.x, 1.0 / TexSize.y);

			/* sharp filter
				0  -1  0
				-1  5 -1
				0  -1  0
			*/
			float kernelValue0 = 0.0;
			float kernelValue1 = -1.0;
			float kernelValue2 = 0.0;
			float kernelValue3 = -1.0;
			float kernelValue4 = 5.0;
			float kernelValue5 = -1.0;
			float kernelValue6 = 0.0;
			float kernelValue7 = -1.0;
			float kernelValue8 = 0.0;

			vec4 sum;//最終的顔色和	//擷取卷積核心中各個元素對應像素的顔色值	
			vec4 cTemp0;
			vec4 cTemp1;
			vec4 cTemp2;
			vec4 cTemp3;
			vec4 cTemp4;
			vec4 cTemp5;
			vec4 cTemp6;
			vec4 cTemp7;
			vec4 cTemp8;

			cTemp0 = texture2D(tex_y, textureOut.st + offset0.xy);
			cTemp1 = texture2D(tex_y, textureOut.st + offset1.xy);
			cTemp2 = texture2D(tex_y, textureOut.st + offset2.xy);
			cTemp3 = texture2D(tex_y, textureOut.st + offset3.xy);
			cTemp4 = texture2D(tex_y, textureOut.st + offset4.xy);
			cTemp5 = texture2D(tex_y, textureOut.st + offset5.xy);
			cTemp6 = texture2D(tex_y, textureOut.st + offset6.xy);
			cTemp7 = texture2D(tex_y, textureOut.st + offset7.xy);
			cTemp8 = texture2D(tex_y, textureOut.st + offset8.xy);
			//顔色求和	

			sum = kernelValue0 * cTemp0 + kernelValue1 * cTemp1 + kernelValue2 * cTemp2 +
				kernelValue3 * cTemp3 + kernelValue4 * cTemp4 + kernelValue5*cTemp5 +
				kernelValue6 * cTemp6 + kernelValue7 * cTemp7 + kernelValue8*cTemp8;

			return sum;
		}

		void main(void)
		{
			vec3 yuv;
			vec3 rgb;
			yuv.x = texture2D(tex_y, textureOut).r;
			yuv.y = texture2D(tex_u, textureOut).r - 0.5;
			yuv.z = texture2D(tex_v, textureOut).r - 0.5;

			//對亮度Y做sharpen處理
			vec4 new_value = sharpen();
			yuv.x = new_value.x;

			rgb = mat3(1, 1, 1, 0, -0.39465, 2.03211, 1.13983, -0.58060, 0) * yuv;


			gl_FragColor = vec4(rgb, 1.0f);
		}
	);

	//Shader: step2
	glShaderSource(v, 1, &vs, NULL);
	glShaderSource(f, 1, &fs, NULL);
	//Shader: step3
	glCompileShader(v);
	//Debug
	glGetShaderiv(v, GL_COMPILE_STATUS, &vertCompiled);
	glCompileShader(f);
	glGetShaderiv(f, GL_COMPILE_STATUS, &fragCompiled);

	//Program: Step1
	p = glCreateProgram();
	//Program: Step2
	glAttachShader(p, v);
	glAttachShader(p, f);

	glBindAttribLocation(p, ATTRIB_VERTEX, "vertexIn");
	glBindAttribLocation(p, ATTRIB_TEXTURE, "textureIn");
	//Program: Step3
	glLinkProgram(p);
	//Debug
	glGetProgramiv(p, GL_LINK_STATUS, &linked);
	//Program: Step4
	glUseProgram(p);


	//Get Uniform Variables Location
	textureUniformY = glGetUniformLocation(p, "tex_y");
	textureUniformU = glGetUniformLocation(p, "tex_u");
	textureUniformV = glGetUniformLocation(p, "tex_v");

#if TEXTURE_ROTATE
	static const GLfloat vertexVertices[] = {
		-1.0f, -0.5f,
		0.5f, -1.0f,
		-0.5f, 1.0f,
		1.0f, 0.5f,
	};
#else
	static const GLfloat vertexVertices[] = {
		-1.0f, -1.0f,
		1.0f, -1.0f,
		-1.0f, 1.0f,
		1.0f, 1.0f,
	};
#endif

#if TEXTURE_HALF
	static const GLfloat textureVertices[] = {
		0.0f, 1.0f,
		0.5f, 1.0f,
		0.0f, 0.0f,
		0.5f, 0.0f,
	};
#else
	static const GLfloat textureVertices[] = {
		0.0f, 1.0f,
		1.0f, 1.0f,
		0.0f, 0.0f,
		1.0f, 0.0f,
	};
#endif
	//Set Arrays
	glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, vertexVertices);
	//Enable it
	glEnableVertexAttribArray(ATTRIB_VERTEX);

	glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, 0, 0, textureVertices);
	glEnableVertexAttribArray(ATTRIB_TEXTURE);


	//Init Texture
	glGenTextures(1, &id_y);
	glBindTexture(GL_TEXTURE_2D, id_y);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);

	glGenTextures(1, &id_u);
	glBindTexture(GL_TEXTURE_2D, id_u);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);

	glGenTextures(1, &id_v);
	glBindTexture(GL_TEXTURE_2D, id_v);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);


	shaderManager.InitializeStockShaders();

	squareBatch.Begin(GL_LINE_LOOP, 4);
	glLineWidth(2.0f);
	squareBatch.CopyVertexData3f(vVerts);
	squareBatch.End();


	squareBatch_v2.Begin(GL_LINE_LOOP, 4);
	glLineWidth(3.0f);
	squareBatch_v2.CopyVertexData3f(vVerts_v2);
	squareBatch_v2.End();


}



int main(int argc, char* argv[])
{
	if ((infile = fopen("test.yuv", "rb")) == NULL){
		printf("cannot open this file\n");
		return -1;
	}

	//YUV Data
	plane[0] = buf;
	plane[1] = plane[0] + pixel_w*pixel_h;
	plane[2] = plane[0] + pixel_w*pixel_h * 3 / 2;

	//Init GLUT
	glutInit(&argc, argv);
	//GLUT_DOUBLE
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA /*| GLUT_STENCIL | GLUT_DEPTH*/);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(screen_w, screen_h);
	glutCreateWindow("Video Player By OpenGL (Texture)");
	printf("Version: %s\n", glGetString(GL_VERSION));

	if (glewInit() != GLEW_OK)
	{
		printf("Failed to initialize GLEW ... exiting");
		exit(EXIT_FAILURE);
	}


	glutDisplayFunc(&display);
	glutTimerFunc(40, timeFunc, 0);

	InitShaders();

	// Begin!
	glutMainLoop();

	return 0;
}
           

在shader中,學到了用子函數。

但是有個問題沒有搞清楚:

 圖像邊界處沒有做坐标做保護,竟然也沒有報錯?

繼續閱讀