54 votes

Où puis-je trouver un exemple de OpenGL ES 2.0, les shaders qui effectuent des tâches de traitement d'image?

Où puis-je trouver de l'OpenGL ES 2.0, les shaders qui peuvent effectuer les tâches de traitement d'image?

  • Palette de transformation ( RVB/YUV/TSL/Lab )
  • Tourbillonnant de l'image
  • La conversion d'une esquisse
  • La conversion à une peinture à l'huile

79voto

Brad Larson Points 122629

J'ai juste ajouté des filtres à mon open source GPUImage cadre qui effectuent trois des quatre tâches de traitement que vous décrivez (tourbillonnant, esquisse le filtrage et la conversion à une peinture à l'huile). Bien que je n'ai pas encore de la palette transformations que les filtres, je ne les ont la possibilité d'appliquer une matrice de transformer les couleurs.

Comme exemples de ces filtres dans l'action, ici, c'est un ton sépia de conversion des couleurs:

Sepia tone image

un tourbillon de distorsion:

Swirl distortion image

une esquisse de filtre:

Sketch filter

et enfin, une peinture à l'huile de conversion:

Oil painting conversion

Notez que tous ces filtres ont été effectués sur des images vidéo en direct, et tout, mais le dernier filtre peut être exécuté en temps réel sur la vidéo à partir de l'appareil iOS caméras. Le dernier filtre est assez gourmand en ressources, de sorte que même comme un shader il faut ~1 seconde ou plus pour le rendu sur un iPad 2.

Le sépia filtre est basé sur la matrice de couleurs fragment shader:

 varying highp vec2 textureCoordinate;

 uniform sampler2D inputImageTexture;

 uniform lowp mat4 colorMatrix;
 uniform lowp float intensity;

 void main()
 {
     lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
     lowp vec4 outputColor = textureColor * colorMatrix;

     gl_FragColor = (intensity * outputColor) + ((1.0 - intensity) * textureColor);
 }

avec une matrice de

self.colorMatrix = (GPUMatrix4x4){
        {0.3588, 0.7044, 0.1368, 0},
        {0.2990, 0.5870, 0.1140, 0},
        {0.2392, 0.4696, 0.0912 ,0},
        {0,0,0,0},
    };

Le tourbillon fragment shader est basé sur ce que les Geeks 3D exemple et a le code suivant:

 varying highp vec2 textureCoordinate;

 uniform sampler2D inputImageTexture;

 uniform highp vec2 center;
 uniform highp float radius;
 uniform highp float angle;

 void main()
 {
     highp vec2 textureCoordinateToUse = textureCoordinate;
     highp float dist = distance(center, textureCoordinate);
     textureCoordinateToUse -= center;
     if (dist < radius)
     {
         highp float percent = (radius - dist) / radius;
         highp float theta = percent * percent * angle * 8.0;
         highp float s = sin(theta);
         highp float c = cos(theta);
         textureCoordinateToUse = vec2(dot(textureCoordinateToUse, vec2(c, -s)), dot(textureCoordinateToUse, vec2(s, c)));
     }
     textureCoordinateToUse += center;

     gl_FragColor = texture2D(inputImageTexture, textureCoordinateToUse );

 }

