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
可以充分去除白色背景,而不会影响我手的白度。
我正在按照 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
可以充分去除白色背景,而不会影响我手的白度。