How to iterate video.pixels.length for random area of image

still the same brother

What does that mean? Post the code that you tried.

i will post it tomorrow brother

Hello, not sure if Iā€™m realy getting what you want, but maybeā€¦

This sample code does 2 diff things:

  • draw a rect using nesteds for loops to access pixels[]
  • draw a rect using one for loop that traverse the whole pixels[] and change only what is needed.

I guess you are looking for the second. If you are going to traverse the whole pixels array you need to have a test to see if that particlar index of the array represents a pixel inside the wanted area.

Or you could adapt the other method pRect(), to return a collection with the indexes inside the area. then you could say (lets say it returned an array indxs[]).

// note not going trhough the whole pixels array
for(int i=0; i< indxs.length;i++){
  pixels[indxs[i]] = //blah;
}

But I think this makes not a lot of sense, anyway you would go trough 2 nesteds for loops (to buid indxs[]), so why not just do whatever you need to do at that time, so this seems useless, donā€™t nowā€¦ anyways itā€™s here to help the comprehension of whatā€™s involved.

here, have a look:

void setup() {
  size(400, 500);
}

void draw() {
  background(200);

  // draw a rect using pixels[] direct access
  // using a single for loop, the isIN() function gets:
  // index, xpos, ypos, rectWidt, rectHeight
  // returns if index represents a point inside rect area
  loadPixels();
  for (int i = 0; i < pixels.length; i++) {
    //define the rect here
    if (isIn(i, mouseX, mouseY, 300, 120))
      pixels[i] = color(220, 220, 0, 200);
  }
  updatePixels();


  //draw a rect using pixels[] direct access
  //with a nested for loop
  pRect(78, 94, 150, 84);
}


void pRect(int x, int y, int w, int h) {
  loadPixels();
  for (int i = x; i < w + x; i++) {
    for (int j = y; j < h + y; j++) {
      //you got address od each point inside the area
      int index = j*width+i;
      // limit to pixels inside screen
      if (index < pixels.length && i< width)
        pixels[index] = color(255, 0, 255);
    }
  }
  updatePixels();
}

boolean isIn(int ind, int x, int y, int w, int h) {
  int ix = ind%width;
  int iy = int(ind/width);
  return ix > x && ix < x+w && ix < width && iy > y && iy < y+h && iy < height;
}

This is the idea, you can easily adapt it for you r needs I thinkā€¦

1 Like

@ vkbr @ svan

