Filling ofPath with video

What I am trying to do is take the contours from ofxCV (done) and fill them with video (not done). It looks like my best bet is to convert the ofPolyline to an ofPath, and then fill that, but now that I am that far, I only know how to use ofFill() to fill it with a solid color, not a video. Does anyone have any advice for this?

Thanks,
Austin

i did something similar some time ago, and used ofpath to draw black & white mask. Then a masking shader (ofxFX has one; see https://github.com/patriciogonzalezvivo/ofxFX/blob/master/src/composers/ofxMask.h) to replace the white pixels with your video.

Might not be the best option but it works :slight_smile:

What if I wanted to fill each path with a different video? Here is my code currently:

void testApp::draw(){

ofSetColor(122,122,122);//white contours
cam.draw(0, 0);//draws camera input
contourFinder.draw();//draws contours on it

int n = contourFinder.size();

for(int i = 0; i < n; i++) {
    ofPoint center = toOf(contourFinder.getCenter(i));//center point of contour
    double area = contourFinder.getContourArea(i);//area of contour
    
    //FOR DISPLAYING ID
    ofPushMatrix();
        ofTranslate(center.x, center.y);
        int label = contourFinder.getLabel(i);//gets ID
        string msg = ofToString(label);
        ofDrawBitmapString(msg, 0, 0);
        ofScale(5, 5);
    ofPopMatrix();
    
    
    //FOR FILLING
    ofPolyline polyline = contourFinder.getPolyline(i);//to convert
    ofPath pathFromContour;//path to be built
    
    for(int i = 0; i < polyline.getVertices().size(); i++) {
        if(i == 0) {
            pathFromContour.newSubPath();
            pathFromContour.moveTo(polyline.getVertices()[i]);
        } else {
            pathFromContour.lineTo(polyline.getVertices()[i]);
        }
    }
    pathFromContour.close();
    pathFromContour.simplify();
    
    ofColor(ofRandom(255),ofRandom(255),ofRandom(255));
    ofFill();
    pathFromContour.draw();
    
}
}

I don’t know if I am creating ofPaths in a way that I can distinguish between different ones…

i suppose you could draw each contour to a different fbo and apply the shader, then merge. It would be pretty gpu & cpu intesive.
You might want to try to draw each contour/path in a distinctive different color; and write a custom shader to replace each color with a different texture. I believe that in the 0.8.1 release there is a tutorial about multitexture shaders.

In this case, how might I assign a different color to each path? Each shape is changing colors at the framerate, I can’t seem to get it to retain a color. For that matter I can’t seem to get each ofPath to retain some sort of identifier from the contour (i). Any tips?

void testApp::draw(){

    ////vector<ofPolyline> polylines;
    ////vector<ofPath> paths;

    ofSetColor(255);//white contours
    cam.draw(0, 0);//draws camera input
    contourFinder.draw();//draws contours on it

    int n = contourFinder.size();//the number of contours

    for(int i = 0; i < n; i++) {

        ofPoint center = toOf(contourFinder.getCenter(i));//center point of contour
        double area = contourFinder.getContourArea(i);//area of contour

        //FOR DISPLAYING ID AND AREA
        ofPushMatrix();
            ofTranslate(center.x, center.y);
            int label = contourFinder.getLabel(i);//gets ID
            string msg = "ID: " + ofToString(label);
            string areaMsg = "AREA: " + ofToString(area);
            ofSetColor(255,0,0);
            ofDrawBitmapString(msg, 0, 0);
            ofDrawBitmapString(areaMsg, 0, 10);
            ofScale(5, 5);
        ofPopMatrix();

        //FOR FILLING
        ofPolyline polyline = contourFinder.getPolyline(i);//to convert

        ////polylines.push_back(polyline);

        ofPath pathFromContour;//path to be built

        for(int j = 0; j < polyline.getVertices().size(); j++) {
            if(j == 0) {
                pathFromContour.newSubPath();
                pathFromContour.moveTo(polyline.getVertices()[j]);
            } else {
                pathFromContour.lineTo(polyline.getVertices()[j]);
            }
        }

        pathFromContour.close();
        pathFromContour.simplify();

        //WHY ARE THEY FILLING SO CHAOTICALLY?
        ofColor pathColor(ofRandom(255),ofRandom(255),ofRandom(255));
        pathFromContour.setFillColor(pathColor);
        pathFromContour.draw();

        ////paths.push_back(pathFromContour);
    }
}

I’d recommend using a shader for this. This isn’t really a beginner thing to be doing, but look at making an ofMesh from each contour and then assigning an id to each vertex saying which video you want to be drawing next to it. In your shader you’d do something like this:

uniform sampler2DRect texs[2];
uniform int which;

void main()
{
	gl_FragColor = gl_Color * texture2DRect(texs[which], gl_TexCoord[0].xy);
}

That “which” you can just set before you draw each contour by doing shader.setUniform1f(“which”, 0); // whichever tex you want. Just make sure to bind all your movie textures.

hi joshua, i’m intrigued by the ofmesh approach but I don’t completely understand how you could fill a mesh using a shader. Is there an example? Also, would you use one mesh to add all contours or 1 for each?

I assume it would be much more performant then the ofPath, fbo & tesselation approach, esp for >10 contours.

Here’s some code:

   void testApp::setup(){
    
    shader.load("shaders/multitex");
    
    ofIndexType indices[] = {0,1,2,2,3,0};
    
    mMesh.addVertex( ofVec3f( 0, 0, 100));
    mMesh.addTexCoord(ofVec2f( 0, 0 ));
    mMesh.addVertex( ofVec3f( 200, 0, 100));
    mMesh.addTexCoord(ofVec2f( 100, 0 ));
    mMesh.addVertex( ofVec3f( 200, 200, 100));
    mMesh.addTexCoord(ofVec2f( 100, 100 ));
    mMesh.addVertex( ofVec3f( 0, 200, 100));
    mMesh.addTexCoord(ofVec2f( 0, 100 ));
    
    mMesh.addIndices(&indices[0], 6);
    
    mMesh2.addVertex( ofVec3f( 200, 0, 100));
    mMesh2.addTexCoord(ofVec2f( 0, 0 ));
    mMesh2.addVertex( ofVec3f( 400, 0, 100));
    mMesh2.addTexCoord(ofVec2f( 100, 0 ));
    mMesh2.addVertex( ofVec3f( 400, 200, 100));
    mMesh2.addTexCoord(ofVec2f( 100, 100 ));
    mMesh2.addVertex( ofVec3f( 200, 200, 100));
    mMesh2.addTexCoord(ofVec2f( 0, 100 ));
    
    mMesh2.addIndices(&indices[0], 6);
    
    img1.loadImage("one.jpg");
    img2.loadImage("two.jpg");
    
    
}

void testApp::draw(){

    ofPushMatrix();
    ofTranslate(200, 100);
    
    shader.begin();
    shader.setUniformTexture("textures[0]", img1, 0);
    shader.setUniformTexture("textures[1]", img2, 1);
    float texIDs[] = {0,0,0,0};
    shader.setAttribute1fv("texID", &texIDs[0], 0);

    
	mMesh.draw();
    
    texIDs[0] = 1; texIDs[1] = 1; texIDs[2] = 1; texIDs[3] = 1;
    shader.setAttribute1fv("texID", &texIDs[0], 0);
	mMesh2.draw();
    
    shader.end();
    
    ofPopMatrix();
}

vert

#version 120

varying vec2 texturePosition;
attribute float texID;
varying float texIDVarying;

void main(){

	texturePosition = gl_MultiTexCoord0.xy;
	
	//get our current vertex position so we can modify it
	vec4 pos = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
    
    texIDVarying = texID;
	
	//finally set the pos to be that actual position rendered
	gl_Position = pos;
}

frag

#version 120

varying vec2 texturePosition;
varying float texIDVarying;
uniform sampler2DRect textures[2];

void main(){
	
    int i = int(texIDVarying);
	gl_FragColor = texture2DRect(textures[i], texturePosition);
}
1 Like