How do I write a particle system to evolve to form an uploaded black and white image?

edited September 2016 in How To...

I want to start out with a window of randomly placed particles and have them generation by generation, form into the shape of an image made up of only Black and White values. The population will be different particle systems. Their "fitness score" will be based on the similarity to the target image. How do I compare the pixels in the processing window to that of an uploaded image?

Answers

  • So what code do you have so far? A blank sketch? A Particle class? Can you load the image?

  • All I have is a random particle generator.

    PVector position = new PVector();
    Particle[] particles = new Particle[50];
    void setup() {
      background(255);
      size(600,600);
    
      for(int i = 0; i < particles.length; i++) {
        position.x = random(width);
        position.y = random(height);
        particles[i] = new Particle(position.x,position.y);
    
      }     
    }
       void draw() {
     background(255);
     for(int j = 0; j < particles.length; j++) {
    
     particles[j].show();
      } 
    }
      class Particle {
      float x;
      float y;
    
      Particle(float x_,float y_) {
    
        x = x_;
        y = y_;
      }
    
      void show() {
    
        fill(0);
        strokeWeight(.1);
        rect(x,y,3,3);
    
      }
    }
    
  • edited September 2016

    Great! You just saved me from having to write 40 lines of particle system code so I can even START helping you. Let's run it.

    ...

    Okay, so you have particles. They don't do much, do they? Anyway, let's just simplify that code a bit first, seeing as there's no need to pass a position if it's going to be random anyway...

    Particle[] particles = new Particle[50];
    
    void setup() {
      size(600, 600);
      for (int i = 0; i < particles.length; i++) {
        particles[i] = new Particle();
      }
    }
    
    void draw() {
      background(255);
      for (int j = 0; j < particles.length; j++) {
        particles[j].draw();
      }
    }
    
    class Particle {
      float x, y; 
      Particle() {
        x = random(width);
        y = random(height);
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        // Maybe do something here.
      }
      void render() {
        fill(0);
        strokeWeight(.1);
        rect(x, y, 3, 3);
      }
    }
    
  • edited September 2016

    Now since we need a black and white image, let's get that sorted out. And black particles are hard to see, so let's turn them red. And static ones are boring. Let's make them move a bit.

    Particle[] particles = new Particle[50];
    
    String http = "http://";
    PImage img = loadImage(http + "i.imgur.com/XVcWLG8.png");
    
    void setup() {
      size(600, 600);
      for (int i = 0; i < particles.length; i++) {
        particles[i] = new Particle();
      }
    }
    
    void draw() {
      background(img);
      for (int j = 0; j < particles.length; j++) {
        particles[j].draw();
      }
    }
    
    class Particle {
      float px, py, vx, vy;
      Particle() {
        px = random(width);
        py = random(height);
        vx = random(-2,2);
        vy = random(-2,2);
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        px+=vx;
        py+=vy;
      }
      void render() {
        fill(255,0,0);
        strokeWeight(.1);
        rect(px, py, 3, 3);
      }
    }
    
  • Now you said something about a generation? That's an okay approach, I guess. I'd much rather have my pixels be fit, get healthy, and reproduce lots on black areas and die quick, suffer, and be like they were in lava on white areas. But that means that each particle will need some sort of health thing going on. Add hit points!

    Particle[] particles = new Particle[50];
    
    String http = "http://";
    PImage img = loadImage(http + "i.imgur.com/XVcWLG8.png");
    
    
    void setup() {
      size(600, 600);
      for (int i = 0; i < particles.length; i++) {
        particles[i] = new Particle();
      }
    }
    
    void draw() {
      background(img);
      for (int j = 0; j < particles.length; j++) {
        particles[j].draw();
      }
    }
    
    class Particle {
      float px, py, vx, vy;
      int hp;
      Particle() {
        px = random(width);
        py = random(height);
        vx = random(-2,2);
        vy = random(-2,2);
        hp = int(random(100));
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        px+=vx;
        py+=vy;
      }
      void render() {
        fill(0,0,255);
        strokeWeight(.1);
        rect(px, py, 3, 3);
        fill(255,0,0);
        rect(px-24,py-6, 50, 4);
        fill(0,255,0);
        rect(px-24,py-6, hp/2, 4);
      }
    }
    
  • This is very helpful, but do you know a way I could write a function that checks each pixel of the processing window to each pixel of the image and gives the number of matching pixels?

  • Answer ✓

    Just iterate over all the pixels in the image (you can either get() them one at a time and loop over x and y position, or you can loadPixels() and then use the pixels array directly (pixels[i] is the color of the i'th pixel)), and compare them to the pixel in the same position in your target image (again, either do img.get(x,y), or img.loadPixels(), then use img.pixels[i]). Then you're just comparing two colors. The best way to do that IMHO, is to take the red, green, and blue components of each color, and find the distance between them.

    Your fitness would then be the sum of all those distances.

  • Answer ✓

    Hrm. My particles aren't doing as well as I would hope...

    ArrayList<Particle> particles = new ArrayList();
    
    String http = "http://";
    PImage img = loadImage(http + "i.imgur.com/XVcWLG8.png");
    
    
    void setup() {
      size(600, 600);
      for (int i = 0; i < 50; i++) {
        particles.add( new Particle() );
      }
    }
    
    void draw() {
      background(img);
      for (int j = particles.size()-1; j >= 0; j--) {
        if (particles.get(j).draw()) {
          particles.remove(j);
        }
      }
    }
    
    class Particle {
      float px, py, vx, vy;
      int hp;
      Particle() {
        px = random(width);
        py = random(height);
        vx = random(-2, 2);
        vy = random(-2, 2);
        hp = int(random(100));
      }
      Particle(float ix, float iy) {
        px = ix;
        py = iy;
        vx = random(-0.1,0.1);
        vy = random(-0.1, 0.1);
        hp = 50;
      }
    
      boolean draw() {
        if ( hp <= 0 ) return true;
        simulate();
        render();
        return false;
      }
      void simulate() {
        px+=vx;
        py+=vy;
        px+=width;
        py+=height;
        px%=width;
        py%=height;
        if (img.get(int(px), int(py)) == color(0)) {
          hp+=1;
          if(hp>=100){
            hp = 50;
            particles.add( new Particle(px, py) );
          }
        } else {
          hp-=1;
        }
      }
      void render() {
        fill(0, 0, 255);
        strokeWeight(.1);
        rect(px-1, py-1, 3, 3);
    //    fill(255, 0, 0);
    //    rect(px-24, py-6, 50, 4);
    //    fill(0, 255, 0);
    //    rect(px-24, py-6, hp/2, 4);
      }
    }
    
  • Thanks a million for all this help!! :) What does "int hp" do?

Sign In or Register to comment.