ofFBO and ofxCV issue

Hi OFers

I’m trying to use the blur function in ofxCv so that I can draw circles then blur them. The only way I have found that works its:

  1. draw the circles to an fbo
  2. transfer the fbo to an image
  3. use the blur function on the image

#include “ofApp.h”

void ofApp::setup() {
ofSetVerticalSync(true);
ofEnableSmoothing();

back1.set(160);
back2.set(80);

fbo.allocate(ofGetWidth(), ofGetHeight());
pixels.allocate(ofGetWidth(), ofGetHeight(), OF_IMAGE_GRAYSCALE);
fbo.begin();
ofClear(255);
ofSetColor(255);
ofSetCircleResolution(64);
ofNoFill();
for(int i = 0; i < 200; i++){
    ofDrawCircle(ofRandom(ofGetWidth()), ofRandom(ofGetHeight()), ofRandom(10, 40));
}
fbo.end();
fbo.readToPixels(pixels);

image.setFromPixels(pixels);

ofxCv::GaussianBlur(image, 30);
image.update();

}

void ofApp::update() {
}

void ofApp::draw() {
ofBackgroundGradient(back1, back2, OF_GRADIENT_CIRCULAR);
ofSetColor(255, 170);
image.draw(0, 0);
ofSetColor(255, 30);
fbo.draw(0, 0);

}

ok now if I want to keep the thing efficient I might transfer the blurred image back to the fbo and draw as required (note that I’m not doing this in the code above). This seems a bit clunky. Should I draw my circles directly into an image (I’ve been searching from many hours to work out how to do that and I still don’t know), blur them and then transfer to an fbo? OR is there a way to use ofxCv on an fbo?

So the specific answers I would like relate to:

  1. can you use ofxCv directly with an fbo and if so how?
  2. can you draw shapes into a ofImage and if so how?
  3. is there a better way to blur drawn images that I haven’t considered?

thanks in advance
Peter Mc

Hi petermc,

Probably.
fbo.readToPixels(pixels) can be an expensive operation, and the GPU can blur things faster than the CPU.

I don’t think. The fbo pixels live in the graphics card memory, and ofxCv works with images in the standard RAM. There is perhaps an addon which use the GPU to perform openCV calculations, but in your case I don’t think this is the best option.

I’m not sure. Perhaps with the cairo renderer? Or with some addon which provide bitmap drawing tools? Or directly with openCV primitive drawing tools (don’t know if they exist). But this time again I don’t think this is the best option.

You can use the GPU to blur things. I think it will be the more convenient and the fastest way to do it.
Take a look at the examples\shader\09_gaussianBlurFilter example in your OF folder, or at these addons: ofxBlur, ofxIterativeBoxBlur (don’t know if one is better than the other in your case)

Thanks for you comments lilive. I tried out the gaussian shader you suggested and it didn’t do a great job but I guess I can find other shaders that might work better. One thing I’m confused about though is that to use the shader you do a draw. eg:

fboBlurOnePass.begin();
shaderBlurX.begin();
shaderBlurX.setUniform1f("blurAmnt", 10);
image.draw(0, 0);
shaderBlurX.end();
fboBlurOnePass.end();

fboBlurTwoPass.begin();
shaderBlurY.begin();
shaderBlurY.setUniform1f("blurAmnt", 10);
fboBlurOnePass.draw(0, 0);
shaderBlurY.end();
fboBlurTwoPass.end();

is the image being drawn into GPU or transfered from RAM to GPC? Also on the second pass the fbo from the first pass is drawn. Is this happening in the GPU?

thanks

Peter Mc

Each time you draw an image, you use a shader. A simple
image.draw(0, 0);
use a shader. You have nothing to do, it happens under the hood, but a shader is used. This is the default OF shader, which allow you to place the image at the upper left corner of the window, at the right size, and to modify its color with ofSetColor(), if you want.

This is the same when you do

shaderBlurX.begin();
shaderBlurX.setUniform1f("blurAmnt", 10);
image.draw(0, 0);
shaderBlurX.end();

except that this time you’re using a custom shader. This shader doesn’t allow you to change the colors with ofSetColor(), but allows you to horizontaly blur the image. A shader only do its work during the rendering process, this is why you have to draw something to make it work.

In your case, you can replace the image.draw() by your ofDrawCircle().

To learn more about the rendering process, the graphics pipeline, and the shaders, see http://openframeworks.cc/ofBook/chapters/shaders.html

All happens into the GPU.
The image pixels are already loaded into the GPU, into an ofTexture (see http://openframeworks.cc/ofBook/chapters/openGL.html#textures)

fboBlurOnePass.begin();
shaderBlurX.begin();
shaderBlurX.setUniform1f("blurAmnt", 10);
image.draw(0, 0);
shaderBlurX.end();
fboBlurOnePass.end();

This draw the image, horizontaly blurred, into a fbo. This means that the pixels of the image texture are processed by the shader, and the resulting pixels are put into the fbo pixels, which live into the graphics card.

fboBlurTwoPass.begin();
shaderBlurY.begin();
shaderBlurY.setUniform1f("blurAmnt", 10);
fboBlurOnePass.draw(0, 0);
shaderBlurY.end();
fboBlurTwoPass.end();

This draw the content of fboBlurOnePass (the horizontaly blurred image) into fboBlurTwoPass, doing a vertical blur.
fboBlurTwoPass now contains the blurred image. You can draw this result to the screen, with

fboBlurTwoPass.draw(0, 0);

Note that the second fbo in this example is not mandatory. You can do

shaderBlurX.begin();
shaderBlurX.setUniform1f("blurAmnt", blur);
image.draw(0, 0);
shaderBlurX.end();
fboBlurOnePass.end();

// no need for a second fbo here, we can draw directly to the screen
shaderBlurY.begin();
shaderBlurY.setUniform1f("blurAmnt", blur); 
fboBlurOnePass.draw(0, 0);
shaderBlurY.end();

for the same result.

Yes. You can try the addons I pointed before.

1 Like

lilive, thanks for taking the time to explain that, it helps a great deal.