using PGraphics

edited April 10 in Library Questions

Hi there, I have problems with my code. what I want to do is tracking color pixel. I want to capture an image with the only traced color(without background video). so I used PGraphics, but It is so slow that the program can't track color well. I think using PGraphics makes the program slow. is there any advice to make tracking faster?

Here is my code.

import processing.video.*;

Capture video;

color trackColor= color(145,43,54);
float threshold = 25;
PGraphics topLayer;


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

void setup() {
  frameRate(60);
  size(640, 360);
  String[] cameras = Capture.list();
  printArray(cameras);
  video = new Capture(this, cameras[3]);
  video.start();
  trackColor = color(145,43,54);
  topLayer = createGraphics(width, height, g.getClass().getName());
}

void captureEvent(Capture video) {
  video.read();
}

void draw() {

  video.loadPixels();
  image(video, 0, 0);

  //threshold = map(mouseX, 0, width, 0, 100);
  threshold = 50;

  int avgX = 0;
  int avgY = 0;
  float worldRecord = 0;

  // Begin loop to walk through every pixel
  for (int x = 0; x < video.width; x++ ) {
    for (int y = 0; y < video.height; y++ ) {
      int loc = x + y * video.width;
      // What is current color
      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) {
        worldRecord = d;
        avgX = x;
        avgY = y;
    }
  }
 }
   topLayer.beginDraw();
  topLayer.stroke(trackColor);
  if (worldRecord < threshold*threshold) {
    topLayer.fill(trackColor);
    topLayer.strokeWeight(1);
    topLayer.point(avgX, avgY); ////////////////////////////////////////
  }
  topLayer.endDraw();
    image(topLayer, 0, 0);
}

Answers

  • Answer ✓

    You can define r2,g2,b2 as global variables and only set/update their values if trackColor changes.

    Threshold could be changed to thresholdSquare:

    final float THRESHOLD = 50;
    float thresholdSquare=THRESHOLD*THRESHOLD;
    

    Then instead of threshold*threshold use this new field.

    Check the Processing reference for bit shifting as a faster way to extract the RGB colors. For instance: float r1=(currentColor>>16)&&0xff;

    To check for code performance, add this to your code in draw():

    if(frameCount%60==0) println("Current rate: "+frameRate());

    This will provide you an idea of how fast a sketch is running. What values do you get.

    Lastly, you code is only updating one pixel. To be precised, it is updating the last pixel found that was below the current threshold. Reading your post, how this code track the color? What do you intend to do?

    Kf

  • edited April 13

    Thanks for your kind reply and also sorry for my poor explanation. what I want to do is making the program like this first code. But I want to change points(x,y) into PGraphics so that I can save only points without background. The problem is that when I change some codes with PGraphics, points have traces.. not like the first code.
    The last code is what I made. is there any advice to make it without any traces?

        import processing.video.*;
    
        Capture video;
    
        color trackColor; 
        float threshold = 25;
    
        void setup() {
          size(640, 360);
          String[] cameras = Capture.list();
          printArray(cameras);
          video = new Capture(this, cameras[3]);
          video.start();
          trackColor = color(255, 0, 0);
        }
    
        void captureEvent(Capture video) {
          video.read();
        }
    
        void draw() {
          video.loadPixels();
          image(video, 0, 0);
    
          //threshold = map(mouseX, 0, width, 0, 100);
          threshold = 80;
    
          float avgX = 0;
          float avgY = 0;
    
          int count = 0;
    
          // Begin loop to walk through every pixel
          for (int x = 0; x < video.width; x++ ) {
            for (int y = 0; y < video.height; y++ ) {
              int loc = x + y * video.width;
              // What is current color
              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) {
                stroke(255);
                strokeWeight(1);
                point(x, y);
                avgX += x;
                avgY += y;
                count++;
              }
            }
          }
    
          // We only consider the color found if its color distance is less than 10. 
          // This threshold of 10 is arbitrary and you can adjust this number depending on how accurate you require the tracking to be.
          if (count > 0) { 
            avgX = avgX / count;
            avgY = avgY / count;
            // Draw a circle at the tracked pixel
            fill(255);
            strokeWeight(4.0);
            stroke(0);
            ellipse(avgX, avgY, 24, 24);
          }
        }
    
        float distSq(float x1, float y1, float z1, float x2, float y2, float z2) {
          float d = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) +(z2-z1)*(z2-z1);
          return d;
        }
    
        void mousePressed() {
          // Save color where the mouse is clicked in trackColor variable
          int loc = mouseX + mouseY*video.width;
          trackColor = video.pixels[loc];
        }
    
    
    
    ////////////////////////////////////////////////////////////////////////////////
    
    
    
          for (int x = 0; x < video.width; x++ ) {
            for (int y = 0; y < video.height; y++ ) {
    
              int loc = x + y * video.width;
              // What is current color
              color currentColor = video.pixels[loc];
              float r1 = (currentColor>>16)&0xFF;
              float g1 = (currentColor>>7) & 0xFF ;
              float b1 = (currentColor) & 0xFF;
              r2 = (trackColor>>16)&0xFF;
              g2 = (trackColor>>7) & 0xFF;
              b2 = (trackColor) & 0xFF;
              //
              float d = distSq(r1, g1, b1, r2, g2, b2); 
    
              if (d < thresholdSquare) {
                //worldRecord = d;
                topLayer.beginDraw();
                topLayer.stroke(trackColor);
                topLayer.point(x, y,1,1);        
             ////////////////////////////////////////
                topLayer.endDraw();
                image(topLayer, 0, 0);
        }
      }
     } 
    
  • Answer ✓

    Traces in the second code above? Maybe what you want to do is to clear the PGraphics before you draw the points:

    topLayer.beginDraw();
    topLayer.background(0);
    for (int x = 0; x < video.width; x++ ) {
           for (int y = 0; y < video.height; y++ ) {
               (...)
           }
    }
    topLayer.endDraw();
    

    Kf

  • One follow-up bit of advice: If you need better performance it is possible that what you actually might want here is to use the OpenCV or BoofCV libraries for Processing -- these might have more robust / quicker implementations of the tracking you are trying to do.

Sign In or Register to comment.