Downscaling an image to an array

currently stuck with this problem, and its probably easy however m brain cant figure it out.


PImage img;
ArrayList<Float> array = new ArrayList<Float>();
int cols = 202;
int rows = 200;
int res,ry;
void setup(){
  size(600,600);
  img = loadImage("sil.jpg");
  res = img.width/cols;
  ry = img.height/rows;
  
  for(int i=0;i<cols;i++){
        for(int j=0;j<rows;j++){
          int p = int(i*res + j*ry * img.width);
          if(p<img.pixels.length){
            float r = red(img.pixels[p]);
            float g = green(img.pixels[p]);
            float bb = blue(img.pixels[p]);
            float br = brightness(img.pixels[p]);
            float h = (red(img.pixels[p]) + green(img.pixels[p]) + blue(img.pixels[p]) + brightness(img.pixels[p]))/4;
            //h = ;
            //if(r>h)h = r;
            //if(g>h)h = g;
            //if(bb>h)h = bb;
            //if(br>h)h = br;
            //h = map(blue(img.pixels[p]),0,ma,0,100);
            //array[p] = h;
            array.add(h);
    }}}
};

void draw(){
  background(0);
  for(int i=0;i<cols;i++){
    for(int j=0;j<rows;j++){
      int p = i+ j*cols;
      noStroke();
      fill(array.get(p));
      rect(j*res,i*res,res,res);
      //rect(i,j,1,1);
    }
  }
};

the image extraction works fine providing that both cols and rows are equal but causes issues otherwise. What am I doing worng?

Hello @paulgoux,

This is as far as I got and had fun working through this.

I did not get to down scaling yet… just working through your code.

Code
PImage img;
ArrayList<Integer> array = new ArrayList<Integer>();
int x, y;

void setup()
  {
  size(500, 200);
  img = loadImage("test.png");
  background(255);
  
  for(int y=0; y<img.height; y++)
    {
    for(int x=0; x<img.width; x++)
      {
      int p = int(y*img.width + x);
      if(p<img.pixels.length)
        {
        int r = int(red(img.pixels[p]));
        int g = int(green(img.pixels[p]));
        int b = int(blue(img.pixels[p]));
        int h = (int(r*256*256 + 256*g + b) | 0xFF000000);
        array.add(h);
        //println(r, g, b, hex(array.get(p)));
        stroke(array.get(y*img.width + x));
        point(x, y);
        }
      }      
    }
  noLoop();
  }

void draw()
  {  
  for(int y=0; y<img.height; y++)
    {
    for(int x=0; x<img.width; x++)
      {
      int p = int(y*img.width + x);
      if(p<img.pixels.length)
        {
        //float r = red(img.pixels[p]);
        //float g = green(img.pixels[p]);
        //float b = blue(img.pixels[p]);
        //int h = (int(r*256*256 + 256*g + b) | 0xFF000000);
        //array.add(h);
        //println(r, g, b, hex(array.get(p)));
        stroke(array.get(y*img.width + x));
        point(x+250, y);
        }
      }      
    }
  }

The image I used:
test

:)

Hello @paulgoux,

I would consider storing your sampled pixel colors in a 2D array instead of an arraylist:

float[][] array = new float[cols][rows];

I find it easier to grasp in regards to what you want to do after.

I checked your code with the arraylist though and here are few comments:

  • you need to separate your x resolution and your y resolution since the numbers of rows and columns can be differents as well as the size of your image
  • when you compute your resolutions, don’t forget to convert you cols and rows variables to a float so you get the correct result (otherwise you get an int as a result)
  • The order in wich you store your colors is really important and you need to first start to loop for the columns then loop for the row to get the same logic as the pixel array
  • To get the index of your pixel, it is better to round both i * resX and j * resY so it gives you the index of the closest pixel. Otherwise, you are rounding the index directly and can have a pixel on the other side of the image.

That beeing said, this is the result code. I also reduced the size of the image by a factor of 2:

PImage img;
ArrayList<Float> array = new ArrayList<Float>();
int cols = 200;
int rows = 200;
float rx, ry;

void setup() {
  size(1600, 533);
  img = loadImage("test.jpg");
  rx = img.width / (float)cols;  // Parse the cols variable to a float to keep decimals for rx
  ry = img.height / (float)rows; // Parse the rows variable to a float to keep decimals for ry

  for (int j = 0; j < rows; j++) {    // Start looping through the rows
    for (int i = 0; i < cols; i++) {  // And then the columns to keep the same "pixel order" in your array
      int p = int(i * rx) + int(j * ry) * img.width;  //Get closest x AND closet y to get your index BUT DON'T get closest index directly => int(i * rx + j * ry * img.width)

      float h = (red(img.pixels[p]) + green(img.pixels[p]) + blue(img.pixels[p]) + brightness(img.pixels[p]))/4.0;
      array.add(h);
    }
  }
};

void draw() {
  background(0);
  
  // Resize picture by half
  rx /= 2.0;
  ry /= 2.0;

  // Display resized image
  for (int i = 0; i < cols; i++) {
    for (int j = 0; j < rows; j++) {
      noStroke();
      fill(array.get(i + j * cols));  // Get index with same method as you would use for the index of a pixel of an image
      rect(i * rx, j * ry, rx, ry);
    }
  }
  
  // Display original image
  image(img, 800, 0);

  noLoop();
};

Original image:

Half sized:
image

1 Like

See changes to your code in draw():

Code
PImage img;
ArrayList<Float> array = new ArrayList<Float>();
int cols = 30;
int rows = 50;
float res, ry;
void setup(){
  size(600,600);
  img = loadImage("test.png");
  res = img.width/cols;
  ry = img.height/rows;
  
  for(int i=0;i<cols;i++){
        for(int j=0;j<rows;j++){
          int p = int(i*res + j*ry * img.width);
          if(p<img.pixels.length){
            float r = red(img.pixels[p]);
            float g = green(img.pixels[p]);
            float bb = blue(img.pixels[p]);
            float br = brightness(img.pixels[p]);
            float h = (red(img.pixels[p]) + green(img.pixels[p]) + blue(img.pixels[p]) + brightness(img.pixels[p]))/4;
            //h = ;
            //if(r>h)h = r;
            //if(g>h)h = g;
            //if(bb>h)h = bb;
            //if(br>h)h = br;
            //h = map(blue(img.pixels[p]),0,ma,0,100);
            //array[p] = h;
            array.add(h);
    }}}
};

void draw(){
  background(0);
  for(int i=0;i<cols;i++){
    for(int j=0;j<rows;j++){
      int p = j + i*rows;
      //noStroke();
      //fill(array.get(p));
      //rect(j*res,i*res,res,res);
      //rect(i,j,1,1);
    stroke(array.get(p));
    point(i, j);
    }
  }
};

:)

200x200:
image

30x50:
image

1 Like

thanks a lot everyone!!

1 Like