سؤال

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();
هل كانت مفيدة؟

المحلول

You could use glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_DST_ALPHA) and then when you enable blending, you could use a pixel shader to do what you want if the pixel is of specific color (set alpha to 0).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top