I need to implement chroma keying (removal of a solid color background) in an openFrameworks application.
I'll be playing many (10 or more) videos simultaneously (in the same frame), and drawing them to the screen along with alternate backgrounds. I can achieve a chroma-key-like effect by iterating through each frame's pixels and setting alpha values for each one based on a green threshold, but with so many videos at once, this pixel-banging becomes prohibitive.
Is there an easy OpenGL blend mode or masking operation which can avoid drawing all pixels of a certain color value? Or is there another openFrameworks or openFrameworks-compatible C++ library which can do this efficiently?
Alternatively, is there a good (space-efficient) way to store alpha-channel in quicktime-compatible video files? We're going to be storing terabytes of video (weeks of continuous recording), so it's important that we use space-efficient formats.
One note: the chroma-key color in the source files will be "perfect" -- it is added digitally. So if there's some sort of thresholding or bitwise-logic trick to do this, that could work too.
EDIT: Here's what worked, following VJo's suggestion for a pixel shader. We used glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
, and the following pixel shader (for magenta as the replaced color):
"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];
}
The C++ proxy classes for the shaders -- 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);
}
To instantiate the shader, in the project:
shaderChromakey chromakey;
chromakey.setup(HORIZONTAL, VERTICAL)
In the draw loop, to enable the shader:
chromakey.beginRender();
// draw chomakeyed frame here
chromakey.endRender();