Screenshot saving slow on Raspberry Pi with ofxRPiCameraVideoGrabber

I am making a simple Photo Booth app for a Raspberry pi, and am running into some problems with using ofImage.saveFile. At the point where I write the image to disk, the app always freezes for about 10 seconds, presumably because the computer is overwhelmed with the task of saving to the SD card.
I am using the ofxRPiCameraVideoGrabber addon and the raspberry pi camera board.

The image to be saved is 1280x720, and saving a smaller image does reduce the freeze time, but it still seems like I might be doing something wrong? Surely writing a 200px x 200px image to disk shouldn’t cause a 4 second freeze? Moving the saveFile command to different places in the code doesn’t seem to affect anything either.

I am very new to Openframeworks, so I wondered if there might be some tricks to managing this kind of thing? I’ve put the project as it is on Github in case anyone has any brainwaves - Any suggestions would be gratefully received.

Thanks!

Take a look at this thread

Yeah - that is a bit excessive. There are a couple of ways you could make it a bit faster.

I doubt the bottleneck is with the file writing and think that resizing the image may actually slow the process as it is probably hitting the slower CPU (as opposed the fast GPU) to do it.

I see you are using ofImage::grabScreen - that appears to be allocating pixels every time which is expensive.

To use ofxRPiCameraVideoGrabber pixel access

in ofApp.h

int updateCounter;
bool doSaveImage;

In ofApp::setup

use this setting:

omxCameraSettings.enablePixels = true;
updateCounter=0;
doSaveImage = false;

and later

videoGrabber.setup(omxCameraSettings);
videoGrabber.disablePixels(); //This will disable the slow pixel updating until you need it

So it looks like you are using the spacebar to take the photo. Do something like this

if(key == ' ')
{
    doSaveImage = true;
}

And then back up in ofApp::update()

if(doSaveImage) 
{
    videoGrabber.enablePixels();
    updateCounter = ofGetFrameNum();  //pixels need to be updated - waiting a frame
}
if(doSaveImage)
{
    if(ofGetFrameNum() > updateCounter) 
    {
        string filePath = ofToDataPath(ofGetTimestampString()+".png", true);
        ofSaveImage(videoGrabber.getPixels(), filePath);
        doSaveImage = false;
        videoGrabber.disablePixels();
    }
}

If you need to capture the FBO content you can see how the addon does it

Thanks for such a detailed reply. The reason I was using grabScreen rather than the video pixel access was because I really want the saved image to include the overlay watermarks. To my understanding this method would save the raw camera image and Fbo content seperately? Or am I missing something?

So to capture the FBO content you can do something like this in ofApp to capture the contents

//ofApp.h
unsigned char * pixels;

//ofApp::setup 
int dataSize = fbo.getWidth() * fbo.getHeight() * 4;
pixels = new unsigned char[dataSize];

//ofApp::update 
   
fbo.begin();
	glReadPixels(0,0, fbo.getWidth(), fbo.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, pixels);	
fbo.end();

string fileName;
if(doSaveImage)
{
	if(doRawSave)
	{
		fileName = ofToDataPath(ofGetTimestampString()+".raw", true);
		ofBuffer buffer((const char*)pixels, dataSize);
		ofBufferToFile(fileName, buffer, true);
	}else
	{
		fileName = ofToDataPath(ofGetTimestampString()+".png", true);
		ofImage image;
		image.setFromPixels(pixels, fbo.getWidth(), fbo.getHeight(), OF_IMAGE_COLOR_ALPHA);
		image.saveImage(fileName);
	}
}

I have actually been updating the addon recently and did a quick/dirty saveImage similar to the above

It was slower than I expected so I tried the “doRawSave” to see if it were any faster.
It seemed to be much faster but then I had to open the file in Photoshop and specify the dimensions/# of channels