How to limit iteration range of one dimensional array

first i am sorry actually this is processing code were it will send coordinate to arduino system, i just decided to ask in this forum since i already wondering in processing forum and stack overflow forum and not found the answer. following is the first code (two dimensional array in for loop) which doing color tracking on left side ( from 0-100 of x axis ) and and bottom part ( 240 - 480 of y axis) of the image .

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

following code is the same function to track a color but with one dimensional array in the for loop

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

int the second code how to limit the range tracking area ( the x axis and the y axis) in one dimensional array. thank you

Usually such image arrays are organized pixel line by pixel line, so you have all pixels of y=0, then all pixels of y=1 and so on.

The limitation is already in the code, it stops iterating at posBuffer.pixels.length because that counts the number of entries in the array. Maybe I misunderstood your question, in that case you have to provide more details.

for(int i = 0; i < posBuffer.pixels.length; i++)

it iterate from 0 - 640 of x axis and from 0 - 480 of y axis

following does limitation to nearly a half of the screen size so the tracking happen on top part of the screen

for(int i = 0; i < posBuffer.pixels.length && i < 150000; i++)

what i want i could limit the x axis from 0 - 100 and for y axis from 240 to end of the height of the screen which is 480 as following

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

Then do that:

int i = y * video.width + x;

This gives you the index in the one-dimensional array (probably, if my above assumptions were right).

1 Like

to make it clear i how to do following part

with following for loop

I'm sure @pylon had the right idea but just to try to try to clarify the problem

posBuffer is a single dimension array representing an entire 640 x 480 screen.
You want to scan an arbitrary rectangular part of that screen. So that rectangle has dimensions x1 by y1 and an origin of x0, y0.

Is that it ?

It appears you you are thinking in terms of a single loop through the entire array where you determine from the index variable 'i' the coordinates (x,y) of the current position to see whether or not it is within the rectangle. This would appear to be the wrong approach. Instead, it looks like you should generate the index variable (into posBuffer) according to the size and position of that rectangular (sub) portion of screen.

However, if absolutely necessary, you could do it something like this outline:

bool isInRectangle( index) {
       // test if index is within rectangle x,y,origin (to be written) 
       // . . .
 }

for (int i = 0; i < 640 * 480 ; i++) {  // scan entire screen uint32_t 
       if ( isInRectangle( i ) ) { 
          // process point
          // . . .
       }
      // . . .
}

EDIT
Attempt to clear apparent ambiguity for the OP

yes correct

is rectangle you mean is the rectangle to be scanned or the rectangle represent my whole screen (640 x 480)

I've reworded it. I hope it is clearer.

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

actually this done 50% of my destination since above snippet limit the movement of the average circle on x axis but kept drawn the tracked color although the tracked color goes beyond 100 of x axis

as following

var i come from

int i = y * video.width + x;

how to apply following x and y

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

into this

posBuffer.pixels[i]

or some thing like this so it could receive x and y value

if(blue(posBuffer.pixels[x][y]) > 0)

thank you

hi brother what the index refer to

bool isInRectangle( index) {
       // test if index is within rectangle x,y,origin (to be written) 
       // . . .
 }

The position in the single dimensioned array posBuffer.pixels[]

Let's start again because it is not clear what your problem is.
You have given two code samples in the OP, both of which contain a draw() method.
You have mentioned a two dimensional array but there isn't one. In both cases, there appears to be a single dimensional array representing the entire screen. However, these are scanned differently.

The first code sample scans the single dimension array:

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];   // single dimension array indexed by loc
    // . . .
    // . . .
  }
}

The second code sample scans the single dimension array:

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) { // single dimension array indexed by i
    // . . .
  }
}

If you are simply attempting to mainly use the code in the second code sample, but with the scanning strategy from the first code sample, you could do something like this:

  for (int x = 0; x < video.width && x < 100; x ++ ) {
    for (int y = 240; y < video.height; y ++ ) {
      int i = x + y * video.width;  // now i
      // encoded so blue is > 0 if a pixel is within threshold
      if (blue(posBuffer.pixels[i]) > 0) { // single dimension array indexed by i
        // . . .
      }
    }
  }

which is similar to post #4

You can't do this, that is treating a single dimensioned array as if it is two dimensional:

i am so sorry. i am a begginer for sure and now i agree that

 video.width 
video.height

is single dimension array .

OK. in the simple question how do i to achieve this part

if(blue(posBuffer.pixels[x][y]) > 0)

since i need x n y value which iterated from for loop where the limitation for tracking arbitrary area occurred

coloPos.txt (1.3 KB)
colorDetect.txt (1.3 KB)
just put those two file in one folder of second code example and change their extension from .txt to .glsl

you see the white overlay?, if i move the yellow paper out of range written in for loop

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

the circle and the white overlay will be disappeared gradually by the time the yellow paper leaves the tracking target area. that i wan to achieve with the second sample code

These are the dimensions of a matrix (your screen). However, that matrix is represented later by a single dimensioned array.

You (a) can't address / re-structure a single dimensioned array like that and (b) don't need to (at least as far as I can see).

I'm trying to understand what your basic understanding problem is without going into your application in any depth (because I don't know this graphics library). I think the core maybe the representation of something which is essentially a 2 dimensional real object ( a screen in this case) as a single dimensioned array in C++ and how to scan it (iterate over it) . Maybe this helps visualise it.

The first part is the screen. The second part is its representation as a single dimensioned array. The part(s) you are interested in are yellow and your problem is to find a way of just picking out the yellow parts from the single dimensioned array.
I hope this helps.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.