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

assume the image as following top left, rectangular with 4 columns and 5 rows

how do i iterate within for loop for yellow rectangular (1,2,5,6,9,10,13,14) to fetch rgb values if my array is 1D (bellow rectangular) with following code

  for(int i = 0; i < posBuffer.pixels.length; i++){
if(blue(posBuffer.pixels[i]) > 0){
  count++;
 avg.add(red(posBuffer.pixels[i]) / 255.0, green(posBuffer.pixels[i]) / 255.0);
}

thank you

The length of a pixel array is width times height (width*height). If you want to select out a certain subset of the pixels then the only way that I know of is to reconvert it to a two dimensional array with two ‘for’ loops: one loop for the width and one loop for the height. You appear to be trying to make a two dimensional array fit into a one dimensional array that you have found somewhere.

pixelArray.length = width*height and you need to take it back to the two dimensional array that it was to start with, then you will be able to select a subset of pixels from the rows and columns:

final int rows = 5;
final int cols = 4;

int left;
int top;
int id = 1;

void rectGrid(int l, int t, int w, int h, int vg, int hg) {
  for (int k = 0; k < rows; k++) {
    for (int j = 0; j < cols; j++) {
      left = l + j*(w+vg);
      top = t + k*(h+hg);
      stroke(0);
      strokeWeight(2);
      if (j < 2 && k < 4) {
        fill(color(240, 240, 40));
      } else {
        fill(255);
      }
      rect( left, top, w, h);
      fill(0);
      textSize(20);
      textAlign(CENTER, CENTER);
      text(str(id), left, top, w, h);
      id++;
    }
  }
}

void setup() {
  size(720, 600);
  background(255);
  rectGrid(0, 0, width/cols, height/rows, 0, 0);
}

void draw() {
}

1 Like

following image is the 1D array data i want iterate, i want to iterate 2 index and skip 2 index and repeat continuously until the end of data

Hi again @doni,

This is linked to your previous post:

You should use a nested for loop and compute the 1D index with the x + y * width formula.

But it seems that you don’t want to use a nested for loop to iterate over the pixels… (I find it more simple and clear :wink: )

You can do that with a single while loop (maybe not the best solution thought):

int i = 0;
int iterations = 0;

while (i < 14) {
  iterations++;
  
  println(i + 1);
  
  if (iterations % 2 == 0) {
    i += 3;
  } else {
    i += 1;
  }
}

// -> 1 2 5 6 9 10 13 14

Or shorter:

while (i < 14) {
  iterations++;
  println(i + 1);
  i += ((iterations % 2) == 0) ? 3 : 1;
}
2 Likes

would you like to help me implemented it on this following code

for(int i = 0; i < posBuffer.pixels.length; i++){
if(blue(posBuffer.pixels[i]) > 0){
  count++;
 avg.add(red(posBuffer.pixels[i]) / 255.0, green(posBuffer.pixels[i]) / 255.0);
}

You should be able to do it yourself, this is not complicated :wink:

Ultimately what do you want to do? We gave you two solutions: either use a nested for loop (with x and y) or a “complicated” while loop.

Up to you to implement it.

2 Likes

where 3 come from in this code

i += 3;

where 1 come from as following

i += 1;

when i try this its error ArrayIndexOutOfBoundsException: 480, but webcam is turn on but some how its stuck some where

int [][] PosBuffer = new int [posBuffer.height [posBuffer.width];

  for (int x = 0; x < posBuffer.width ; x++ ) {
      for (int y = 0; y < posBuffer.height; y++ ) { 
     
        if(blue(PosBuffer[x][y]) > 0){
    count++;
     avg.add(red(PosBuffer[x][y]) / 255.0, green(PosBuffer[x][y]) / 255.0);
}
  }
  }

when i try this its error ArrayIndexOutOfBoundsException: 1, but webcam is turn on but some how its stuck some where

int [][] PosBuffer = {{posBuffer.width},{posBuffer.height}};

  for (int x = 0; x < posBuffer.width ; x++ ) {
      for (int y = 0; y < posBuffer.height; y++ ) { 
     
        if(blue(PosBuffer[x][y]) > 0){
    count++;
     avg.add(red(PosBuffer[x][y]) / 255.0, green(PosBuffer[x][y]) / 255.0);
}
  }
  }

when i try this its error ArrayIndexOutOfBoundsException: -2147450880 , but webcam is turn on but some how its stuck some where

for(int i = 0; i < posBuffer.pixels.length ; i+=640){
    for(int j = i; j < i + 100; j++)   
     i = i + j;
   if(blue(posBuffer.pixels[i]) > 0){
  count++;
  avg.add(red(posBuffer.pixels[i]) / 255.0, green(posBuffer.pixels[i]) / 255.0);
   }
}

when i try this its error ArrayIndexOutOfBoundsException: 307200, but webcam is turn on but some how its stuck some where

int i = 0;
int iteration = 0;
while (i < posBuffer.pixels.length){
  iteration++;
  if(iteration % 100 == 0){
    i += 75;
    if(blue(posBuffer.pixels[i]) > 0){
  count++;
  avg.add(red(posBuffer.pixels[i]) / 255.0, green(posBuffer.pixels[i]) / 255.0);   
  }else
  {
      i += 50;
    }
}
}

The following demo will color a subset range of a webcam image. Note that it uses x + y*width to get the pixel id:

import processing.video.*;

Capture cam;

void setup() {
  size(640, 480);
  String[] cameras = Capture.list();
  if (cameras == null) {
    println("Failed to retrieve the list of available cameras, will try the default...");
    cam = new Capture(this, 640, 480);
  } else if (cameras.length == 0) {
    println("There are no cameras available for capture.");
    exit();
  } else {
    println("Available cameras:");
    printArray(cameras);
    cam = new Capture(this, cameras[0]);
  }
  cam.start();
}

void draw() {
  if (cam.available() == true) {
    cam.read();
  }
  image(cam, 0, 0, width, height);
  loadPixels();
  color pink = color(255, 102, 204);
  for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
      int id = x + y * width;
      if (x < 100 && y > 240) {
        pixels[id] = pink;
      }
    }
  }
  updatePixels();
}
1 Like

actually i succeed to have full control on limitation of x and y data in for loop when using this 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];
    }