L'esquisse filtre est générée à l'aide de Sobel détection de bord, avec des bords montré dans différents tons de gris. Le shader pour ce est comme suit:

 varying highp vec2 textureCoordinate;

 uniform sampler2D inputImageTexture;

 uniform mediump float intensity;
 uniform mediump float imageWidthFactor; 
 uniform mediump float imageHeightFactor; 

 const mediump vec3 W = vec3(0.2125, 0.7154, 0.0721);

 void main()
 {
    mediump vec3 textureColor = texture2D(inputImageTexture, textureCoordinate).rgb;

    mediump vec2 stp0 = vec2(1.0 / imageWidthFactor, 0.0);
    mediump vec2 st0p = vec2(0.0, 1.0 / imageHeightFactor);
    mediump vec2 stpp = vec2(1.0 / imageWidthFactor, 1.0 / imageHeightFactor);
    mediump vec2 stpm = vec2(1.0 / imageWidthFactor, -1.0 / imageHeightFactor);

    mediump float i00   = dot( textureColor, W);
    mediump float im1m1 = dot( texture2D(inputImageTexture, textureCoordinate - stpp).rgb, W);
    mediump float ip1p1 = dot( texture2D(inputImageTexture, textureCoordinate + stpp).rgb, W);
    mediump float im1p1 = dot( texture2D(inputImageTexture, textureCoordinate - stpm).rgb, W);
    mediump float ip1m1 = dot( texture2D(inputImageTexture, textureCoordinate + stpm).rgb, W);
    mediump float im10 = dot( texture2D(inputImageTexture, textureCoordinate - stp0).rgb, W);
    mediump float ip10 = dot( texture2D(inputImageTexture, textureCoordinate + stp0).rgb, W);
    mediump float i0m1 = dot( texture2D(inputImageTexture, textureCoordinate - st0p).rgb, W);
    mediump float i0p1 = dot( texture2D(inputImageTexture, textureCoordinate + st0p).rgb, W);
    mediump float h = -im1p1 - 2.0 * i0p1 - ip1p1 + im1m1 + 2.0 * i0m1 + ip1m1;
    mediump float v = -im1m1 - 2.0 * im10 - im1p1 + ip1m1 + 2.0 * ip10 + ip1p1;

    mediump float mag = 1.0 - length(vec2(h, v));
    mediump vec3 target = vec3(mag);

    gl_FragColor = vec4(mix(textureColor, target, intensity), 1.0);
 }

Enfin, la peinture à l'huile look est généré à l'aide d'un Kuwahara filtre. Ce filtre est de l'excellent travail de Jan Eric Kyprianidis et ses collègues chercheurs, comme décrit dans l'article "Anisotrope Kuwahara de Filtrage sur le GPU" à l'intérieur de la GPU Pro livre. Le code du shader de qui est comme suit:

 varying highp vec2 textureCoordinate;
 uniform sampler2D inputImageTexture;
 uniform int radius;

 precision highp float;

 const vec2 src_size = vec2 (768.0, 1024.0);

 void main (void) 
 {
    vec2 uv = textureCoordinate;
    float n = float((radius + 1) * (radius + 1));

    vec3 m[4];
    vec3 s[4];
    for (int k = 0; k < 4; ++k) {
        m[k] = vec3(0.0);
        s[k] = vec3(0.0);
    }

    for (int j = -radius; j <= 0; ++j)  {
        for (int i = -radius; i <= 0; ++i)  {
            vec3 c = texture2D(inputImageTexture, uv + vec2(i,j) / src_size).rgb;
            m[0] += c;
            s[0] += c * c;
        }
    }

    for (int j = -radius; j <= 0; ++j)  {
        for (int i = 0; i <= radius; ++i)  {
            vec3 c = texture2D(inputImageTexture, uv + vec2(i,j) / src_size).rgb;
            m[1] += c;
            s[1] += c * c;
        }
    }

    for (int j = 0; j <= radius; ++j)  {
        for (int i = 0; i <= radius; ++i)  {
            vec3 c = texture2D(inputImageTexture, uv + vec2(i,j) / src_size).rgb;
            m[2] += c;
            s[2] += c * c;
        }
    }

    for (int j = 0; j <= radius; ++j)  {
        for (int i = -radius; i <= 0; ++i)  {
            vec3 c = texture2D(inputImageTexture, uv + vec2(i,j) / src_size).rgb;
            m[3] += c;
            s[3] += c * c;
        }
    }


    float min_sigma2 = 1e+2;
    for (int k = 0; k < 4; ++k) {
        m[k] /= n;
        s[k] = abs(s[k] / n - m[k] * m[k]);

        float sigma2 = s[k].r + s[k].g + s[k].b;
        if (sigma2 < min_sigma2) {
            min_sigma2 = sigma2;
            gl_FragColor = vec4(m[k], 1.0);
        }
    }
 }

Encore une fois, ce sont tous les filtres intégrés dans GPUImage, de sorte que vous pouvez déposer ce cadre dans votre application et commencer à les utiliser sur des images, des vidéos et des films sans avoir à toucher à tout OpenGL ES. Tout le code pour le framework est disponible sous une licence BSD, si vous voulez voir comment cela fonctionne, ou le personnaliser.

2voto

Gregory Mazurek Points 121

Vous pourriez commencer par la vérification de cette liste des shaders ici. Si vous voulez creuser un peu plus, je vous recommande de consulter le carnet d'orange trouvé ici.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X