OpenGL:带白色的色度键

OpenGL: Chromakey With White

我正在按照 Erik Buck 的 this 指南来为我的视频处理获得绿屏效果。这绝对是了不起的,但它并不完全符合我的要求。我的任务是在我的 iOS 项目中使用 OpenGL 到 'cut out' white 使用相同的方法。

以下是 Erik Buck 项目中的 OpenGL 代码,用于为每个纹理查找绿色纹素并将其不透明度指定为零:

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

通过反复试验,我能够操纵此代码使不同的颜色透明,但事实证明白色是一个挑战。

如何让背景中的白色变透明?

您需要修改着色器中的算法来更改颜色。 gDelta 的值是像素输出不透明度的决定因素。在您发布的代码中,一旦绿色分量的值高于红色和蓝色的平均值,像素就开始变得透明。

您基本上只需要决定要使用哪个公式来检测 'white'。一种非常简单(和类似)的方法是计算所有组件的平均值,并定义一些截止值。例如:

//...
float cutoff = 0.8f;
lowp float gDelta = cutoff - dot(tempColor, vec4(0.33, 0.33, 0.33, 0.0));
//...

您需要稍微修改一下以找到适合您需要的颜色范围。

另外,这个过程正式调用chroma-keying。尽管您可以使用任何颜色,但通常是与 "cutout" 对象不匹配的颜色。亮绿色是一个常见的选择,因为它很少与肤色或衣服相匹配。因此,白色可能是一个非常糟糕的选择。

白其实很简单:

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

我发现将阈值设置为 1.99 可以充分去除白色背景,而不会影响我手的白度。