Clave de Chroma con OpenFrameworks/OpenGL
-
23-10-2019 - |
Pregunta
Necesito implementar la tecla de croma (eliminación de un fondo de color sólido) en una aplicación OpenFrameWorks.
Tocaré muchos (10 o más) videos simultáneamente (en el mismo cuadro) y los dibujaré a la pantalla junto con fondos alternativos. Puedo lograr un efecto de clave de croma iterando a través de los píxeles de cada cuadro y estableciendo valores alfa para cada uno en función de un umbral verde, pero con tantos videos a la vez, este bango de píxel se vuelve prohibitivo.
¿Existe un modo de combinación o operación de enmascaramiento fácil de OpenGL que pueda evitar dibujar todos los píxeles de un cierto valor de color? ¿O hay otra biblioteca C ++ compatible con OpenFrameWorks o OpenFrameWorks que puede hacer esto de manera eficiente?
Alternativamente, ¿hay una buena forma (de eficiencia espacial) de almacenar el alfa-canal en archivos de video compatibles con QuickTime? Vamos a almacenar terabytes de video (semanas de grabación continua), por lo que es importante que usemos formatos de eficiencia espacial.
Una nota: el color de tecla de croma en los archivos de origen será "perfecto", se agrega digitalmente. Entonces, si hay algún tipo de umbral o truco de lógico bit a bit para hacer esto, eso también podría funcionar.
EDITAR: Esto es lo que funcionó, siguiendo la sugerencia de Vjo para un sombreador de píxeles. Nosotros usamos glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
, y el siguiente sombreador de píxeles (para magenta como el color reemplazado):
"Data/Shaders/Chromakey.Frag":
#extension GL_ARB_texture_rectangle : enable
uniform sampler2DRect src_tex_unit0;
vec4 color;
void main( void )
{
vec2 st = gl_TexCoord[0].st;
vec4 sample = texture2DRect(src_tex_unit0, st );
gl_FragColor = sample;
if((sample.r > 0.5) && (sample.g < 0.5) && (sample.b > 0.5)) {
gl_FragColor.a = 0.0;
}
}
"Data/Shaders/Chromakey.vert":
void main()
{
gl_Position = ftransform();
gl_TexCoord[0] = gl_MultiTexCoord[0];
}
Las clases de proxy C ++ para los sombreadores - shaderChromakey.h:
#include "ofMain.h"
#include "ofxShader.h"
#include "ofxFBOTexture.h"
class shaderChromakey{
public:
void setup(int fboW, int fboH);
void beginRender();
void endRender();
void draw(int x, int y, int width, int height);
ofxShader shader;
ofxFBOTexture fbo;
};
shaderChromakey.cpp:
#include "shaderChromakey.h"
//--------------------------------------------------------------
void shaderChromakey::setup(int fboW, int fboH){
ofBackground(255,255,255);
ofSetVerticalSync(true);
fbo.allocate(fboW, fboH, true);
shader.loadShader("shaders/chromakey");
}
//--------------------------------------------------------------
void shaderChromakey::beginRender(){
fbo.swapIn();
}
//--------------------------------------------------------------
void shaderChromakey::endRender(){
fbo.swapOut();
}
//--------------------------------------------------------------
void shaderChromakey::draw(int x, int y, int width, int height){
shader.setShaderActive(true);
fbo.draw(x, y, width, height);
shader.setShaderActive(false);
}
Para instanciar el sombreador, en el proyecto:
shaderChromakey chromakey;
chromakey.setup(HORIZONTAL, VERTICAL)
En el bucle de dibujo, para habilitar el sombreador:
chromakey.beginRender();
// draw chomakeyed frame here
chromakey.endRender();
Solución
Podrías usar glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_DST_ALPHA)
Y luego, cuando habilita la mezcla, puede usar un sombreador de píxeles para hacer lo que quiera si el píxel es de color específico (establezca alfa en 0).