OpenGL Shader 圖像處理

fmms 12年前發布 | 122K 次閱讀 OpenGL 圖形/圖像處理

Referred from http://r3dux.org/2011/06/glsl-image-processing/

使用OpenGL做圖像處理,最主要的就是FragShader的實現,以下是幾種已經實現了的shader。有黑白照處理,Sephia特效,反相,高斯模糊,Median模糊,銳化,腐蝕,膨脹,拉普拉斯邊緣檢測等。后幾種圖像處理主要就是核函數的選取和計算需要事先從程序中傳入或者 hardcode到程序中。

#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];
        }
    }
}

以下是計算高斯模糊的核函數中對應附近像素的偏移坐標:

// 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);
        }
    }
}

 本文由用戶 fmms 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!