Search code examples
iosopengl-esshaderfragment-shaderchromakey

OpenGL: Chromakey With White


I am following this guide by Erik Buck to get a green screen effect for my video processing. This works absolutely marvelous but it doesn't exactly meet my requirement. I am tasked with using OpenGL in my iOS project to 'cut out' the white using this same method.

Below is the OpenGL code from Erik Buck's project to find the green texels for each texture and assign it's opacity to zero:

varying highp vec2 vCoordinate;
uniform sampler2D uVideoframe;


void main()
{
   // Look up the color of the texel corresponding to the fragment being
   // generated while rendering a triangle
   lowp vec4 tempColor = texture2D(uVideoframe, vCoordinate);

   // Calculate the average intensity of the texel's red and blue components
   lowp float rbAverage = tempColor.r * 0.5 + tempColor.b * 0.5;

   // Calculate the difference between the green element intensity and the
   // average of red and blue intensities
   lowp float gDelta = tempColor.g - rbAverage;

   // If the green intensity is greater than the average of red and blue
   // intensities, calculate a transparency value in the range 0.0 to 1.0
   // based on how much more intense the green element is
   tempColor.a = 1.0 - smoothstep(0.0, 0.25, gDelta);

   // Use the cube of the transparency value. That way, a fragment that
   // is partially translucent becomes even more translucent. This sharpens
   // the final result by avoiding almost but not quite opaque fragments that
   // tend to form halos at color boundaries.
   tempColor.a = tempColor.a * tempColor.a * tempColor.a;

      gl_FragColor = tempColor;
}

Through trial and error I was able to manipulate this code to be able to make different colors transparent, but white has been proven a challenge.

How do I make the white in the background to be transparent?

enter image description here


Solution

  • White is actually quite simple:

    void main()
    {
        lowp vec4 tempColor = texture2D(uVideoframe, vCoordinate);
        lowp float rgbAverage = tempColor.r + tempColor.b + tempColor.g;
        if (rgbAverage > 1.99) {
            tempColor.a = 0.0;
        }
        else {
            tempColor.a = 1.0;
        }
        gl_FragColor = tempColor;
    }
    

    I found that setting the threshold to 1.99 adequately removes a white background without affecting the whiteness of my hand.