Interactive Image Rasterization with Mouse

Hi everyone,
I’m pretty new to Processing and I’m trying to create a fun pixelate tool for image. I’ve archived the effect for the image by using this tutorial, which include drawing grids of rectangles using loop and get the color from the image to create the pixelated effect.

Now I want to make it to the next level where I can input the area where the effect should apply. Basically, draw a rectangle using mouse on the canvas, and the effect applies only to that area. Similar to this awesome studio work https://www.instagram.com/p/B885QDjicYE/. I tried to use the void mousePressed and mouseReleased but the result is very weird.

PImage test_image;
int startX, startY, endX, endY, tileSize;

void setup() {
  startX = 0;
  startY = 0;
  endX = 0;
  endY = 0;
  tileSize = 12;
  smooth();
  size(704, 288);
  test_image = loadImage("bite-1.png");
  background(test_image);
}

void mousePressed() {
  startX = mouseX;
  startY = mouseY;
}

void mouseDragged() {
  endX = mouseX - startX;
  endY = mouseY - startY;
  noFill();
  rect(startX, startY, endX, endY);
} 
void draw() {
  background(test_image);
  stroke(155);
  rect(startX, startY, endX, endY);
  noFill();

  for (int y = startY; y < endY; y += tileSize) {
    for (int x = startX; x < endX; x += tileSize) {
      color c = test_image.get(x, y);

      pushMatrix();

      translate(x, y);
      fill(c);
      //rectMode(CENTER);
      noStroke();
      rect(0, 0, tileSize, tileSize);
      resetMatrix();

      popMatrix();
    }
  }
}



void mouseReleased() {

  loadPixels();
  test_image.loadPixels();
  test_image.pixels = pixels;
  test_image.updatePixels();
}

I really appreciate any helps! Thank you in advance.

2 Likes

The Instagram example you linked to is going to be a lot more complex, since it’s animated and there are multiple regions. One option would be a custom class that stores the various regions (with values for x, y, width, and height, etc). You could then store those regions in an ArrayList, adding a new one each time the mouse is released. I think you have the basics there already!

3 Likes

I ported it to p5.js. Is this the bug you’re talking about? (Where the pixelization effect only partially fills the selection?):

This might have to do with a translate() error, because when I start dragging from (0,0), it looks better:

Or perhaps these are specific to p5.js! One big difference between p5.js and Java Processing is push() vs pushMatrix(), but I don’t use them often enough to say anything worthwhile haha. But it’s a place to start!

1 Like

Definitely gonna look Array thingy! I’m relatively new to the program as a graphic designer, still have to learn a lot of new phrases! thank you!

I’m using P3 on Mac and that’s the exact weird result I got! There must be something wrong with startX and startY variables that do not work with translate(). I’m gonna need a work-around, thank you!

I spent more time than I’d like to admit tracking down the bug. The problem stemmed from the fact that I thought endX and endY were world-coordinates (You should have named them height and width :grin:).

Anyways, you’re comparing y and x to the width of the box. So imagine the selection got moved back to (0,0). Your for-loops think "Oh, we reached the “edge”, we’re done!

To fix this, you’re gonna want to add the start coordinates to the end-variables like so:

for (int y = startY; y < startY + endY; y += tileSize) {
  for (int x = startX; x < startX + endX; x += tileSize) {

All that being said, good luck with this!

1 Like

Hi! Sorry for this so late late reply! i got caught up into my regular design-related jobs (resumed from weeks of working from home) and didn’t have time to update my progress. Now I did! Your codes work beautifully as in my vision! And bravo to the adjustment of startX startY so the “pixelated patch” stay in a defined grid form across the image! My non-logical-brain would never able to think of that. Also I did some minor extra code lines so the drawing could be done in any kind direction, not just from-left-to-right/top-to-bottom. Here’s the link for online editor! https://www.openprocessing.org/sketch/890933 (yes, I am also getting used to browser processing for easier sharing!).
Oddly, the original code I did in P3 sketch, I could draw over and over the image, while the OpenProcessing sketch keep clearing the image every time I try to draw over it. I guess the loadPixels updatePixels doesn’t work on browser?
here’s the original code in P3

PImage test_image;
int a = 1,startX, startY, endX, endY, tileSize, pixelSize;

void setup() {
  startX = 0;
  startY = 0;
  endX = 0;
  endY = 0;
  pixelSize = 50;
  
  smooth();
  size(1000, 1000);
  test_image = loadImage("atest.jpg");
  background(test_image);
  
}

void mousePressed() {
  
  tileSize = pixelSize * a;
  a = a*1;
  startX = mouseX - mouseX % tileSize;
  startY = mouseY - mouseY % tileSize;
}

void mouseDragged() {
  endX = pmouseX + pmouseX % tileSize;
  endY = pmouseY + pmouseY % tileSize;
  if ((startX < endX) && (startY > endY)){
  drawRastered2();
  } else if ((startX < endX) && (startY < endY)){
    drawRastered3();
  } else if ((startX > endX) && (startY < endY)){
    drawRastered4();
  } else {
    drawRastered1();
  }
  
  
} 

void draw() {
  if ((startX < endX) && (startY > endY)){
  drawRastered2();
  } else if ((startX < endX) && (startY < endY)){
    drawRastered3();
  } else if ((startX > endX) && (startY < endY)){
    drawRastered4();
  } else {
    drawRastered1();
  }
  
}

void drawRastered1() {
  background(test_image);

  // Draw the pixelation

  for (int y = startY; y > endY; y -= tileSize) {
    for (int x = startX; x > endX; x -= tileSize) {
      int c = test_image.get(x + tileSize/2, y + tileSize/2);
      fill(c);
      noStroke();
      rect(x, y, tileSize, tileSize);
      
    }
  }

}
void drawRastered2() {
  background(test_image);

  // Draw the pixelation

  for (int y = startY; y > endY; y -= tileSize) {
    for (int x = startX; x < endX; x += tileSize) {
      int c = test_image.get(x + tileSize/2, y + tileSize/2);
      fill(c);
      noStroke();
      rect(x, y, tileSize, tileSize);
      
    }
  }

}
void drawRastered3() {
  background(test_image);

  // Draw the pixelation

  for (int y = startY; y < endY; y += tileSize) {
    for (int x = startX; x < endX; x += tileSize) {
      int c = test_image.get(x + tileSize/2, y + tileSize/2);
      fill(c); 
      noStroke();
      rect(x, y, tileSize, tileSize);
      
      
    }
  }

}
void drawRastered4() {
  //background(test_image);

  // Draw the pixelation

  for (int y = startY; y < endY; y += tileSize) {
    for (int x = startX; x > endX; x -= tileSize) {
      int c = test_image.get(x + tileSize/2, y + tileSize/2);
      fill(c);
      noStroke();
      rect(x, y, tileSize, tileSize);
      
    }
  }

}

// Draw the bounding box
//stroke(255,0,0);
//rect(startX, startY, endX - startX, endY - startY);
//noFill();
// noStroke();

void mouseReleased() {
  endX = pmouseX + pmouseX % tileSize;
  endY = pmouseY + pmouseY % tileSize;
  
  println(a);

  loadPixels();
  test_image.loadPixels();
  test_image.pixels = pixels;
  test_image.updatePixels();
}
1 Like
2 Likes

Haha, no worries. I can’t count the number of times I’ve made similar mistakes. Practice makes perfect.