javaprocessingmosaic

i am trying to mosaic effect on an image in processing but the image remains the same ?


I am very new to processing.

I am trying to create a program that applies mosaic effect on a normal image. What I am trying to achieve is for the image to create blocks of filter size (e.g. 30 pixels) and replace it with the average of the r,g,b, colors of that block

Here is what I have done so far :

class ME {

  PImage image;

  ME(String imagename) {
    this.image = loadImage(imagename);
  }


  void display(int length, int height ) {
    image.resize(length, height);
    image(this.image, 0, 0);
  }


  void effect(int filterationSize) {
  print("smth");
    image.loadPixels(); 
    float r, g, b;

    for (int v = 0; v < (width*height ); v += filterationSize*width) 
    {
      for (int h = 0; h < width; h+=filterationSize)
      {
        r = g = b = 0;

        for (int bH = 0; bH<filterationSize; bH++)
        {
           for (int bV = 0; bV<filterationSize; bV++)
        {

        int p = v+h+bH+bV*width;

        if ( p < width*width)
          {


            r += (red(this.image.pixels[p]) / (filterationSize*filterationSize));
            g += (green(this.image.pixels[p]) / (filterationSize*filterationSize));
            b += (blue(this.image.pixels[p]) / (filterationSize*filterationSize));
          }


        }


        }



         for (int blockH = 0; blockH<filterationSize; blockH++)
      {
        for (int blockV = 0; blockV<filterationSize; blockV++)
        {
          int p = v+h+blockH+blockV*width;

          if ( p < width*width)
          {

            this.image.pixels[p] = color(r, g, b);
          }
        }
      }
      }
    }

    this.image.updatePixels();

  }
}

And here is my main class :

ME img ;

void setup(){
  size(500 ,500);
  img = new ME("image.png");
  img.display(width , height);

}



void draw(){

   img.effect(30);

}

But in the end the image turns out to be the same image as the very beginning.


Solution

  • You missed to display the image after you have applied the effect to the image:

    void draw(){
        img.effect(30);
        img.display(width , height);
    }
    

    But probably you want to apply the effect once, after the image has been loaded:

        ME img;
    
    void setup(){
       size(500 ,500);
       img = new ME("image.png");
       img.display(width , height);
       img.effect(30);
    }
    
    void draw(){
        img.effect(30);
        img.display(width, height);
    }
    

    Further you may improve the effect algorithm.

    Calculate the number of tiles, but note that the last tile in a row or column may be clipped:

    int tiles_x = width / filterationSize;
    if ( width % filterationSize > 0 ) 
        tiles_x += 1;
    
    int tiles_y = height / filterationSize;
    if ( height % filterationSize > 0 ) 
        tiles_y += 1;
    

    Calculate the start end coordinates and the "size" of a tile inside the loop:

    int start_x = tile_x*filterationSize;
    int start_y = tile_y*filterationSize;
    int end_x   = min(start_x+filterationSize, width); 
    int end_y   = min(start_y+filterationSize, height);
    int size    = (end_x-start_x) * (end_y-start_y); 
    

    Now it is easy to calculate the average of the pixels of one tile. The full algorithm may look like this:

    void effect(int filterationSize) {
        image.loadPixels(); 
    
        int tiles_x = width / filterationSize;
        if ( width % filterationSize > 0 ) 
            tiles_x += 1;
        int tiles_y = height / filterationSize;
        if ( height % filterationSize > 0 ) 
            tiles_y += 1;
    
        print( tiles_x, tiles_y );
        for ( int tile_y = 0; tile_y < tiles_x; tile_y ++ ) {
            for ( int tile_x = 0; tile_x < tiles_y; tile_x ++ ) {
    
                int start_x = tile_x*filterationSize;
                int start_y = tile_y*filterationSize;
                int end_x   = min(start_x+filterationSize, width); 
                int end_y   = min(start_y+filterationSize, height);
                int size    = (end_x-start_x) * (end_y-start_y);
    
                float r = 0, g = 0, b = 0;
                for (int by = start_y; by < end_y; by++ ) {
                    for (int bx = start_x; bx < end_x; bx++ ) {
                        int p = by * width + bx;
                        r += red(this.image.pixels[p])   / size;
                        g += green(this.image.pixels[p]) / size;
                        b += blue(this.image.pixels[p])  / size;
                    }
                }
    
                for (int by = start_y; by < end_y; by++ ) {
                    for (int bx = start_x; bx < end_x; bx++ ) {
                        int p = by * width + bx;
                        this.image.pixels[p] = color(r, g, b);
                    }
                }
            }
        }
        this.image.updatePixels();
    }
    

    See the effect applied on a 256*256 image and a tile length of 32: