Save Fbo texture to ofPixels Raspberry Pi3


#1

Hi,

I’m struggling to save the texture of an Fbo into an image.
The format has to be very long (300 by 3000).
I’m running a rPi3 with the latest openframeworks armv6 (not nightly build).

After pocking around, I managed to get the Fbo’s texture saved to an image using this code:

 f.allocate(300, 1000,GL_RGBA);
ofPixels pixels;
    ofTextureData texData = f.getTexture().getTextureData();
    
    pixels.allocate(300, 1000,OF_PIXELS_RGBA);
    
    auto glFormat = ofGetGLFormat(pixels);
    

    
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//    ofSetPixelStoreiAlignment(GL_PACK_ALIGNMENT,pixels.getWidth(),pixels.getBytesPerChannel(),pixels.getNumChannels());
//    glBindBufferARB(GL_PACK_ALIGNMENT, texData.textureTarget,texData.textureID);
    glBindTexture(texData.textureTarget,texData.textureID);
//    glReadPixels(0, texData.height, texData.width,texData.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.getPixels());
    glReadPixels(0, -texData.height,texData.width,texData.height, glFormat, GL_UNSIGNED_BYTE, pixels.getData());
//    glReadPixels(0, 0, texData.width,texData.height, OF_PIXELS_RGBA, GL_UNSIGNED_BYTE, pixels.getPixels());
//    glBindTexture(texData.textureTarget,0);
    
    
    string name = ofToString(ofGetFrameNum()) + ".jpg";
    
    ofImageQualityType quality;
    quality = OF_IMAGE_QUALITY_BEST;
    //        quality = OF_IMAGE_QUALITY_WORST;
    ofSaveImage(pixels, name, quality);

my issue is that all I’m only getting the texture which is visible on screen -and repeats at the end of the picture-, when I need an image bigger than the screen (app size is 320 x 500 ):

I tried to change the line

    glReadPixels(0, -texData.height,texData.width,texData.height, glFormat, GL_UNSIGNED_BYTE, pixels.getData());

to

    glReadPixels(0,0,texData.width,texData.height, glFormat, GL_UNSIGNED_BYTE, pixels.getData());

and making more changes, but I think I’m missing something else…

This is my log when I run the app :



sudo make RunReleaseHOST_OS=Linux
checking pkg-config libraries:   cairo zlib gstreamer-app-1.0 gstreamer-1.0 gstreamer-video-1.0 gstreamer-base-1.0 libudev freetype2 fontconfig sndfile openal libcurl glfw3 rtaudio gtk+-3.0 libmpg123 
with PKG_CONFIG_LIBDIR=
[warning] ofAppEGLWindow: init(): X11 not availble on RPI yet, using a native window instead
[notice ] ofAppEGLWindow: setupRPiNativeWindow(): screenRect: 1920x1080
[notice ] ofAppEGLWindow: setupRPiNativeWindow(): windowRect: 320x500
[notice ] ofAppEGLWindow: createSurface(): setting up EGL Display
[notice ] ofAppEGLWindow: createSurface(): EGL Display correctly set 0x1
[notice ] ofAppEGLWindow: createSurface(): no current renderer selected
[notice ] ofAppEGLWindow: createSurface(): default renderer detected
[notice ] ofAppEGLWindow: createSurface(): surface created correctly
[notice ] ofAppEGLWindow: createSurface(): API bound correctly
[notice ] ofAppEGLWindow: createSurface(): -----EGL-----
[notice ] ofAppEGLWindow: createSurface(): EGL_VERSION_MAJOR = 1
[notice ] ofAppEGLWindow: createSurface(): EGL_VERSION_MINOR = 4
[notice ] ofAppEGLWindow: createSurface(): EGL_CLIENT_APIS = OpenGL_ES OpenVG
[notice ] ofAppEGLWindow: createSurface(): EGL_VENDOR = Broadcom
[notice ] ofAppEGLWindow: createSurface(): EGL_VERSION = 1.4
[notice ] ofAppEGLWindow: createSurface(): EGL_EXTENSIONS = EGL_KHR_image EGL_KHR_image_base EGL_KHR_image_pixmap EGL_KHR_vg_parent_image EGL_KHR_gl_texture_2D_image EGL_KHR_gl_texture_cubemap_image EGL_KHR_lock_surface 
[notice ] ofAppEGLWindow: createSurface(): GL_RENDERER = VideoCore IV HW
[notice ] ofAppEGLWindow: createSurface(): GL_VERSION  = OpenGL ES-CM 1.1
[notice ] ofAppEGLWindow: createSurface(): GL_VENDOR   = Broadcom
[notice ] ofAppEGLWindow: createSurface(): -------------
[notice ] ofAppEGLWindow: setupPeripherals(): peripheral setup complete
[notice ] ofAppEGLWindow: setupNativeUDev(): created udev object
[notice ] ofAppEGLWindow: setupMouse(): mouse_fd=5 devicePath=/dev/input/by-path/platform-3f980000.usb-usb-0:1.4:1.0-event-mouse
[notice ] ofAppEGLWindow: setupMouse(): mouse device name =  USB OPTICAL MOUSE
[ error ] ofAppEGLWindow: ioctl GABS failed
[ error ] ofAppEGLWindow: ioctl GABS failed
[notice ] ofAppEGLWindow: setupKeyboard(): keyboard_fd=6 devicePath=/dev/input/by-path/platform-3f980000.usb-usb-0:1.5.3:1.0-event-kbd
[notice ] ofAppEGLWindow: setupKeyboard(): keyboard device name = Mitsumi Electric Apple Extended USB Keyboard
[notice ] ofAppEGLWindow: setupPeripherals(): native event setup complete
saving
saving
saving
saving
saving
saving
saving
saving
saving
saving
[notice ] ofAppEGLWindow: destroyNativeKeyboard()
[notice ] ofAppEGLWindow: destroySurface(): destroying EGL surface

