weird fbo filling problem

Hi,

I use FBOs with the ofFBOTexture Class in 006. I generate a fbo in a class to draw something in this FBO and then draw the FBOs from all Objects generated from this Class in the TestApp through a loop. Everytime I generate a new FBO the last FBO gets messed up. It’s completly filled with a color (0,255,255). I don’t use this color anywhere in my code. I use transparency within the FBOs and autoClear is off, if this ist a hint.

generating the FBOs:

  
	fbo.allocate(myWidth,myHeight,false,true);  

The code which fills the FBOs:

  
			fbo.swapIn();  
			fbo.setupScreenForMe();  
			ofSetColor(255, 255, 255, 255);  
			ofLine(pX[pCount]+myWidth/2,pY[pCount]+myHeight/2,pX[closestElement]+myWidth/2,pY[closestElement]+myHeight/2);  
			ofSetColor(255, 255, 255, 0);  
			fbo.setupScreenForThem();  
			fbo.swapOut();  

The draw function of my class:

  
void grower::draw(){  
	fbo.draw(posX-myWidth/2,posY-myHeight/2);  
}  

and the call to this form testApp:

  
	for (int i = 0; i < growItems.size(); i++) {  
		ofEnableAlphaBlending();  
		growItems[i].draw();  
		ofDisableAlphaBlending();  
	}  

Maybe someone got a hint, I’m at a complete loss here.

Thanks!

Just a little update:
I upgraded to the latest ofxFBOTexture from http://addons.openframeworks.cc/project-…-fbotexture
but the Problem remains the same :frowning:

I can’t see anything wrong with your code, you might need to post a full example

ok, here is the full code (except the blob detection):

grower.h:

  
#ifndef _GROWER  
#define _GROWER  
  
#include "trackedBlob.h"  
#include "ofxFBOTexture.h"  
  
  
class grower{  
public:  
	grower(trackedBlob & tBlob);  
	  
	void update();  
	void draw();  
	void setPos(float x, float y);  
	ofxFBOTexture & getTexture();  
	  
	trackedBlob myBlob;  
	int id;  
	float posX;  
	float posY;  
	int dead;  
	  
	int myWidth;  
	int myHeight;  
	float startRadius;  
	int maxP;  
	float * pX;  
	float * pY;  
	int pCount;  
	float pSize;  
	int stickDist;  
	ofxFBOTexture fbo;  
};  
#endif  

grower.cpp

  
#ifndef _GROWER  
#define _GROWER  
  
#include "trackedBlob.h"  
#include "ofxFBOTexture.h"  
  
  
class grower{  
public:  
	grower(trackedBlob & tBlob);  
	  
	void update();  
	void draw();  
	void setPos(float x, float y);  
	ofxFBOTexture & getTexture();  
	  
	trackedBlob myBlob;  
	int id;  
	float posX;  
	float posY;  
	int dead;  
	  
	int myWidth;  
	int myHeight;  
	float startRadius;  
	int maxP;  
	float * pX;  
	float * pY;  
	int pCount;  
	float pSize;  
	int stickDist;  
	ofxFBOTexture fbo;  
};  
#endif  

testApp.h

  
#ifndef _TEST_APP  
#define _TEST_APP  
  
#include "ofMain.h"  
  
#include "blobTracker.h"  
#include "trackedBlob.h"  
#include "ofxOpenCv.h"  
#include "ofxVectorMath.h"  
#include "grower.h"  
  
  
class testApp : public ofBaseApp{  
  
	public:  
  
	void setup();  
	void update();  
	void draw();  
	  
	void keyPressed  (int key);  
	  
	void mouseMoved(int x, int y );  
	void mouseDragged(int x, int y, int button);  
	void mousePressed(int x, int y, int button);  
	  
	ofVideoPlayer video;  
//	ofVideoGrabber 		video;  
	  
	ofxCvGrayscaleImage cvThresh;  
	ofxCvGrayscaleImage cvBackground;  
	ofxCvGrayscaleImage cvGray;  
	ofxCvColorImage cvColor;  
	  
	ofxCvContourFinder contourFinder;  
	  
