Slowdown from image manipulation

I’ve been encountering some pretty massive slowdown when I try to manipulate large images. Whenever I use images close in size to the display size, there will be a huge framerate drop (from about 60 to as low as 8 or 9) unless the image is completely unrotated, and not resized at all (displayed at the same exact size as the image itself). I can’t remember ever experiencing this before, but it’s possible that I’ve just never used an image large enough to have an effect. So is this something that other people have experienced? Is there any way to avoid this, if I need to scale or rotate large images like this?

Here is a simple sketch to illustrate this issue. It loads an image called “image.jpg” and displays it at its natural size. Pressing the 0 - 6 keys will apply some sort of transformation to the image (e.g. scaling it up, rotating it, or translating it). In nearly all of the cases, the framerate drops considerably (down to about 10 fps on my machine).

PImage img;
int mode;

void setup() {
  img = loadImage("image.jpg"); // Any image works. Mine happens to be 1280x800.
  size(displayWidth, displayHeight);
  mode = 0;
}

void draw() {
  background(0);
  imageMode(CENTER);
  switch (mode) {
    case 0: // Standard. Display image in the center of the screen. Displayed at "natural" size of image.
      image(img, width / 2, height / 2, img.width, img.height);
      break;
    case 1: // Display image at center of screen. Slightly taller than "natural" size and thus distorted.
      image(img, width / 2, height / 2, img.width, img.height + 100);
      break;
    case 2: // Display image at center of screen. Scaled uniformly.
      image(img, width / 2, height / 2, img.width * 2, img.height * 2);
      break;
    case 3: // Display image at center of screen. Scaled uniformly using scale() method.
      scale(2);
      image(img, width / 4, height / 4, img.width, img.height);
      scale(0.5);
      break;
    case 4: // Display image at natural size rotated 15 degrees.
      rotate(radians(15));
      image(img, width / 2, height / 2, img.width, img.height);
      rotate(radians(-15));
      break;
    case 5: // Display image at natural size. First use scale() method to scale up, then counteract by displaying image uniformly scaled down.
      scale(2);
      image(img, width / 4, height / 4, img.width / 2, img.height / 2);
      scale(0.5);
      break;
    case 6: // Display image translated.
      translate(50, 50);
      image(img, width / 2, height / 2, img.width, img.height);
      translate(-50, -50);
      break;
    default:
      break;
  }
  fill(0);
  noStroke();
  rect(180, 180, 80, 50);
  fill(255);
  text(frameRate, 200, 200);
  text("Mode: " + mode, 200, 220);
}

void keyPressed() {
  switch (key) {
    case '1':
      mode = 1;
      break;
    case '2':
      mode = 2;
      break;
    case '3':
      mode = 3;
      break;
    case '4':
      mode = 4;
      break;
    case '5':
      mode = 5;
      break;
    case '6':
      mode = 6;
      break;
    default:
      mode = 0;
      break;
  }
}

I recommend to do a proper resize() in setup() once and for all instead of using image() with 5 parameters

Use image() only with 3 parameters otherwise it slows things down

Chrisir

3 Likes

Okay, I can do that. But it seems like that still won’t bring any improvements to rotating images, or using scale() to zoom in or out.

If you must resizecan image do a one-time conversion to a buffer, rather than redoing that same conversion every single frame. Then even if you get a 100ms frame, it is only a single frame.

Also, don’t change the image if you can change the view instead, eg with translate, rotate, or scale. No reason to alter the PImage img data in those cases, just call image(img, x, y) after the appropriate matrix operations on the view.

1 Like