OpenGL Shader 图像处理
fmms
13年前
<p>Referred from http://r3dux.org/2011/06/glsl-image-processing/</p> <p>使用OpenGL做图像处理,最主要的就是FragShader的实现,以下是几种已经实现了的shader。有黑白照处理,Sephia特效,反相,高斯模糊,Median模糊,锐化,腐蚀,膨胀,拉普拉斯边缘检测等。后几种图像处理主要就是核函数的选取和计算需要事先从程序中传入或者 hardcode到程序中。</p> <pre class="brush:java; toolbar: true; auto-links: false;">#version 330 uniform sampler2D quadTexture; uniform int filterNumber; uniform vec2 tcOffset[25]; // Texture coordinate offsets in vec2 vTex; out vec4 vFragColour; void main(void) { // Standard if (filterNumber == 0) { vFragColour = texture2D(quadTexture, vTex); } // Greyscale if (filterNumber == 1) { // Convert to greyscale using NTSC weightings float grey = dot(texture2D(quadTexture, vTex).rgb, vec3(0.299, 0.587, 0.114)); vFragColour = vec4(grey, grey, grey, 1.0); } // Sepia tone if (filterNumber == 2) { // Convert to greyscale using NTSC weightings float grey = dot(texture2D(quadTexture, vTex).rgb, vec3(0.299, 0.587, 0.114)); // Play with these rgb weightings to get different tones. // (As long as all rgb weightings add up to 1.0 you won't lighten or darken the image) vFragColour = vec4(grey * vec3(1.2, 1.0, 0.8), 1.0); } // Negative if (filterNumber == 3) { vec4 texMapColour = texture2D(quadTexture, vTex); vFragColour = vec4(1.0 - texMapColour.rgb, 1.0); } // Blur (gaussian) if (filterNumber == 4) { vec4 sample[25]; for (int i = 0; i < 25; i++) { // Sample a grid around and including our texel sample[i] = texture(quadTexture, vTex + tcOffset[i]); } // Gaussian weighting: // 1 4 7 4 1 // 4 16 26 16 4 // 7 26 41 26 7 / 273 (i.e. divide by total of weightings) // 4 16 26 16 4 // 1 4 7 4 1 vFragColour = ( (1.0 * (sample[0] + sample[4] + sample[20] + sample[24])) + (4.0 * (sample[1] + sample[3] + sample[5] + sample[9] + sample[15] + sample[19] + sample[21] + sample[23])) + (7.0 * (sample[2] + sample[10] + sample[14] + sample[22])) + (16.0 * (sample[6] + sample[8] + sample[16] + sample[18])) + (26.0 * (sample[7] + sample[11] + sample[13] + sample[17])) + (41.0 * sample[12]) ) / 273.0; } // Blur (median filter) if (filterNumber == 5) { vFragColour = vec4(0.0); for (int i = 0; i < 25; i++) { // Sample a grid around and including our texel vFragColour += texture(quadTexture, vTex + tcOffset[i]); } vFragColour /= 25; } // Sharpen if (filterNumber == 6) { vec4 sample[25]; for (int i = 0; i < 25; i++) { // Sample a grid around and including our texel sample[i] = texture(quadTexture, vTex + tcOffset[i]); } // Sharpen weighting: // -1 -1 -1 -1 -1 // -1 -1 -1 -1 -1 // -1 -1 25 -1 -1 // -1 -1 -1 -1 -1 // -1 -1 -1 -1 -1 vFragColour = 25.0 * sample[12]; for (int i = 0; i < 25; i++) { if (i != 12) vFragColour -= sample[i]; } } // Dilate if (filterNumber == 7) { vec4 sample[25]; vec4 maxValue = vec4(0.0); for (int i = 0; i < 25; i++) { // Sample a grid around and including our texel sample[i] = texture(quadTexture, vTex + tcOffset[i]); // Keep the maximum value maxValue = max(sample[i], maxValue); } vFragColour = maxValue; } // Erode if (filterNumber == 8) { vec4 sample[25]; vec4 minValue = vec4(1.0); for (int i = 0; i < 25; i++) { // Sample a grid around and including our texel sample[i] = texture(quadTexture, vTex + tcOffset[i]); // Keep the minimum value minValue = min(sample[i], minValue); } vFragColour = minValue; } // Laplacian Edge Detection (very, very similar to sharpen filter - check it out!) if (filterNumber == 9) { vec4 sample[25]; for (int i = 0; i < 25; i++) { // Sample a grid around and including our texel sample[i] = texture(quadTexture, vTex + tcOffset[i]); } // Laplacian weighting: // -1 -1 -1 -1 -1 // -1 -1 -1 -1 -1 // -1 -1 24 -1 -1 // -1 -1 -1 -1 -1 // -1 -1 -1 -1 -1 vFragColour = 24.0 * sample[12]; for (int i = 0; i < 25; i++) { if (i != 12) vFragColour -= sample[i]; } } }</pre> <br /> <p>以下是计算高斯模糊的核函数中对应附近像素的偏移坐标:</p> <pre class="brush:java; toolbar: true; auto-links: false;">// Set up texture sampling offset storage const GLint tcOffsetColumns = 5; const GLint tcOffsetRows = 5; GLfloat texCoordOffsets[tcOffsetColumns * tcOffsetRows * 2]; // Calculate texture coordinate offsets for kernel convolution effects void genTexCoordOffsets(GLuint width, GLuint height, GLfloat step = 1.0f) // Note: Change this step value to increase the number of pixels we sample across... { // Note: You can multiply the step to displace the samples further. Do this with diff values horiz and vert and you have directional blur of a sort... float xInc = step / (GLfloat)(windowWidth); float yInc = step / (GLfloat)(windowHeight); for (int i = 0; i < tcOffsetColumns; i++) { for (int j = 0; j < tcOffsetRows; j++) { texCoordOffsets[(((i*5)+j)*2)+0] = (-2.0f * xInc) + ((GLfloat)i * xInc); texCoordOffsets[(((i*5)+j)*2)+1] = (-2.0f * yInc) + ((GLfloat)j * yInc); } } }</pre> <p></p>