i am sorry indeed, i found that for (int y = 0; y < posBuffer.height; y++) { for (int x = 0; x < posBuffer.width && x < 100; x++) { int id = x + y * width; // encoded so blue is > 0 if a pixel is within threshold if (blue(posBuffer.pixels[id]) > 0) { count++; // processing takes 0-1 (float) color values from shader to 0-255 (int) values for color // to decode, we need to divide the color by 255 to get the original value avg.add(red(posBuffer.pixels[id]) / 255.0, green(posBuffer.pixels[id]) / 255.0); } } responsible to control circle over the value and overlay is the one which drawn sampled color.
i try several code to modify overlay but not succeed

Itā€™s difficult to tell what the goals of this project really are. If the goal is to trap clicks only in one area of an image then the place to do that is in mousePressed(). It is not difficult to trap clicks in a specified area and ignore clicks outside of this area. The pixel under the mouse is identified by its coordinates and analyzed for r,g,b values (trackColor). The trackColor and mouse coordinates are subsequently stored in global variables. This data is used to draw a circle filled with the trackColor at the click location for visual feedback in addition to console ā€˜printlnā€™ verification. The source code for two demos follow; the first demo creates its own two toned image to demonstrate the concept (saved to sketch folder) and the second demo is for use on an image of your choice (copy/pasted to sketch folder) to validate the technique.

Concept demonstration

PImage img;
color trackColor;
int locX = -10; //offscreen initially
int locY = 260;

void createTwoToneImage() {
  img = createImage(640, 480, ARGB);
  loadPixels();
  for (int x = 0; x < width; x++) {
    for (int y = 0; y < height; y++) {
      int id = x + y * width;
      if (x < 100 && y > 240) {
        img.pixels[id] = color(240, 240, 40);// yellow
      } else {
        img.pixels[id] = color(0, 153, 204); // blue
      }
    }
  }
  updatePixels();
  img.save("twoTone.png");
}

void drawCircle() {
  stroke(0);
  strokeWeight(3);
  fill(trackColor);
  circle(locX, locY, 16);
}

void setup() {
  size(640, 480);
  surface.setTitle("Click in the yellow area");
  createTwoToneImage();
  img = loadImage("twoTone.png");
}

void draw() {
  image(img, 0, 0);
  drawCircle();
}

void mousePressed() {
  if (mouseX < 100 && mouseY > 240) {
    int loc = mouseX + mouseY*img.width;
    float r = red(img.pixels[loc]);
    float g = green(img.pixels[loc]);
    float b = blue(img.pixels[loc]);
    trackColor = color(r, g, b);
    println(r, g, b);
    locX = mouseX;
    locY = mouseY;
  }
}

For use on image to validate technique

PImage img;
color trackColor;
int locX = -10; //offscreen initially
int locY = 260;

void setup() {
  size(640, 480);
  img = loadImage("myImage.jpg");
}

void draw() {
  image(img, 0, 0);
  drawCircle();
}

void drawCircle() {
  stroke(0);
  strokeWeight(3);
  fill(trackColor);
  circle(locX, locY, 16);
}

void mousePressed() {
  if (mouseX < 100 && mouseY > 240) {
    int loc = mouseX + mouseY*img.width;
    float r = red(img.pixels[loc]);
    float g = green(img.pixels[loc]);
    float b = blue(img.pixels[loc]);
    trackColor = color(r, g, b);
    println(r, g, b);
    locX = mouseX;
    locY = mouseY;
  }
}

the goal is actually represent in this rewrite code

import processing.video.*;
    Capture video;
    
    float threshold = 210;
    color trackColor; 
    PVector target;
    
    void setup() {
     
    size(640, 480);
    video = new Capture(this, width, height);
    video.start();
     trackColor = color(160,0,0); // Start off tracking for red    
    }
    
    void captureEvent(Capture video) {
    // Read image from the camera
    video.read();
    }
    
    void draw() {
    loadPixels();
    video.loadPixels();
    image(video, 0, 0);
    float avgX = 0;
    float avgY = 0;
     int count = 0;
    
    for (int x = 0; x < video.width && x < 100; x ++ ) {
    for (int y = 240; 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);
    
    // Using euclidean distance to compare colors
    float d = distSq(r1, g1, b1, r2, g2, b2);
    if (d < threshold) {
    stroke(255);
    strokeWeight(1);
    point(x,y);
     
    avgX += x;
    avgY += y;
     count++;
    }
    }
    }
    if (count > 0) { 
    avgX = avgX / count;
    avgY = avgY / count;
    // Draw a circle at the tracked pixel
    fill(trackColor);
    strokeWeight(4.0);
    stroke(0);
    ellipse(avgX, avgY, 20, 20);
    text("brightnesslevel: " + trackColor, 20, 60);
    text("FPS: " + frameRate, 20, 80);
    }
    target = new PVector (avgX, avgY);
    }
    
    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];
    }

by clicking on any area of the screen the code get the rgb value and seeking all the pixel with the same rgb value at the same time get the coordinate and do averaging to it where circle got drawn and and also draw overlay over any pixel with the same rgb value, but since the code limit x y value within for loop iteration the circle and the overlay only drawn within those range that is the goal, but so difficult to do with the second code which combined with glsl code

1 Like

thanks all of you guys. i think i will leave it

Iā€™m unable to run your code due to video library.
I tried to make it a runnable one, video independent by using a random generated PGraphic.
Does this attempt makes sense?
I can now vizualize, i think, what you are doingā€¦
So does this code has the issue you have? If so, what is it again? :))

PGraphics video;