Help?

Thks,

P

ofApp.cpp (1.9 KB)


#2

I would try a couple of things:

  1. put everything FBO/pixels related into draw. I’ve had some quirks doing things in update
  2. try smaller sizes first and maybe increase the GPU allocation to see if it helps with larger sizes (if #1 doesn’t solve)
  3. allocate the FBO later (say ofGetFrameNum() == 10). more of a last resort but may help debug

#3

have you tried fbo.readToPixels(…) some times there’s some limitation in the formats you can use but that should work


#4

Hi,

Thanks for replying :slight_smile: , I have tried first to do that fbo.readToPixels(…), but the images come out totally blank.
I tried again just now, using all the formats for the pixels for the allocation, but it still comes out blank:


 ofPixels pixels;
 ofTextureData texData = f.getTexture().getTextureData();
    ///     OF_PIXELS_RGB
	///     OF_PIXELS_RGBA
	///     OF_PIXELS_BGRA
	///     OF_PIXELS_MONO
    pixels.allocate(texData.width, texData.height, OF_PIXELS_BGRA);
    
    f.readToPixels(pixels);

@jvcleave, will try your advice now and let you know:

I tried to

  1. put everything into the draw function,
  2. change the config.txt and add gpu_mem=512 ( using sudo nano /boot/config.txt )
  3. wait for the frame 100 to allocate the fbo, then try to draw:
std::cout << ofToString(ofGetElapsedTimef) << std::endl;
    if(ofGetFrameNum() > 100){
        
        if(fboAssigned){
            
            f.allocate(300, 700);
            fboAssigned = false;
        }
        activated = true;
    }
    if(activated){
        
        f.begin();
        ofClear(255, 0,0);
        ofDrawLine({0,0,200},{150, 150,0});
        ofDrawCircle({0,500,0},40);
        f.end();
        f.draw(0,0);
        
        ofImage save;
        
        ofPixels pixels;
        ofTextureData texData = f.getTexture().getTextureData();
        
        pixels.allocate(texData.width,texData.height,OF_PIXELS_RGBA);
//        f.readToPixels(pixels);
//
        ofSetPixelStoreiAlignment(GL_PACK_ALIGNMENT,pixels.getWidth(),pixels.getBytesPerChannel(),pixels.getNumChannels());
        glBindTexture(texData.textureTarget,texData.textureID);
        glReadPixels(0, 0, texData.width,texData.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.getData());
        string name = ofToString(ofGetFrameNum()) + ".png";
        ofImageQualityType quality;
        quality = OF_IMAGE_QUALITY_BEST;
        ofSaveImage(pixels, name, quality);
    }

Still no luck…
Thks


#5

Here is how ofxOMXPlayer does it internally - I know that still works

//setup
int dataSize = videoWidth * videoHeight * 4;
pixels = new unsigned char[dataSize];
fbo.allocate(videoWidth, videoHeight, GL_RGBA);
texture.allocate(videoWidth, videoHeight, GL_RGBA);

//in update loop
fbo.begin();
ofClear(0, 0, 0, 0);
texture.draw(0, 0);
glReadPixels(0,0,videoWidth, videoHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
fbo.end();

//later to test in update
ofTexture pixelOutput;

if (!pixelOutput.isAllocated()) 
{
  pixelOutput.allocate(omxPlayer.getWidth(), omxPlayer.getHeight(), GL_RGBA);
}
pixelOutput.loadData(omxPlayer.getPixels(), omxPlayer.getWidth(), omxPlayer.getHeight(), GL_RGBA);

//draw
pixelOutput.draw(0, 0);


#6

I tried, not sure I did it right, will try again later today, thks @jvcleave, :slight_smile: .

[EDIT]
Amazing, @jvcleave, you solved it.

if anyone had the same problem, here is the solution which worked for me:

//ofApp.h
    unsigned char* pixels;
//ofApp.cpp in setup

    //setup
    int dataSize = videoWidth * videoHeight * 4;
    pixels = new unsigned char[dataSize];
    fbo.allocate(videoWidth, videoHeight, GL_RGBA);

//ofApp.cpp in update
fbo.begin();
    ofClear(255, 0,0);
    ofDrawLine({0,0,200},{150, 150,0});
    ofDrawCircle({0,700,0},40);
    glReadPixels(0,0,videoWidth, videoHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
    fbo.end();
    string name = ofToString(ofGetFrameNum()) + ".jpg";
    ofImage image;
    image.setFromPixels(pixels, videoWidth, videoHeight, OF_IMAGE_COLOR_ALPHA);
    image.saveImage(name);