but fail with this code

import processing.video.*;
PShader colorFinder, colorPosShader;
PGraphics overlay, posBuffer;
// Variable for capture device
Capture video;

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

void setup() {
  //size(320, 240);
  size(640, 480, P2D);
  overlay = createGraphics(width, height, P2D);
  posBuffer = createGraphics(width, height, P2D);
  colorFinder = loadShader("colorDetect.glsl");
  colorPosShader = loadShader("colorPos.glsl");
  printArray(Capture.list());
  video = new Capture(this, width, height);
  video.start();
  video.loadPixels();
  // Start off tracking for red
  trackColor = color(255, 0, 0);
}

void captureEvent(Capture video) {
  // Read image from the camera
  video.read();
}

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 i = 0; i < posBuffer.pixels.length; i++){
    // encoded so blue is > 0 if a pixel is within threshold
    if(blue(posBuffer.pixels[i]) > 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[i]) / 255.0, green(posBuffer.pixels[i]) / 255.0);
    }
  }
  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(0);
  circle(avg.x, avg.y, 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
  video.loadPixels();
  int loc = mouseX + mouseY*video.width;
  trackColor = video.pixels[loc];
}

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

this is the link

all “ArrayIndexOutOfBoundsException: n” errors come from this line

if(blue(PosBuffer[x][y]) > 0)

The pixels are changing rapidly in realtime video. Using x + y*width to get pixel id inside of nested for loops seems to work without array overruns.

if you don mind try the second code combined with glsl which is GPU pararel processing, i faced difficulties when tried to do limitation over pixels.length within second code for loop

The following runs without crashing on my system:

 for (int y = 0; y < posBuffer.height; y++) {
    for (int x = 0; x < posBuffer.width; 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);
      }
    }
1 Like
 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);
      }
    }

when i limit iteration in x axis the sampled pixel and circle still drawn even in area over 100 of x axis. its different with first code it could limit the circle movement and drawn sampled color according to limitation value stated in iteration

for (int x = 0; x < video.width && x < 100; x ++ ) {
    for (int y = 240; y < video.height; y ++ )

if i move the yellow paper beyond limit value stated in iteration the white and the circle wont be drawn

Is this what you are trying to do?

  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);
      }
      }
    }
  }

1 Like

wow nearly! the circle jailed in this value if (x < 100 && y > 240) but the sampled color still drawn beyond that x and y value

the sampled color still drawn beyond that x and y value

If you don’t want to sample beyond x < 100 and y > 240 then you’ve got to limit where the mouse traps clicks. I’ve shown you this code previously. The last post of this thread:https://discourse.processing.org/t/how-to-iterate-over-2d-region-with-1d-pixels-array/39336/23

One change would be to not use the counter but use the most recent code that was posted above; ie, use id = x + y*width.

i am so sorry not noticed it. OK i should check ti

still the same brother, why i insist my self to use code with glsl is because its faster than the first code.