float threshold = 210;
color trackColor; 
PVector target;
// correctd as per next answer, Thanks @svan
void setup() {
  size(640, 480);
  video = createGraphics(width, height);
  trackColor = color(160, 0, 0); // Start off tracking for red    
  video.beginDraw();
  video.loadPixels();
  for (int i=0; i< video.pixels.length; i++) {
    video.pixels[i] = color(random(155), random(75), random(90));
  }
  video.updatePixels();
  video.endDraw();
}

void draw() {
  background(120);
  loadPixels();

  image(video, 0, 0);
  float avgX = 0;
  float avgY = 0;
  int count = 0;

  for (int x = 0; x < video.width && x < 100; x ++ ) {
    for (int y = 240; 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);

      // Using euclidean distance to compare colors
      float d = distSq(r1, g1, b1, r2, g2, b2);
      if (d < threshold) {
        stroke(255);
        strokeWeight(1);
        point(x, y);

        avgX += x;
        avgY += y;
        count++;
      }
    }
  }
  if (count > 0) { 
    avgX = avgX / count;
    avgY = avgY / count;
    // Draw a circle at the tracked pixel
    fill(trackColor);
    strokeWeight(4.0);
    stroke(0);
    ellipse(avgX, avgY, 20, 20);
    fill(255);
    text("brightnesslevel: " + trackColor, 20, 60);
    text("FPS: " + frameRate, 20, 80);
  }
  target = new PVector (avgX, avgY);
}

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() {
  video.beginDraw();
  video.loadPixels();
  for (int i=0; i< video.pixels.length; i++) {
    video.pixels[i] = color(random(155), random(75), random(90));
  }
  video.endDraw();
  video.updatePixels();
  // Save color where the mouse is clicked in trackColor variable
  int loc = mouseX + mouseY*video.width;
  trackColor = video.pixels[loc];
}

2 Likes

@vkbr I was unable to run the code that you posted using a PGraphic in lieu of a webcam image due to a null pointer exception. By adding video.beginDraw() and video.endDraw() it became runnable. Revised setup() follows:

void setup() {
  size(640, 480);
  video = createGraphics(width, height);
  trackColor = color(160, 0, 0); // Start off tracking for red    
  video.beginDraw();
  video.loadPixels();
  for (int i=0; i< video.pixels.length; i++) {
    video.pixels[i] = color(random(155), random(75), random(90));
  }
  video.updatePixels();
  video.endDraw();
}

It is an interesting model and may provide insight into what we are trying to achieve.

2 Likes

@vkbr The following demo from previous posts adds shaders but has been modified to use a PGraphic in lieu of a webcam image. In order to run this demo you will need the two shader files which are included below the demo. They will need to be added to the sketch folder. In order to bring the image into focus you may need to use the mouse wheel. You should see the image with various shades.

PShader colorFinder, colorPosShader;
PGraphics overlay, posBuffer;
PGraphics video;

// A variable for the color we are searching for.
color trackColor;
float threshold = 0.1;

int locX = 0;
int locY = 0;

void setup() {
  size(640, 480, P2D);
  overlay = createGraphics(width, height, P2D);
  posBuffer = createGraphics(width, height, P2D);
  colorFinder = loadShader("colorDetect.glsl");
  colorPosShader = loadShader("colorPos.glsl");
  // Start off tracking for red
  video = createGraphics(width, height);
  trackColor = color(255, 0, 0);
  video.beginDraw();
  video.loadPixels();
  for (int i=0; i< video.pixels.length; i++) {
    video.pixels[i] = color(random(155), random(75), random(90));
  }
  video.updatePixels();
  video.endDraw();
}

