Drowning – Image manipulation

Since October the 10th is World Mental Health Day, I decided to make this week’s assignment somehow related to Depression.
As I was looking for inspiration, I came across this picture: I liked the scattered effect, so I decided to create something similar with Image pixels. After some brainstorming, I got the idea to represent the feeling of depression with a drowning animation and a wave crash effect for the pixels.

The Point class

To do this, I first thought about creating a Point class. Every pixel, of the image  used, would be represented by a point. The class includes a drawPoint() function that draws a point at the x and y positions of the pixel with the color of that pixel, and then updates its y-position to give a “bouncing” effect. There is a gravity variable that pulls down the point. When the point reaches the bottom of the screen(or a certain boundary), we multiply by -1 so that it goes back up. There is also slowDown variable to reduce the distance the point travels every time it goes back up or down.

Here is the code for this class:

class Point{
  color col;
  float x,y,vy, gravity, slowDown;
  
  Point(int x2,int y2,color col2){
    x= x2;
    y= y2;
    col= col2;
    vy = 0;
    
    gravity = 1;
    slowDown = random(0.5,0.7);
  }
  
  void drawPoint(){
    vy += gravity;
    y += vy;
    
    if (y>= height/1.5){
      y = height/1.5;
      vy *= -1;
      vy *= slowDown;
    }
    strokeWeight(2);
    stroke(col);
    point(x,y);
  
  }

}

Failed Attempts

At first, I tried to keep it simple. So, I wanted to iterate through the image’s pixel, and for every pixel, add a new Point to the array of points (pointsArray). Then, I would iterate through the points and draw them.
However, this made the pixels of the transparent background also get drawn, which resulted in there being too many pixels. This made the animation super slow and it didn’t give the effect I was looking for.
Here is how it looked like:

I didn’t know how to approach fixing this, so with a lot of research and help from online forums, I got the idea to create a new image. This image would be the “difference” (difference in the color of the pixels) between my image and a black image (color values are zeros). This gives us a new image that contains my image but with a black background. Then, all I had to do was iterate through the image pixels and only populate the pointsArray if the pixel isn’t black. (For this to work, make sure the image you’re using doesn’t have any black parts that you want to be drawn.)
However, this resulted in the image being still. This is what was displayed when I ran the program:

solution

To solve this, I turned to Google once again. Apparently, this was happening because the for loop (that makes the pixels of our new image) nested inside the draw() loop makes the points continuously draw in their initial spot because the new image is consistently being made.
To solve this, I again made the new image be the difference between my image and a black image, BUT THEN, it is turned into the difference between my image and itself. This means that the new image becomes fully black when the draw() is called for the second time, so it isn’t being considered anymore.

I also added a noise wave at the bottom using the code from an example on processing.org (https://processing.org/examples/noisewave.html)

Here is the code for that:

int nPixels;
int imgWidth = 480;
int imgHeight =240;
int[] toBlack, difference;
PImage img, differenceImage;
Point[] pointsArray;
int index;
float yoff = 0.0;


void setup(){
  size(700,700);
  //initializing all variables
  nPixels = imgWidth*imgHeight;
  pointsArray = new Point [nPixels];
  difference = new int[nPixels];
  toBlack = new int[nPixels];
  differenceImage = createImage (imgWidth,imgHeight,RGB); //create a new empty image to be filled with pixels
  img = loadImage("falling.png");
  img.loadPixels();
}
 
void draw(){
  background(51);
  
  for (int i = 0; i<nPixels; i++){
    color img_color = img.pixels[i];
    color toBlack_color = toBlack[i]; //here this array just has the values: 0
    //so the first time the difference is made, it only gets rid of the transparent background
    
    //setting the color variables for the pixels of the new image created
    int r =int(red(img_color)) - int(red(toBlack_color));
    int g =int(green(img_color)) - int(green(toBlack_color));
    int b =int(blue(img_color)) - int(blue(toBlack_color));

    difference[i] = color(r,g,b);
    toBlack[i] = img_color; //we set this to img_color so that from now on, the difference will always give a black pixel
    //and so these pixels won't be considered from now on
}
  //creating the difference image using the array of colors/pixels
  differenceImage.loadPixels();
  for (int i=0; i<img.pixels.length;i++){
    differenceImage.pixels[i] = difference[i];
  }
  //updating its pixels
  differenceImage.updatePixels();
  
  //populating the Point array with points only when the pixels aren't black!
  int index = 0;
  color col;
  for (int y=0; y<imgHeight;y++){
    for (int x=0; x<imgWidth; x++){
      if(differenceImage.get(x,y)>color(20)){ //needs to be not black(>0) but I put 10 just to be safe
        col = color(img.get(x,y));
        pointsArray[index] = new Point(int(map(x,0,imgWidth,0,width)),int(map(y,0,imgHeight,0,height/2)),col); 
      }
      index++;
    }
  }
  //drawing a point for each pixel and moving it up and down like a wave crash
  for (int i=0; i<pointsArray.length;i++){
    if (pointsArray[i]!=null){ //some of the points are empty because we skipped the index where the pixel is black
      pointsArray[i].drawPoint();
    }
  }
  //waves. code copied from an example on processing.org 
  fill(0,25,35);
  noStroke();
  beginShape();
  float xoff = 0;
  for (float x = 0; x <= width; x += 10) {
    float y = map(noise(xoff, yoff), 0, 1, 400,470);
    vertex(x, y);
    xoff += 0.05;
  }
  yoff += 0.01;
  vertex(width, height);
  vertex(0, height);
  endShape(CLOSE);

}

 

Final outcome

3 thoughts on “Drowning – Image manipulation”

  1. This idea is so cool and I always admire your problem-solving approach to things! I think your code will be a great resource to help me understand what I can do with pixel arrays too 🙂

  2. One thing that might be nice is to give each point a different gravity, so they all fall at different rates. And then when they bounce up you don’t get those implied lines. You can also look at collision detection with the box2d library, and make each part actually break over that wave itself. And then you might be able to make the wave move too!

Leave a Reply