	blobTracker tracker;  
	  
	//vector is like an array - but it is more flexible  
	//think of a vector as a c++ array  
	vector <trackedBlob> trackedBlobs;  
	  
	  
	vector<grower> growItems;  
	  
	int threshold;  
	int backSubMode;  
	int distanceThresh;  
	  
	ofPoint biggestBlobPos;  
	  
  
};  
  
#endif  

testApp.cpp

  
#include "testApp.h"  
  
  
//--------------------------------------------------------------  
void testApp::setup(){  
	ofBackground(20,20,20);  
	  
//	video.setVerbose(true);  
//	video.initGrabber(400,300);  
	video.loadMovie("multiPerson-FromBehind-IR.mov");  
	video.play();  
  
	//allocate the openCV images  
	cvColor.allocate(video.width, video.height);  
	cvGray.allocate(video.width, video.height);  
	cvBackground.allocate(video.width, video.height);  
	cvThresh.allocate(video.width, video.height);  
	  
	  
	//-----  
	backSubMode = 2;  
	threshold   = 30;  
	  
	//how far a blob has to move between frames before it is treated as a new blob  
	//you usually have to adjust this based on the size of the video and the people within it.  
	//basically this is 'how far do you think someone would normally move between frames measured in pixels'  
	distanceThresh = 80;  
	  
	//we say that we are interested in previous blobs that are younger than 500ms  
	//this means that if we don't see a stored blob for more than half a second we forget about it.  
	//this is essentially the memory in milliseconds of your tracker  
	tracker.setup(500);  
	  
}  
  
//--------------------------------------------------------------  
void testApp::update(){  
//	video.grabFrame();  
	video.idleMovie();  
	  
	if(video.isFrameNew()){  
		unsigned char * pixels = video.getPixels();  
		//we needs to put the video data into the openCV image  
		cvColor.setFromPixels(pixels, video.width, video.height);  
		  
		//converting from color to grayscale is as simple as   
		//setting the gray cv image = to the color cv image  
		cvGray = cvColor;  
		  
		//lets treat the first few frames of the video as our background  
		if(ofGetFrameNum() < 20)	cvBackground = cvGray;  
		  
		//we do background subtraction - between the current frame and our background  
		//we can do absolute difference / lighter than / and darker than  
		//typical is absolute diff  
		if(backSubMode == 0){  
			cvThresh = cvGray;  
			cvThresh.absDiff(cvBackground);  
		}else if(backSubMode == 1){  
			cvThresh = cvGray;  
			cvThresh -= cvBackground;  
		}else if(backSubMode == 2){  
			cvThresh = cvBackground;  
			cvThresh -= cvGray;  
		}  
		  
		cvThresh.threshold(threshold);  
		  
		//lets find blobs and their contours  
		int numFound = contourFinder.findContours(cvThresh, 10 * 10, 200 * 200, 100, false, false);  
		  
		//TRACKER   
		  
		//we do this whether or not we have found any blobs because the tracker also kills its stored blobs  
		//if they haven't been matched for a while.  
		tracker.begin();  
		  
		if( numFound > 0){  
			//allocate our array (vector) with enough space for the number of blobs we have found  
			trackedBlobs.assign(numFound, trackedBlob());  
			  
			//loop through each blob found  
			for(int i = 0; i < numFound; i++){  
				  
				//copy each blob over to our array  
				trackedBlobs[i] = contourFinder.blobs[i];  
				  
		  
				  
				//see if the blob is one known from previous frames  
				bool blobMatched = tracker.matchTrackedBlob( trackedBlobs[i], distanceThresh );  
				  
				//if the blob can't be matched against the stored blobs  
				//add it to the stored blobs  
				if( blobMatched == false ){  
					tracker.addBlob(trackedBlobs[i]);  
				}  
			}  
		}  
		  
		//this is where stored blobs that need to die, get killed :)  
		tracker.end();  
		  
		  
		  
		// grow Liste checken und tote Blobs in eraseGrowListe schreiben  
		vector <int> eraseGrowList;  
		eraseGrowList.clear();  
		for(int j = growItems.size()-1; j >= 0; j--){  
			growItems[j].dead=1;  
			for(int k = 0; k < trackedBlobs.size();k++){  
				if(trackedBlobs[k].id==growItems[j].id){  
					growItems[j].dead=0;  
					growItems[j].setPos(trackedBlobs[k].centroid.x,trackedBlobs[k].centroid.y);  
				}  
			}  
			if(growItems[j].dead==1){  
				eraseGrowList.push_back(j);  
				printf("growItem %i is dead! \n",j);  
			}  
		}  
		// tote grower löschen aus growItems  
		for(int j = 0; j < eraseGrowList.size(); j++){  
			growItems.erase(growItems.begin() + eraseGrowList[j]);  
		}  
		  
		  
		for(int i = 0; i < trackedBlobs.size(); i++){  
			if( trackedBlobs[i].bNew ){  
				// make grower for each blob and add to growItems list  
				// grower * tgrower = new grower(trackedBlobs[i]);  
				growItems.push_back(*new grower(trackedBlobs[i]));  
				//			printf("new blob is dead: %s \n", growItems.back().myBlob.dead ? "true" : "false");  
			}else{  
				ofSetColor(0x0000FF);  
			}  
		}  
					  
			// grower jeden zyklus updaten  
			for (int i = 0; i < growItems.size(); i++) {  
				growItems[i].update();  
			}  
		  
}  
	  
	  
	  
		  
  
}  
  
