fbo > ofImage > save to file

I am using the latest ofxFBOTexture addon here

http://addons.openframeworks.cc/project-…-fbotexture

I want to save the fbo as an image file.

in app.h i have

  
  
ofImage grabbed;  
ofxFBOTexture       fbo;  
unsigned char * pixels;  
  

in app.cpp setup…

  
  
    fbo.allocate(width, height, false);  
    fbo.clear(0, 0, 0, 0);  
  
    pixels = new unsigned char[width*height*4];  
  
    grabbed.allocate(width, height, OF_IMAGE_COLOR_ALPHA);  
  

in app.cpp save function…

  
  
    fbo.begin();  
  
    glPixelStorei(GL_PACK_ALIGNMENT, 1);  
    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);  
  
    grabbed.setFromPixels(pixels, width, height, OF_IMAGE_COLOR_ALPHA);  
    grabbed.saveImage("test1.png");  
  
    fbo.end();  
  

It seems to pass the fbo into the ofimage ok, but the image is upside down.

Also when I save as png it is ok, but when I save as jpg the file is empty.

Any ideas?

Should we add this sort of save functionality to the fbo addon to make things easier in future?

what happens if you grab from the screen via the ofImage:

  
grabbed.grabScreen(...)  

as opposed to manually getting the pixels. grabScreen is doing essentially the same thing, right? Or does that not work with the FBO.

I think that should do the proper image flipping thing (since 0,0 is the top left) and so on just a grabbing on a normal screen.

  • z

grabScreen works, but thats not working with the fbo.

The fbo isn’t being drawn to screen, is just a texture in memory.

When you draw into an fbo though
fbo.begin()
– draw something
fbo.end()

fbo.draw()

the fbo is output the right way up on the screen, just not when you pass the pixels into ofImage.

Thanks

I just tested and I could save with ofImage inside the FBO calls… the only tricky thing is that ofImage grabscreen uses ofGetHeight() to flip the coordinates over so this appears to work poorly when they have non matching heights. It seems like swapIn() and swapOut() of the FBO maybe should effect the call to ofGetHeight() since we get problems with functions that are adjusting the 0,0 top left to opengl world.

  
  
myFbo.begin();   // begin = swapIn() and setupScreenForMe()  
	myFbo.clear();  
	  
	ofSetColor(255, 0, 0);  
	ofRect(50,50,100,100);  
	ofRect(200,200,800,800);  
	  
	if (ofGetFrameNum() % 100 == 0){  
		ofImage temp;  
		temp.grabScreen(0, 0, 1024,768);  
		temp.saveImage("blah.jpg");  
	}  
	fboSingleScenes.end(); // swapOut() and setupScreenForThem()  
  

when I switched to theo’s multisample FBO addition (http://forum.openframeworks.cc/t/render-to-texture/371/0), I had to be more explicit which required some poking around the FBO class to make some variables public. I copied the code from here:

http://stackoverflow.com/questions/6825-…-han-window

  
  
myFbo.begin();  
	myFbo.clear();  
	  
	ofSetColor(255, 0, 0);  
	ofRect(50,50,100,100);  
	ofRect(200,200,800,800);  
	  
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, myFbo.fbo);  
	if (ofGetFrameNum() % 100 == 0){  
		ofImage temp;  
		temp.grabScreen(0, 0, 1024,768);  
		temp.saveImage("blah.jpg");  
	}  
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);  
	fboSingleScenes.end();  
  

I hope this code helps!

take care,
zach

What does this do? The function doesn’t trigger for me
if (ofGetFrameNum() % 100 == 0)

When I comment it out it works sort of.

I am drawing into fbo as part of draw function, but the save function is being called on keypress (not inside the draw loop). Is that bad?

  
  
fbo.begin();  
imgSaver.grabScreen(0, 0, width, height);  
imgSaver.saveImage("blah.png");  
fbo.end();  
  

(imgSaver and fbo are allocated with same width & height)

So that for me works, but there is a gap at the top of the image. So I draw a rect at 0,0 in the fbo, then do grabScreen with imgSaver, and the rect is lower. The top 24 pixels of imgSaver (ofImage) are empty.

Also, does saving a JPG work for you on Windows? It doesn’t work for me, even with normal grabscreen (not fbo). I can save as png, but jpg makes an empty 0kb file.

Thanks

What does this do?
if (ofGetFrameNum() % 100 == 0)

takes a screenshot every 100 frames… I just didn’t want to save an image every frame, but I wanted to throw the save into the draw to quickly test it.

