OpenGL: Хромакей с белым

Я следую этому руководству Эрика Бака, чтобы получить эффект зеленого экрана для моей обработки видео. Это работает абсолютно изумительно, но не совсем соответствует моим требованиям. Мне поручено использовать OpenGL в моем проекте iOS, чтобы "вырезать" белый цвет тем же способом.

Ниже приведен код 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;
}

Методом проб и ошибок я смог манипулировать этим кодом, чтобы сделать разные цвета прозрачными, но белый цвет оказался проблемой.

Как сделать белый фон прозрачным?

2 ответа

Белый на самом деле довольно прост:

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 адекватно удаляет белый фон, не влияя на белизну моей руки.

Вам нужно будет изменить алгоритм в шейдере, чтобы изменить цвет. Значение gDelta является определяющим фактором в непрозрачности вывода пикселей. В опубликованном вами коде, когда значение зеленого компонента превышает среднее значение красного и синего, пиксель начинает становиться прозрачным.

По сути, вам просто нужно решить, какую формулу вы хотите использовать для определения "белого". Одним очень простым (и похожим) способом было бы вычисление среднего значения всех компонентов и определение некоторой отсечки. Например:

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

Вам нужно будет немного изменить это, чтобы придумать цветовую гамму, которая соответствует вашим потребностям.

Также этот процесс формально называют chroma-keying, Хотя вы можете использовать любой цвет, как правило, цвета, которые не будут соответствовать объекту "вырез". Яркий зеленый - частый выбор, потому что он редко сочетается с оттенками кожи или одеждой. По этой причине белый может быть действительно плохим выбором.

Другие вопросы по тегам