//--------------------------------------------------------------  
void testApp::draw(){  
	ofSetColor(255, 255, 255);  
	cvColor.draw(0, 0);  
	  
	//lets draw the tracked blobs ids!  
	  
	//using our vector (c++ array) is cool because it knows how big it is.   
	//the size() function returns the number of things its storing.  
	  
	for(int i = 0; i < trackedBlobs.size(); i++){  
		if( trackedBlobs[i].bNew ){  
			ofSetColor(0xFFFF00);  
		}else{  
			ofSetColor(0x0000FF);  
		}  
		ofFill();  
		ofCircle(trackedBlobs[i].centroid.x, trackedBlobs[i].centroid.y, 4);  
		  
		ofSetColor(0x00FFFF);  
		ofDrawBitmapString("id: "+ofToString(trackedBlobs[i].id), trackedBlobs[i].boundingRect.x, trackedBlobs[i].boundingRect.y);		  
	}  
	  
	  
	ofSetColor(0x000000);  
	ofFill();  
	ofRect(video.width, video.height, video.width, video.height);  
	contourFinder.draw(video.width, video.height);  
	  
	  
  
	// draws the grower  
	for (int i = 0; i < growItems.size(); i++) {  
		ofEnableAlphaBlending();  
		//growItems[i].draw();  
		ofxFBOTexture & tTex = growItems[i].getTexture();  
		tTex.draw(growItems[i].posX,growItems[i].posY);  
		ofDisableAlphaBlending();  
	}  
  
  
}  
  
  
//--------------------------------------------------------------  
void testApp::keyPressed  (int key){  
	if(key == '1'){  
		backSubMode = 0;  
	}else if(key == '2'){  
		backSubMode = 1;  
	}else if(key == '3'){  
		backSubMode = 2;  
	}  
	  
	if(key == 'g'){  
		cvBackground = cvGray;  
	}  
	  
	//reset the tracker and id count  
	if(key == 'r'){  
		tracker.resetCounter();  
	}  
	  
	if( key == OF_KEY_UP ){  
		threshold++;  
		if(threshold > 255)threshold = 255;  
	}else if(key == OF_KEY_DOWN){  
		threshold--;  
		if(threshold < 0)threshold = 0;  
	}  
	  
	  
}  
  
//--------------------------------------------------------------  
void testApp::mouseMoved(int x, int y ){  
}  
  
//--------------------------------------------------------------  
void testApp::mouseDragged(int x, int y, int button){  
}  
  
//--------------------------------------------------------------  
void testApp::mousePressed(int x, int y, int button){  
}  

thanks for looking into that

as you can see in the code I tried drawing directly through an draw method and referencing the texture and then drawing. both methods produce exactly the same problem.