void draw() {
  colorFinder.set("threshold", threshold);
  colorFinder.set("targetColor", red(trackColor) / 255.0, green(trackColor) / 255.0, blue(trackColor) / 255.0, 1.0);
  colorPosShader.set("threshold", threshold);
  colorPosShader.set("targetColor", red(trackColor) / 255.0, green(trackColor) / 255.0, blue(trackColor) / 255.0, 1.0);
  overlay.beginDraw();
  overlay.shader(colorFinder);
  overlay.image(video, 0, 0);
  overlay.endDraw();
  posBuffer.beginDraw();
  posBuffer.shader(colorPosShader);
  posBuffer.image(video, 0, 0);
  posBuffer.endDraw();
  //compute average position by looking at pixels from position buffer
  posBuffer.loadPixels();
  PVector avg = new PVector(0, 0);
  int count = 0;
  for (int y = 0; y < posBuffer.height; y++) {
    for (int x = 0; x < posBuffer.width; x++) {
      int id = x + y * width;
      if (x < 100 && y > 240) {
      // encoded so blue is > 0 if a pixel is within threshold
      if (blue(posBuffer.pixels[id]) > 0) {
        count++;
        // processing takes 0-1 (float) color values from shader to 0-255 (int) values for color
        // to decode, we need to divide the color by 255 to get the original value
        avg.add(red(posBuffer.pixels[id]) / 255.0, green(posBuffer.pixels[id]) / 255.0);
        updatePixels();
      }
      }
    }
  }
  if (count > 0) {
    // we have the sum of positions, so divide by the number of additions
    avg.div((float) count);
    // convert 0-1 position to screen position
    avg.x *= width;
    avg.y *= height;
  } else {
    // appear offscreen
    avg = new PVector(-100, -100);
  }
  image(overlay, 0, 0);
  fill(trackColor);
  stroke(255);
  circle(locX, locY, 16);
  fill(0, 50);
  noStroke();
  rect(0, 0, 150, 30);
  fill(150);
  text("Framerate: " + frameRate, 0, 11);
  text("Threshold: " + threshold, 0, 22);
}

void mousePressed() {
  // Save color where the mouse is clicked in trackColor variable
  if (mouseX < 100 && mouseY > 240) {
    video.loadPixels();
    int loc = mouseX + mouseY*video.width;
    trackColor = video.pixels[loc];
    locX = mouseX;
    locY = mouseY;
  }
}

void mouseWheel(MouseEvent e) {
  threshold -= e.getCount() * 0.01;
  threshold = constrain(threshold, 0, 1);
}

file to be named: colorDetect.glsl

#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif

uniform sampler2D texture;

varying vec4 vertColor;
varying vec4 vertTexCoord;

uniform vec4 targetColor;
uniform float threshold; //between 0 and 1

void main() {
  vec4 texColor = texture2D(texture, vertTexCoord.st) * vertColor;
  vec3 a = texColor.xyz;
  vec3 b = targetColor.xyz;
  float dist = sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y) + (b.z - a.z) * (b.z - a.z));
  bool cond = dist < threshold * sqrt(3);
  // if color is within threshold, encode the pixel's position into red and green components
  // and use blue component as a marker that the pixel was in range
  // vertTexCoord is from 0 to 1, so after computing average, multiply by width and height to get screen position
  gl_FragColor = cond ? vec4(vertTexCoord.x, vertTexCoord.y, 1, 1) : vec4(0, 0, 0, 1);
}

file to be named: colorPos.glsl

#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif

uniform sampler2D texture;

varying vec4 vertColor;
varying vec4 vertTexCoord;

uniform vec4 targetColor;
uniform float threshold; //between 0 and 1

void main() {
  vec4 texColor = texture2D(texture, vertTexCoord.st) * vertColor;
  vec3 a = texColor.xyz;
  vec3 b = targetColor.xyz;
  float dist = sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y) + (b.z - a.z) * (b.z - a.z));
  bool cond = dist < threshold * sqrt(3);
  // if color is within threshold, encode the pixel's position into red and green components
  // and use blue component as a marker that the pixel was in range
  // vertTexCoord is from 0 to 1, so after computing average, multiply by width and height to get screen position
  gl_FragColor = cond ? vec4(vertTexCoord.x, vertTexCoord.y, 1, 1) : vec4(0, 0, 0, 1);
}

2 Likes

thanks Iā€™ll try later. :wink:

Also I pasted your correction to my code in my previous post/ :slight_smile:

thanks for that also. wierd enough I got not errors with my wrong codeā€¦

For sure posBuffeer is variable for circle, and the overlay is variable for draw any pixel with same rgb value with first clikced pixels. I hope my post not distrub your time