Joint Color Tracker

A cluster of circle that are attracted to an on-screen color, in this case, red (calibration to color via my lipstick because it was the easiest thing to smear on my face contrast to my green-ish surroundings). The idea was to track acceleration and drag in the elbow joint’s extension.

If a color is left on screen for enough time to feel nature, the circles cluster around the color. If the color then moves the circles follow, sensitive to physical properties (friction, bounds of the screen, acceleration of the motion). I used this to abstractly track the movement of my elbow, concept diagram below.

import processing.video.*;

Mover[] movers = new Mover[100];
Attractor a;
Capture cam;
color trackColor;

void setup() {
  size(600, 400);
  smooth();
  for (int i = 0; i < movers.length; i++) {
    movers[i] = new Mover(random(0.1, 2), random(width), random(height));
  }
  a = new Attractor();
  String[] cameras = Capture.list();
  for (int i = 0; i < cameras.length; i++) {
  }
  cam = new Capture(this,cameras[0]);
  cam.start();
  trackColor = color(90,25,40);
}

void draw() {
  background(255,0);
  a.display();
  for (int i = 0; i < movers.length; i++) {
    PVector force = a.attract(movers[i]);
    movers[i].applyForce(force);
    movers[i].boundaries();
    movers[i].update();
    movers[i].display();
  }
}

class Attractor {
  float mass;
  float G;
  PVector location;

  Attractor() {
    location = new PVector(width/2,height/2);
    mass = 20;
    G = 2;
  }

  PVector attract(Mover m) {
    PVector force = PVector.sub(location,m.location);
    float d = force.mag();
    d = constrain(d,5.0,25.0);
    force.normalize();
    float strength = (G * mass * m.mass) / (d * d);
    force.mult(strength);
    return force;
  }

  void display() {
  if (cam.available() == true) {
    cam.read();
  }
  cam.loadPixels();
  image(cam,0,0);
  float worldRecord = 500;
  int closestX = 0;
  int closestY = 0;
  for (int x = 0; x < cam.width; x ++ ) {
    for (int y = 0; y < cam.height; y ++ ) {
      int loc = x + y*cam.width;
      color currentColor = cam.pixels[loc];
      float r1 = red(currentColor);
      float g1 = green(currentColor);
      float b1 = blue(currentColor);
      float r2 = red(trackColor);
      float g2 = green(trackColor);
      float b2 = blue(trackColor);
      float d = dist(r1,g1,b1,r2,g2,b2);
      if (d < worldRecord) {
        worldRecord = d;
        closestX = x;
        closestY = y;
      }
    }
  }
  if (worldRecord < 50) {
    fill(90,25,40,0);
    strokeWeight(4.0);
    stroke(0);
    ellipse(closestX,closestY,mass*2,mass*2);
  }
  }

}

class Mover {

  PVector location;
  PVector velocity;
  PVector acceleration;
  float mass;

  Mover(float m, float x, float y) {
    mass = m;
    location = new PVector(random(width), random(height));
    velocity = new PVector(1.5, 0);
    acceleration = new PVector(0, 0);
  }

  void applyForce(PVector force) {
    PVector f = PVector.div(force, mass);
    acceleration.add(f);
  }

  void update() {
    velocity.add(acceleration);
    location.add(velocity);
    acceleration.mult(0);
  }

  void display() {
    stroke(255);
    strokeWeight(0);
    fill(255,50);
    ellipse(location.x, location.y, mass*10, mass*10);
  }

    void boundaries() {
    float d = 50;
    PVector force = new PVector(0, 0);
    if (location.x < d) {
      force.x = 1;
    }
    else if (location.x > width -d) {
      force.x = -1;
    }
    if (location.y < d) {
      force.y = 1;
    }
    else if (location.y > height-d) {
      force.y = -1;
    }
    force.normalize();
    force.mult(0.1);
    applyForce(force);
  }
}

http://itp.nyu.edu/~mc4562/noc/colourfollow/VideoAttractor.pde

Leave a Reply

Your email address will not be published. Required fields are marked *