What happens when you create a function in the grower class called draw(), and instead of doing this:

  
  
ofxFBOTexture & tTex = growItems[i].getTexture();  
tTex.draw(growItems[i].posX,growItems[i].posY);  

You just call

  
growItems[i].draw();  

so that in the grower class the draw function looks something like:

  
  
draw()  
{  
   fbo.draw(posX,posY);  
}  

I did this. It’s in the code above :slight_smile:

This produces exactly the same problem.

The lines are:

  
  
// in grower.cpp  
void grower::draw(){  
	fbo.draw(posX-myWidth/2,posY-myHeight/2);  
}  
  
// in testApp.cpp  
for (int i = 0; i < growItems.size(); i++) {  
		ofEnableAlphaBlending();  
		growItems[i].draw();  
		ofDisableAlphaBlending();  
	}  
  

Well, actually you duplicated the header file code…

Hmm, not sure if I can help you just from looking at the code, but here’s something that might be causing problems:

  
      for(int j = 0; j < eraseGrowList.size(); j++){  
         growItems.erase(growItems.begin() + eraseGrowList[j]);  
      }  

I’m not sure this will work the way you want it to because vector::erase() invalidates all iterators following the element to be erased.

can you post a zip of all the source code?

thanks!
zach

Hi,

here is a zip with the complete src folder. Thank you for looking into this.

src.zip

Hi,

I experimented some more and made a little test-environment with just the grower and a testapp which generates the grower.

The problem stays weird. Every ?-times a FBO gets created the already created FBOs get fill complete with the setColor.

Here is a zip (inkl. the xcode project) with the src. Maybe somebody got an idea what’s wrong with the FBO.

fbo_test2.zip

Ok the problem is that same as the other recent FBO issue.

When you call the call the vector push_back function, is creates a copy of the object being pushed back.

From:
http://www.cplusplus.com/reference/stl/-…-push-back/

Add element at the end

Adds a new element at the end of the vector, after its current last element. The content of this new element is initialized to a copy of x.

A copy means calling the copy constructor. The FBO class has none so it defaults to the ofTexture copy constructor…which doesn’t copy the texture properly. The orginally created FBO then goes out of scope and therefore its texture may be deleted.

A fix would be to do this:

  
void testApp::update(){  
	if(myGrower.size()<100){  
	myGrower.push_back(new grower());  
	}  
}  
  
//--------------------------------------------------------------  
void testApp::draw(){  
	ofEnableAlphaBlending();  
	for (int i = 0; i < myGrower.size(); i++) {  
		myGrower[i]->draw();  
	}  
	ofDisableAlphaBlending();  
}  

By the way FBO’s are not useful for this kind of thing. Just use a regular texture unless you are going to be dynamically creating different textures every frame.

Thank you for your answer.

The code of yours doesn’t seem to work. I got an error while compiling at

  
myGrower.push_back(new grower());  

error: no matching function for call to ‘std::vector<grower, std::allocator > ::push_back(grower*)’

as far as I understand this the push_back want a dereferenced object. I’m quite new to c++ and so pointers are sometimes quite a miracle for me.

For the second suggestion:
I used FBOs because I need to draw ofScreen and then draw the Objects in another Image. Can I draw directly to an texture and then later use it?

Thanks for your help.

Sorry, I forgot to mention that myGrower needs to be a vector of pointers to grower objects.
i.e.

  
  
vector<grower*> myGrower;  
  

The push_back() expects what ever type of object you have decided to put in your vector (whatever it is you have in the header file definition).

Pointers and memory problems are the most difficult thing for beginners when learning C++, so feel free to ask questions!

If you are drawing a screen to a texture, which is often called “render to texture” then an FBO is your best option (unless its good enough to do it offline, i.e. draw one screen, save it to disk, edit it in an image editor and then load it as a regular texture).

Thank you very very much for helping me with that.

In the meantime I threw the whole FBO out of this and just saved drawing coordinates, because I just draw a few Points in every FBO. Later then I draw it in another FBO to use this to mask another picture :slight_smile:

Best,
Christoph