How to draw with color tracking?

edited January 2018 in Library Questions

Hello,

I watched a lot of Daniel Shiffman tutorials and wanted to write a piece of code that draws out the path in which a certain color moves across the screen in my video. Lets say if my video were a skateboard, and I did a trick with color wheels on, I'd like to have the program draw the movement by following the colored wheels throughout it's movement.

What I have so far:

// Most of this code I learned how to write thanks to Daniel Shiffman

import processing.video.*;

Movie video;

color trackColor; 
float threshold = 20;
float distThreshold = 75;

ArrayList<Blob> blobs = new ArrayList<Blob>();

void setup() {
  size(1080, 720);
  video = new Movie(this, "sk8.mov");
  video.loop();
  trackColor = color(206, 74, 129);
}

void movieEvent(Movie video) {
  video.read();
}

void keyPressed() {
  if (key == 'a') {
    distThreshold++;
  } else if (key == 'z') {
    distThreshold--;
  }
  println(distThreshold);
}

void draw() {
  video.loadPixels();
  image(video, 0, 0);

  blobs.clear();

  threshold = 62;

  for (int x = 0; x < video.width; x++ ) {
    for (int y = 0; y < video.height; y++ ) {
      int loc = x + y * video.width;
      color currentColor = video.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 = distSq(r1, g1, b1, r2, g2, b2); 

      if (d < threshold*threshold) {

        boolean found = false;
        for (Blob b : blobs) {
          if (b.isNear(x, y)) {
            b.add(x, y);
            found = true;
            break;
          }
        }

        if (!found) {
          Blob b = new Blob(x, y);
          blobs.add(b);
        }
      }
    }
  }

  for (Blob b : blobs) {
    if (b.size() > 500) {
      b.show();
    }
  }
}


float distSq(float x1, float y1, float x2, float y2) {
  float d = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
  return d;
}

void mousePressed() {
  // Save color where the mouse is clicked in trackColor variable
  int loc = mouseX + mouseY*video.width;
  trackColor = video.pixels[loc];
}
class Blob {
  float minx;
  float miny;
  float maxx;
  float maxy;

  Blob(float x, float y) {
    minx = x;
    miny = y;
    maxx = x;
    maxy = y;
  }

  void show() {
    stroke(0);
    fill(255);
    strokeWeight(2);
    rectMode(CORNERS);
    rect(minx, miny, maxx, maxy);
  }

  void add(float x, float y) {
    minx = min(minx, x);
    miny = min(miny, y);
    maxx = max(maxx, x);
    maxy = max(maxy, y);
  }

  float size() {
    return (maxx-minx)*(maxy-miny); 
  }

  boolean isNear(float x, float y) {
    float cx = (minx + maxx) / 2;
    float cy = (miny + maxy) / 2;

    float d = distSq(cx, cy, x, y);
    if (d < distThreshold*distThreshold) {
      return true;
    } else {
      return false;
    }
  }
}

What this code successfully does is track the color of the wheels on my skateboard, and follows the wheels throughout the clip. However, I am trying to figure out how to make it not just follow the wheels, but draw a line in the path where the wheels were before.

Any help would be greatly appreciated.

Thank you

Answers

  • Each time you detect where the wheels are, you can add that point to an ArrayList. Then you just need to draw a line between all the points in an ArrayList.

    ArrayList<PVector> points = new ArrayList();
    
    void setup(){
      size(400,400);
      stroke(255);
    }
    
    void draw(){
      background(0);
      // Use the positon of the mouse (if the mouse is clicked) to spoof a detected point.
      if( mousePressed ){
        points.add(new PVector(mouseX, mouseY));
      }
      // Limit it to the last 100 points.
      while( points.size() > 100 ){
        points.remove(0);
      }
      // Draw a line between all the points.
      for(int i = 0; i < points.size()-1; i++){
        line(points.get(i).x,points.get(i).y,points.get(i+1).x,points.get(i+1).y);
      }
    }
    
  • Please don't post duplicates

  • One warning about this approach -- it can be very limited. In many real world lighting conditions red wheels on a skateboard do not stay the same color under natural light -- on certain frames they are in shadow and dark brown or black, at other moments a glare may make them very light pink or white. Our eyes/brains are so good at knowing they are red wheels that we aren't aware the RGB values are constantly changing until we have the computer check for red and it doesn't work very well.

    If you have the equivalent of a colored ball on a stick under fixed studio lighting conditions, this approach can work well. Otherwise you may soon find yourself upgrading to OpenCV / BoofCV.

Sign In or Register to comment.