How to apply an effect to an image using the mouse coordinates?

Viewed 47

I coded a program on Processing where all the pixels on the screen are scrambled, but around the cursor. The code works by replacing the pixels with a random pixel between 0 and the pixel the loop is currently on. To find that pixel, I used the code (y*width+x)-1. This code, however, is taking pixels from the entire screen. I want the code to instead take the pixels from a 40m square around the mouse coordinates. How can I do this?

import processing.video.*;
Capture video;

void setup() {
  size(640, 480);
  video = new Capture(this, 640, 480);
  video.start();
  
}

void draw() {
  loadPixels();
  if (video.available()){
    video.read();
    video.loadPixels();

    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {
        pixels[y*width+x] = video.pixels[y*video.width+(width-x-1)];
     
     // the code should only be applied 20 pixels around the mouse
      if (dist(mouseX, mouseY, x, y) < 20){
        int d = int(random(0, y*width+x-1));
        pixels[y*width+x] = video.pixels[d]; 
      }
    }    
    }
  }
  updatePixels();
}
1 Answers

You don't need to iterate through all the pixels to only change a few.

Luckily your sketch is the same size as the webcam feed, so you're on the right track using the x + (y + width) arithmetic to convert from a 2D array index to the 1D pixels[] index. Remember that you're sampling from a 1D array currently (random 0, coords). Even if you upate the start/end index that's still a range that will span a few full image rows which means pixels to the left and right of the effect selection. I recommend picking the random x, y indices in 2D, then converting these random values to 1D (as opposed to a single index from the 1D array).

Here's what I mean:

import processing.video.*;
Capture video;

void setup() {
  size(640, 480);
  video = new Capture(this, 640, 480);
  video.start();
}

void draw() {
  loadPixels();
  if (video.available()) {
    video.read();
    video.loadPixels();

    //for (int y = 0; y < height; y++) {
    //  for (int x = 0; x < width; x++) {
    //    pixels[y*width+x] = video.pixels[y*video.width+(width-x-1)];

    //    // the code should only be applied 20 pixels around the mouse
    //    if (dist(mouseX, mouseY, x, y) < 20) {
    //      int d = int(random(0, y*width+x-1));
    //      pixels[y*width+x] = video.pixels[d];
    //    }
    //  }
    //}
    // mouse x, y shorthand
    int mx = mouseX;
    int my = mouseY;
    // random pixels effect size
    int size = 40;
    // half of size
    int hsize = size / 2;
    // 2D pixel coordinates of the effect's bounding box
    int minX = mx - hsize;
    int maxX = mx + hsize;
    int minY = my - hsize;
    int maxY = my + hsize;
    // apply the effect only where the bounding can be applied
    // e.g. avoid a border (of hsize) around edges of the image
    if (mx >= hsize && mx < width - hsize &&
        my >= hsize && my < height - hsize) {
      for(int y = minY; y < maxY; y++){
        for(int x = minX; x < maxX; x++){
          // pick random x,y coordinates to sample a pixel from
          int rx = (int)random(minX, maxX);
          int ry = (int)random(minY, maxY);
          // convert the 2D random coordinates to a 1D pixel[] index
          int ri = rx + (ry * width);
          // replace current pixel with randomly sampled pixel (within effect bbox)
          pixels[x + (y * width)] = video.pixels[ri];
        }
      }
    }
    
  }
  updatePixels();
}

(Note that the above isn't tested, but hopefully the point gets across)

Related