jpg seem to work for me here on mac.

I’m not sure about key presses, but you might have much better results putting in a boolean flag and just setting it to true when you press the key, using that to take a screenshot after you draw to the fbo and setting that flag to false at that point so that you only take one picture. I’ve found it’s usually better not to do stuff like grabScreen() in the keypressed function.

take care,
zach

ok so jpg didnt work because i had
imgSaver.allocate(width, height, OF_IMAGE_COLOR_ALPHA);

(it just made an empty file). Maybe we could put some error checking in ofImage and print a console message?

here are some posts which also might be useful
http://forum.openframeworks.cc/t/saveimage-plus-alpha/1145/0
http://forum.openframeworks.cc/t/multithreaded-image-saver/1687/0

thanks. ive not been able to solve my problem yet.

my ofImage and ofxFboTexture have both been allocated like so:

  
  
width = 666;  
height = 1000;  
fbo.allocate(width, height, false);  
imgSaver.allocate(width, height, OF_IMAGE_COLOR);  
  

I draw stuff into my fbo at 0,0 then save the fbo contents using imgSaver like so (within the draw loop):

  
  
fbo.begin();  
imgSaver.grabScreen(0, 0, width, height);  
imgSaver.saveImage("data/caps/"+imageFileName+".jpg");  
fbo.end();  
  

Everything is the right way up and the jpg saves off fine, but I get a pixel buffer problem. Hopefully this image explains…

I don’t think grabScreen is working properly. What do you think?

Thanks

based on http://forum.openframeworks.cc/t/saveimage-plus-alpha/1145/13 i have tried the following code…

setup…

  
  
    fbo.allocate(width, height, false);  
    fbo.clear(0, 0, 0, 1);  
  
    pixels = new unsigned char[width*height*3];  
  
    imgSaver.allocate(width, height, OF_IMAGE_COLOR);  
    imgSaver.setUseTexture(false);  
  

save image (within draw)…

  
  
fbo.begin();  
glPixelStorei(GL_PACK_ALIGNMENT, 1);  
glReadPixels(0, 0, fbo.getWidth(), fbo.getHeight(), GL_RGB, GL_UNSIGNED_BYTE, pixels);  
  
imgSaver.setFromPixels(pixels, fbo.getWidth(), fbo.getHeight(), OF_IMAGE_COLOR);  
imgSaver.saveImage("data/caps/"+imageFileName+".jpg");  
fbo.end();  
  

This seems to work (no pixel buffer problem) but the image is upside down (needs to flip vertically).

Any ideas greatly appreciated.

I’ve been wracking my brains on this for ages. Does anyone have any ideas?

Thanks
Chris

@chris - your problem now is that the image is upsidedown?

http://www.opengl.org/discussion-boards-…-917&page=2

"the problem i think is that glreadPixels starts from Bottom-Left .
how can i change it to starts from Top-Left ?
It can not be changed, all of OpenGL is designed around bottom up framebuffers and textures, many people do not realize this because the bottom up/top down order does not matter on textures (except when using glCopyTexSubImage which operates in native bottom up order).

Generally you want to flip the image before saving your screenshot, assuming the image format you are saving does not support bottom up pixels (TGA and BMP do for example, and use that by default)."

I think the FBO grabScreen incompatabilities means we need to add something to the core, to allow for temporarily setting the width and height to something other then the window width and height (since that’s will mess up with we’re in an FBO that doesn’t have matching resolution)…

-zach

Hmm… if the issue is of an upside down image, might I suggest the ofImage::mirror method I proposed here: http://forum.openframeworks.cc/t/ofimage—mirror-amp;-rotate-functionality/1716/0

This method allows you to flip an ofImage horizontally and/or vertically. Should work at least as a workaround until the underlying issue can be addressed.

I just ran into a similar problem trying to save an image sequence for video capture. I was getting the buffer problem where I would see bits of past frames in the current one.

disabling the vertical flip code in grabScreen seemed to help, but the problem persisted (and video was upsidedown). Eventualy I realized that I was performing grabScreen from within an ofxThread object. I did not realize that all methods of an ofxThread objet will run in a separate thread, not just the threadedFunction. This caused the frame grab code to read from a buffer that was being overwritten all of the time.

My solution was to run grabScreen from within the main thread, in the draw function and pass the pixels into my threaded image saver object.

So I hope this helps if anyone has been experiencing this, just make sure to grab the screen within the main thread. In fact, don’t do any GL calls from within any methods of a threaded object.