We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpPrograms › Performance issues on a simple app
Page Index Toggle Pages: 1
Performance issues on a simple app (Read 565 times)
Performance issues on a simple app
Apr 27th, 2009, 10:26am
 
Hi people. Once again, newbie requires your help Smiley Let's see if I can make me clear. English isn't my mother tongue, so I apologize in advance.
Well, I'm writing this very simple app where an image is shown. If the user clicks and drags the mouse, a new underlying image will be unveiled, but only on those points where the mouse has passed by. So it would look like if we were having three layers in photoshop, and we were brushing off the one on top. The result is that we would be able to see the underlying one only at the mouse's track.
I'm aware that it's not the best explanation, but I guess the code would clarify it a bit Tongue
Well, my problem is that after writing such a program, the code that runs is DAMN SLOW. What I basically do is to print a circle (the rubber/brush stroke) of a certain dimension pixel by pixel, accesing the pixels array of the image that I want to show. And there it is the problem. The bigger it is the radius of the stroke, the slower it becomes the program.
I tried many approaches. Tried to use P2D anda JAVA2D, but OPENGL turned out to be slightly faster on this. Tried as well to deactivate the error management in OPENGL, since I read that it's performance consuming, but still, no big improvements. I also tried to print each pixel in different ways, like 1x1 rects, 1x1 ellipses, point, etc. The one that seemed to work better was the rect approach, but anyway, I never manage to get more than 30 FPS at a 1600x1200 resolution (it actually drops from 300 FPS to 30 FPS!!).
I tried another different approach, which was using the method get, and printing a square section of the new image as big as the radius that I had defined. It works really smoothly this way, but I still need the effect of a circular stroke since the app is going to be used together with a tablet.
So to summarize, what I'm asking is for advice about how to optimize my code, and if it's not possible, some recommendation in general.
I was opening the task manager while playing with the sketch, and I realized that the processor was having no more than a 60% of load. Could it be possible as an approach to push the JVM to use all the resources available?
Anyway, here is the simplified version of the code. You should put a couple of images in your own for it to work. Resolution 1600x1200 pixels. Another thing is that if you press ENTER, you switch from the get mode to the pixel by pixel with recs mode, so you can easily compare performance between both. Hope it helps:

Code:
import processing.opengl.*;

int BRUSH_RADIUS = 30;
boolean WITH_GET = true;
PImage baseLayer, newLayer;

void setup(){
 // Engine
 size(1600,1200,OPENGL);  hint(DISABLE_DEPTH_TEST);  hint(DISABLE_OPENGL_ERROR_REPORT);
 // Options
 noStroke();  frameRate(300);
 // Load images
 baseLayer = loadImage("layer1.jpg");
 newLayer = loadImage("layer2.jpg");
 // First image
 image(baseLayer, 0, 0);
}

void draw(){
 int x = mouseX;
 int y = mouseY;
 if(mousePressed){
   // Circular shape by drawing pixels/(1x1)squares. Slow performance.
   if(!WITH_GET){
     for(int i = x-BRUSH_RADIUS; i < x+BRUSH_RADIUS; i++)
       for(int j = y-BRUSH_RADIUS; j < y+BRUSH_RADIUS; j++){          
         if(checkPoint(x, y, i, j)){
           // Get pixel from the new layer
           color c = newLayer.pixels[j*width + i];
           // Print pixel on the screen
           pushStyle();
           fill(c);
           rect(i,j,1,1);
           popStyle();
         }  
       }
   }
   // Square shape. Fast performance.
   else{
     PImage tmp = newLayer.get(x - BRUSH_RADIUS, y - BRUSH_RADIUS, 2*BRUSH_RADIUS, 2*BRUSH_RADIUS);
     image(tmp, x - BRUSH_RADIUS, y - BRUSH_RADIUS);
   }
 }
}
// Discards the points that dont belong to the circle with center (centerX, centerY) and radius BRUSH_RADIUS
boolean checkPoint(int centerX, int centerY, int pointX, int pointY){
 float pointValue =  sq(pointX - centerX) + sq(pointY - centerY);
 if (pointValue < sq(BRUSH_RADIUS) && (pointX >= 0) && (pointX < width) && (pointY >= 0) && (pointY < height))
   return true;
 else return false;
}
// Pressing enter toggles rendering mode
void keyPressed(){
 if(keyCode == ENTER)
   if(WITH_GET)
     WITH_GET = false;
   else WITH_GET = true;
}


Thank you very much for all your help in advance. I mean it!

/F
Re: Performance issues on a simple app
Reply #1 - Apr 27th, 2009, 2:11pm
 
Some generic remarks about the first algorithm:
- No need for push/popStyle, it is used only to avoid disturbing another part of the program. At worst, you can do it once, around the outer loop.
- point(), ellipse(), rect() are relatively high level primitives. You found out it is faster to get the pixel data directly (not using get()), you can do the same to set the pixel data: do loadPixels before the loop, updatePixels after, and you probably have optimal speed.
- Oh, and pre-compute sq(BRUSH_RADIUS) in setup, one computation less.
- And perhaps separate the comparisons to screen bounds: doing them (and returning) before computing sq() calls might help on the bounds of the sketch.

For arbitrary shapes, you can also use mask. I shown an example in Re: Graphic as an image mask. Not necessarily faster, but more flexible.
Re: Performance issues on a simple app
Reply #2 - May 3rd, 2009, 5:10am
 
Thanks a lot for the answer!
In the end I went for the mask approach. It did its work way better.
About load and updatePixels, loading them and updating them on each loop of draw was killing my program. It turned out to be faster keeping on using set for drawing the pixel instead.

/F
Re: Performance issues on a simple app
Reply #3 - May 4th, 2009, 2:25am
 
Fer wrote on May 3rd, 2009, 5:10am:
About load and updatePixels, loading them and updating them on each loop of draw was killing my program. It turned out to be faster keeping on using set for drawing the pixel instead.

Ah, that might be because you are in OpenGL mode. In some other modes, using set() might be slower! Smiley
Page Index Toggle Pages: 1