# How to Iterate over 2D region with 1D pixels array

the snippet code below is doing color tracking and get the average position and draw circle on it, the screen size (640, 480). how to do iteration in one dimensional array in for loop within part of the screen, for example i want to do tracking/iteration from 0 to 100 of x axis and from 0 to 100 of y axis. thank you

``````PGraphics  posBuffer;

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);
}
}
``````
1 Like

Hi @doni,

Interesting question!

You should change the title to: â€śIterate over 2D region with 1D pixels arrayâ€ť

The Processing tutorial on images has the solution to your issue:

In the above example, because the colors are set randomly, we didnâ€™t have to worry about where the pixels are onscreen as we access them, since we are simply setting all the pixels with no regard to their relative location. However, in many image processing applications, the XY location of the pixels themselves is crucial information. A simple example of this might be, set every even column of pixels to white and every odd to black. How could you do this with a one dimensional pixel array? How do you know what column or row any given pixel is in?

In programming with pixels, we need to be able to think of every pixel as living in a two dimensional world, but continue to access the data in one (since that is how it is made available to us). We can do this via the following formula:

1. Assume a window or image with a given WIDTH and HEIGHT.
2. We then know the pixel array has a total number of elements equaling WIDTH * HEIGHT.
3. For any given X, Y point in the window, the location in our 1 dimensional pixel array is: LOCATION = X + Y*WIDTH

And this sketch is an example on how to get a 1D index out of 2D coordinates:

1 Like

the doc is to long to read but ill try. thank you

I quoted the specific part of the documentation
And look at the second link which is a real world code example.

I have made this kind of â€śutilitieâ€ť once:

``````
void setup() {
size(400, 400);
smooth();
}

void draw() {

PVector p = toBiDimensional(toUniDimensional(mouseX, mouseY, 400), 400);
ellipse(p.x, p.y, 4, 4);

pixels[toUniDimensional(mouseX, mouseY, 400)] = color(255, 0, 255);
updatePixels();

println(mouseX+ "  " + mouseY);
println(toUniDimensional(mouseX, mouseY, 400));
println(p);
}

PVector toBiDimensional(int index, int wid)
{
return new PVector(index%wid, int(index/wid));
}

int toUniDimensional(int x, int y, int wid)
{
return y*wid+x;
}

``````
2 Likes

i could limit iteration as following

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

}
}
``````

but how to do that with this for loop

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

If you want to check the first 100 pixels of both the width and height, why not just check the first 10,000 (which is 100x100)?

if i do as following

it will track from index 0 to index 10000. the area from 0 to 10000 will be top part of the image/ screen.

but if i do as following

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

i could do tracking in left side part and bottom part of the image/ screen so exclude tracking from 101 to width (640) which is right part of the image/ screen and 0 to 239 of y axis of the image/screen which is top part of the screen and this is i am looking for

i could do tracking in left side part and bottom part of the image/ screen so exclude tracking from 101 to width (640) which is right part of the image/ screen and 0 to 239 of y axis of the image/screen which is top part of the screen and this is i am looking for

Are these different areas? You asked for the first 100x100 in the original post.

i am sorry. but i mentioned " for example". ok lets say my area tracking will be 0 to 100 of x axis and 0 to 100 of y axis, how to do that in 1D array? or should i convert 1D array to 2d array first

I donâ€™t understand your interest in converting an image or a graphic to a one dimensional array. By definition 640x480 is a two dimensional array. The pixels in that image or graphic are arranged in rows and columns, ie two dimensions. An image of 640x480 has 307,200 pixels. Once we know what segment of that you want to study we should be able to offset into that grid to get the pixels that you want. I assume (which is dangerous) that the pixels are put in by row as opposed to being put in by columns. If that is true and we know the id number for each pixel you should be able to select a range of pixels to manipulate.

``````import processing.video.*;
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);
printArray(Capture.list());
video = new Capture(this, width, height);
video.start();
// Start off tracking for red
trackColor = color(255, 0, 0);
}

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

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("targetColor", red(trackColor) / 255.0, green(trackColor) / 255.0, blue(trackColor) / 255.0, 1.0);
overlay.beginDraw();
overlay.image(video, 0, 0);
overlay.endDraw();
posBuffer.beginDraw();
posBuffer.image(video, 0, 0);
posBuffer.endDraw();
//compute average position by looking at pixels from position buffer
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
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 whole picture of the code

I was unable to run the demo that you posted due to a null pointer exception:

In lieu of working on your project I propose that we work on a simpler demo using any .jpg image that you might have on your system and then running the following code:

``````int counter = 0;

void setup() {
size(400, 400);
image(img, 0, 0, 400, 400);
color pink = color(255, 102, 204);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (x > 100 && y > 240) {
pixels[counter] = pink;
}
counter++;
}
}
updatePixels();
}

void draw() {
}
``````

The only thing required is to place your image into the sketch folder so that Processing can find it. What you should see is that any pixel with an x-coordinate > 100 and a y-coordinate > 240 is painted pink. On my system this corresponds to the lower right corner of the image. Please see if you get the same thing and let me know if this is similar to what you want to do.

1 Like

if you donâ€™t mind following is my first code that i am trying to adapt to 1D array

``````    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
}

void draw() {
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];
}
``````

The second code posted runs ok and after hooking up my web camera shows my image sitting in front of the computer. When the mouse is clicked the pixel color under the cursor is used to fill a small circle in the lower left hand corner of the screen. How does that relate to the question that you asked? What are you hoping to achieve that this code doesnâ€™t already do? You keep talking about a one dimensional array and I fail to see the connection.

achive by this snippet

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

and that is i want to with following code

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

i think is needed to change this

``````posBuffer.pixels.length
``````

or this

``````posBuffer.pixels
``````

to become 2D array something like this

``````CopyposBuffer[x][y]
``````

so the 2D array could receive x ,y limited value which iterate in for loop

Try something like this:

``````  for (int x = 0; x < video.width && x < 100; x ++ ) {
for (int y = 240; y < video.height; y ++ ) {
int loc = x + y*video.width;
if(blue(video.pixels[loc]) > 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(video.pixels[loc]) / 255.0, green(video.pixels[loc]) / 255.0);
}
}
}
``````

I canâ€™t run it because my system doesnâ€™t know what avg.add(); is.

When run with this line REMmed out, the circle is now at the top of the screen. Is that what you want to change?

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

the circle movement is already limited by the x , y value in the iteration but the color tracked is still drawn over x ,y value

Whatâ€™s the problem now? I didnâ€™t understand your last comment.

If you want the circle to be directly over the pixel sampled then do something like this:

``````  float locX = 0;
float locY = 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;
locX = mouseX;
locY = mouseY;
if (blue(video.pixels[loc]) > 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(video.pixels[loc]) / 255.0, green(video.pixels[loc]) / 255.0);
}
}
}

...

ellipse(locX, locY, 20, 20);
``````