Mask image with a ofPath shape

Hi there!

I have to select parts of an image I get from the webcam to later process them with ofCv. The problem is that the shapes I need to get are not regular (not a rectangle I can easily get with grabScreen()), they are something like trapezoids. I was thinking of ‘drawing’ the shapes with ofPath and then using the ofPath to somehow crop the ofImage. Is there any way I can use ofPath (or something similar) to either crop the image or get the specific part of the image I want into another ofImage?

Thanks a million! :slightly_smiling:

Hi,
I see some ways to do that. I haven’t tested all of them, but the 1 and the 3.

1-
Draw the path in a ofFbo fbo1. You have to do this only once, or each time the path change, but not every frame.
Draw the webcam in a second ofFbo fbo2, masked with fbo1 (check the examples to find how to mask).
Read the pixels from fbo2 into an ofPixels: fbo2.readToPixels( pixels )
You can now get the openCV Mat: Mat img = ofxCv::toCv( pixels )

2-
Draw the webcam in a ofFbo fbo.
Draw the path in the same fbo, in black. Not exactly the path, but its outside.
Read the pixels from fbo into an ofPixels: fbo.readToPixels( pixels )
You can now get the openCV Mat: Mat img = ofxCv::toCv( pixels )

3-
Get a mesh from the ofPath:

ofVboMesh mesh = path.getTessellation();
int num = mesh.getNumVertices();
for ( int i = 0; i < num; i++ ){
    mesh.addTexCoord( mesh.getVertex( i) );
}

You have to do this only once, or each time the path change, but not every frame.

Use this mesh to draw only the cropped part in a fbo. Something like:

fbo.begin();
webcam.getTexture().bind();
mesh.draw();
webcam.getTexture().unbind();
fbo.end();

Read the pixels from fbo into an ofPixels: fbo.readToPixels( pixels )
You can now get the openCV Mat: Mat img = ofxCv::toCv( pixels )
This is perhaps a little faster than the 2 previous methods.

4-
Draw the path in a ofFbo.
Create a openCV image from this fbo.
You have to do this only once, or each time the path change, but not every frame.
Use a openCV method to apply the mask to the webcam image, like in this topic.
Depending on your harware, this may be faster than the others methods, because readToPixels can be an expensive operation (transfert from graphics card memory to main memory), and it is the only method which use it only when the path change. But on the other side, the masking operation is done by the CPU in this method…

5-
Draw the path with openCV (but I don’t know if openCV have primitive drawing methods to do that), and use it to mask the webcam image like in the previous method.

since 0.9 there’s an easy way to do this:

ofPath path;
ofImage img;
ofFbo fbo;


void setup(){
    path.lineTo(...);
    // draw on the path, level of gray means alpha

    fbo.allocate(w,h,GL_LUMINANCE); //or GL_RED if you are using the programmable renderer
    fbo.begin();
    path.draw();
    fbo.end();

    img.getTexture().setAlphaMask(fbo.getTexture());
}

void draw(){
    img.draw();
}

Thanks a million guys (also for the impressive speed of response)!
The “img.getTexture().setAlphaMask(fbo.getTexture());” part is the one I was desperately missing.

Thx! :slight_smile:

2 Likes

Is this working correctly ? I can’t get the wanted result… a simple crop of the image…

ofPath path;
ofImage img;
ofFbo fbo;

//--------------------------------------------------------------
void ofApp::setup(){

    path.moveTo(100,100);
    path.lineTo(200,100);
    path.lineTo(200,200);
    path.lineTo(100,200);
    path.lineTo(100,100);

    
    fbo.allocate(ofGetWidth(),ofGetHeight(),GL_LUMINANCE);
    fbo.begin();
    path.draw();
    fbo.end();
    
    img.load("sarah.png");
    img.getTexture().setAlphaMask(fbo.getTexture());
    
}

//--------------------------------------------------------------
void ofApp::update(){

}

//--------------------------------------------------------------
void ofApp::draw(){
    
    img.draw(100,100);

}

I found an answer here : setAlphaMask example failing