Particles on webcam pixels (and phone cam)

Hi there. Based on the frame differencing Processing example, how can I include particle systems to represent the pixels on the webcam? I mean, how can I represent the webcam’s movement through particles?

Here’s an example: https://www.youtube.com/watch?v=YxFcLAWFwcM&fbclid=IwAR25DN_FfdtITW7Gj-YnmA5Di9JVX-mUmtqk3SAvdDagbfLZsaKg_NtFHUQ

Thanks.

1 Like

Hi. Nice video. I’m going to work on this also.
Here is the code.
http://www.dayofthenewdan.com/ParticleVideo.zip

1 Like

Hello. Thanks for sharing! I would also appreciate your help :slight_smile:

@joana
Since I do not have a PC, I adapted the code to be able to work with the android Ketai library. I still not have the quality of the original video. In the video below I am waving a golden brush in front of my phone camara, but it is barely noticeable. I will tweak a bit to see what happens. Please post your result also.

/**
ParticleVideo by Dan Bridges 2011
Check out Daniel Shiffman's tutorials on
particle systems here: 
http://www.shiffman.net/teaching/nature/particles/
As you can see some of this code is built upon
those tutorials.
*/

import ketai.camera.*;
KetaiCamera cam;

PImage prevFrame;
float threshold = 50;
int videoWidth;
int videoHeight;
int reduction;
ParticleSystem system;

void setup() {
  size(320, 240);
  system = new ParticleSystem(30000);
  frameRate(30);
  reduction = 1;
  videoWidth = width/reduction;
  videoHeight = height/reduction;
  cam = new KetaiCamera(this, 320, 240, 20);
  cam.start();
  prevFrame = createImage(cam.width, cam.height, RGB);
}


void onCameraPreviewEvent() {
  prevFrame.copy(cam, 0, 0, cam.width, cam.height, 0, 0, cam.width, cam.height);
  prevFrame.updatePixels();
  cam.read();
}


void draw() {
  // image(cam, 0, 0);
  background(255,200);
  cam.loadPixels();
  prevFrame.loadPixels();
  for (int x=0; x< videoWidth; x+=3) {
    for (int y = 0; y < videoHeight; y+=4) {
      if (abs((cam.pixels[y* videoWidth +x] >> 16 & 0xFF)-(prevFrame.pixels[y* videoWidth +x] >> 16 & 0xFF)) < 75
        && abs((cam.pixels[y* videoWidth +x] >> 8 & 0xFF)-(prevFrame.pixels[y* videoWidth +x] >> 8 & 0xFF)) < 75
        && abs((cam.pixels[y* videoWidth +x] & 0xFF)-(prevFrame.pixels[y* videoWidth +x] & 0xFF)) < 75) {
      } else {
        for (int i=0; i<2; i++) {
          system.addParticle(( videoWidth - x - 1)*reduction, y*reduction, random(-100, 100), random(-320, 0), 1);
        }
      }
    }
  }      
  system.update(1/frameRate, cam);
  fill(0);
}


public class ParticleSystem {
    private ArrayList <Particle> particles;
    private int iterations;
    private int maxSize;

    ParticleSystem(int maxSize) {
        this.particles = new ArrayList<Particle>(maxSize);
        this.iterations = 1;
        this.maxSize = maxSize;
    }
    
    void update(float dt, KetaiCamera cam ) {
        for (int j = particles.size()-1; j >= 0; j--) {
            Particle particle = particles.get(j);
            particle.update(dt);
            if (particle.position.x > 0 && particle.position.x < width &&
                particle.position.y > 0 && particle.position.y < height) {
                particle.render(cam.pixels[floor(particle.position.y/reduction)*videoWidth+(videoWidth-floor(particle.position.x/reduction)-1)]);
            }
            if (particle.shouldDestroy()) {
                particles.remove(j);
            }
        }
    }
    
    void addParticle(float x, float y, float mass) {
        this.addParticle(x, y, 0, 0, mass);
    }
    
    void addParticle(float x, float y, float dx, float dy, float mass) {
        if (size() < maxSize) {
            particles.add(new Particle(x, y, dx, dy, mass));
        }        
    }
    
    int size() {
       return particles.size();
    } 
}



public class Particle {
    private PVector position;
    private PVector velocity;
    private PVector force;
    private float mass;
    private boolean fixed;
    private float diameter;
    private float time;
    private float maxTime;

    Particle(float x, float y, float mass) {
        this(x, y, 0.0, 0.0, mass);
    }
    
    Particle(float x, float y, float dx, float dy, float mass) {
        this.position = new PVector(x, y);
        this.velocity = new PVector(dx, dy);
        this.force = new PVector(0, 0);
        this.mass = mass;
        this.fixed = false;
        this.diameter = random(1, 10);
        this.time = 0;
        this.maxTime = random(3, 7);
    }
    
    void update(float dt) {
        time += dt;
        if (!fixed){
            //Gravity
            force.add(0.0, 200*mass, 0);
            //force.div(mass); take this out for simplicity, don't need it for free fall
            velocity.add(PVector.mult(force, dt));
            position.add(PVector.mult(velocity, dt));
        }
        //Zero forces
        force.mult(0);
    }
    
    void render(color c) {
        int transparency = floor((time/maxTime)*255);
        ellipseMode(CENTER);
        fill(blendColor(c, color(255, 255, 255, transparency), BLEND));
        noStroke();
        ellipse(position.x, position.y, diameter, diameter);
    }
    
    boolean shouldDestroy() {
        //destroy if off screen
        if (position.x > width || 
        position.x < 0 ||
        position.y > height) {
            return true;
        }
        
        //destroy if time is up
        if (time > maxTime) {
            return true;
        }
        
        return false;
    }
}
1 Like