slicing Image to Array

Hi, I have 2 questions regarding how to slice images, and randomly move the tiles around on a grid. I've looked at some posts, which helped me (notably ), and looking at 2 dimensional arrays, but I'm stuck and need help.

  1. is there an easier (less code than below) way to directly slice an image to an array (using a for-loop perhaps) in void setup() ?
  2. when I'm moving the images around the grid, they never overlap or leave blanks, but I want to achieve this. How?

Thank you kindly for your help!!

PImage img;

PImage[] pieces = new PImage[16];

void setup() {

  size(800, 800);

  img = loadImage("http://3.bp.blogspot.com/-fGkhXK9efpM/TmaRMG2mQpI/AAAAAAAAB5w/zEjlbty8zGM/s1600/searichter.jpg");

  pieces[0] = img.get(0, 0, img.width/4, img.height/4);  
  pieces[1] = img.get(img.width/4, 0, img.width/4, img.height/4);
  pieces[2] = img.get(img.width/4*2, 0, img.width/4, img.height/4);
  pieces[3] = img.get(img.width/4*3, 0, img.width/4, img.height/4);
  pieces[4] = img.get(0, img.height/4, img.width/4, img.height/4);
  pieces[5] = img.get(img.width/4, img.height/4, img.width/4, img.height/4);
  pieces[6] = img.get(img.width/4*2, img.height/4, img.width/4, img.height/4);
  pieces[7] = img.get(img.width/4*3, img.height/4, img.width/4, img.height/4);
  pieces[8] = img.get(0, img.height/4*2, img.width/4, img.height/4);
  pieces[9] = img.get(img.width/4, img.height/4*2, img.width/4, img.height/4);
  pieces[10] = img.get(img.width/4*2, img.height/4*2, img.width/4, img.height/4);
  pieces[11] = img.get(img.width/4*3, img.height/4*2, img.width/4, img.height/4);
  pieces[12] = img.get(0, img.height/4*3, img.width/4, img.height/4);
  pieces[13] = img.get(img.width/4, img.height/4*3, img.width/4, img.height/4);
  pieces[14] = img.get(img.width/4*2, img.height/4*3, img.width/4, img.height/4);
  pieces[15] = img.get(img.width/4*3, img.height/4*3, img.width/4, img.height/4);

  frameRate(0.5);
}


void draw() {

  for (int i=0; i < pieces.length; i++) { 
    image(pieces[i], (round(random(0, 3))*img.width/4), (round(random(0, 3))*img.height/4));
  }
}

Answers

  • edited May 2016

    Simplified the code a little. Gonna try a loop for the slicing creation next time! =:)

        /* @pjs pauseOnBlur="true"; preload="/static/uploaded_resources/p.6273/searichter.jpg"; */
        
        /** 
         * Sliced Image (v2.3)
         * by  MatzeWagner (2013/Oct)
         * mod GoToLoop
         * 
         * forum.processing.org/two/discussion/586/slicing-image-to-array
         * studio.processingtogether.com/sp/pad/export/ro.9$MTikWt80-9w/latest
         */
        
        final static int GRID = 4, NUM = GRID*GRID;
        final PImage[] pieces = new PImage[NUM];
        PImage img;
        
        int halfX, halfY, quadX, quadY, thrdX, thrdY;
        boolean isShuffling = true;
        
        final static String HOST = "http:/" + "/3.bp.blogspot.com";
        
        final static String PATH = "/-fGkhXK9efpM/TmaRMG2mQpI/AAAAAAAAB5w/zEjlbty8zGM/s1600/";
        //final static String PATH = "/static/uploaded_resources/p.6273/";
        
        final static String NAME = "searichter.jpg";
        
        void setup() {
          size(806, 809);
          frameRate(.5);
        
          img = loadImage(HOST + PATH + NAME);
          //img = loadImage(PATH + NAME);
          //img = loadImage(NAME);
        
          halfX = img.width  >> 1;
          halfY = img.height >> 1;
          quadX = halfX >> 1;
          quadY = halfY >> 1;
          thrdX = quadX * 3;
          thrdY = quadY * 3;
        
          pieces[0]  = img.get(0, 0, quadX, quadY);  
          pieces[1]  = img.get(0, quadX, quadX, quadY);
          pieces[2]  = img.get(0, halfX, quadX, quadY);
          pieces[3]  = img.get(0, thrdX, quadX, quadY);
        
          pieces[4]  = img.get(quadX, 0, quadX, quadY);
          pieces[5]  = img.get(quadX, quadY, quadX, quadY);
          pieces[6]  = img.get(quadX, halfY, quadX, quadY);
          pieces[7]  = img.get(quadX, thrdY, quadX, quadY);
        
          pieces[8]  = img.get(halfX, 0, quadX, quadY);
          pieces[9]  = img.get(halfX, quadY, quadX, quadY);
          pieces[10] = img.get(halfX, halfY, quadX, quadY);
          pieces[11] = img.get(halfX, thrdY, quadX, quadY);
        
          pieces[12] = img.get(thrdX, 0, quadX, quadY);
          pieces[13] = img.get(thrdX, quadY, quadX, quadY);
          pieces[14] = img.get(thrdX, halfY, quadX, quadY);
          pieces[15] = img.get(thrdX, thrdY, quadX, quadY);
        }
        
        void draw() {
          //background(img);
        
          if (isShuffling) for ( int i = 0; i != NUM;
            image(pieces[i++], (int) random(GRID)*quadX, (int) random(GRID)*quadY) );
        
          else for ( int i = 0; i != NUM; image(pieces[i], i/GRID * quadX, i++ % GRID * quadY) ); // Java
          //else for ( int i = 0; i != NUM; image(pieces[i], (i>>2) * quadX, i++ % GRID * quadY) ); // JS
        }
        
        void mousePressed() {
          isShuffling = !isShuffling;
        }
        
        void keyPressed() {
          mousePressed();
        }
    
  • edited May 2016 Answer ✓

    Finally I was able to make a loop to slice the image! \m/
    Also correcting division for JS Mode and code accepts any GRID value for jig-saw slicing now! =D>

    BtW, check it online at the link below:
    studio.processingtogether.com/sp/pad/export/ro.9$MTikWt80-9w/latest

        /* @pjs pauseOnBlur = "true"; 
         preload = "/static/uploaded_resources/p.6273/searichter.jpg"; */
        
        /** 
         * Sliced Image (v2.62)
         * by  MatzeWagner (2013/Oct)
         * mod GoToLoop
         * 
         * forum.processing.org/two/discussion/586/slicing-image-to-array
         * studio.processingtogether.com/sp/pad/export/ro.9$MTikWt80-9w/latest
         */
        
        final static int GRID = 10, NUM = GRID*GRID;
        final PImage[] pieces = new PImage[NUM];
        PImage img;
        
        int jigX, jigY;
        boolean isShuffling = true;
        
        final static String HOST = "http:/" + "/3.bp.blogspot.com";
        
        final static String PATH = "/-fGkhXK9efpM/TmaRMG2mQpI/AAAAAAAAB5w/zEjlbty8zGM/s1600/";
        //final static String PATH = "/static/uploaded_resources/p.6273/";
        
        final static String NAME = "searichter.jpg";
        
        void setup() {
          size(806, 809);
          frameRate(.5);
        
          img = loadImage(HOST + PATH + NAME);
          //img = loadImage(PATH + NAME);
          //img = loadImage(NAME);
        
          jigX = (int) (img.width/GRID);  // (int) is to force integer division for JS!
          jigY = (int) (img.height/GRID);
        
          final int diff = img.height - (jigY>>2);
          int i = 0, jx = 0, jy = 0;
        
          while (i != NUM) {
            pieces[i++] = img.get(jx, jy, jigX, jigY);
        
            if ((jy += jigY) > diff) {
              jx += jigX;
              jy = 0;
            }
          }
        }
        
        void draw() {
          //background(img);
        
          if (isShuffling) for ( int i = 0; i != NUM;
            image(pieces[i++], (int) random(GRID)*jigX, (int) random(GRID)*jigY) );
        
          else for ( int i = 0; i != NUM; 
            image(pieces[i], (int) (i/GRID) * jigX, i++ % GRID * jigY) );
        }
        
        void mousePressed() {
          isShuffling = !isShuffling;
        }
        
        void keyPressed() {
          mousePressed();
        }
    
  • edited October 2013

    GoToLoop, thank you so much for your help! It works like a charm, and I'm learning quite a bit from your code, which is indeed much more flexible than my first attempt. Just for clarification, am I understanding this correctly:

             while (i != NUM) {      // as long as i is unequal NUM
                pieces[i++] = img.get(jx, jy, jigX, jigY); 
    // keep extracting sections from image 
    
           if ((jy += jigY) >= img.height - DIFF) { 
    // if jy+jigY is > than (height minus cell size)  
                  jx += jigX;     // jump to the next column 
                  jy = 0;           // the top of next column that is 
                }
              }
    

    Also, why do you use ' += ' instead of just ' + ' in the above section? Lastly, and this should really be my last question, is there a way to slow the shuffling down without affecting the global frameRate() ? Thanks a million!!!!

  • edited October 2013

    lastly, why do you use ' += ' instead of just ' + ' in the above section?

    B/c it's shorter than jy = jy + jigY! :-j
    http://processing.org/reference/addassign.html

    // if jy+jigY is > than (height minus cell size)

    Pay attention that it's -> jy += jigY! It means jy points to the next row below after it!

    Constant DIFF isn't a cell/piece size. It's a poor correction for the integer division between img.width & GRID! :(
    You see, with jigX = img.width/GRID, jixX*GRID isn't exactly img.width! It's <= img.width!!! @-)
    That it so b/c the fraction part is discarded in the division part! And your source image is very irregular -> 806x809!

    jx += jigX; // jump to the next column
    jy = 0; // the top of next column that is

    jy = 0 means back to the top row. And jx += jigXmeans it's now at next column.
    jy += jigY after GRID times should be near or equal to img.height!
    So it's reached the bottom. and needs to get back to top row!!! :D

    Version 2.5 is following the same order established at version 2.3:
    Top to bottom row, and then next column! Look at there to figure out the pattern better! ;-)

    P.S.: Version 2.6 -> To be more flexible w/ any GRID & img.height, variable diff is derived from jigY now: *-:)
    final int diff = img.height - (jigY>>2);
    if ((jy += jigY) > diff) {

  • Thanks again for being patient and thorough GoToLoop, that does indeed make sense. :-B

  • edited May 2016

    Taking a closer look at the code agin, I've come to realize that this display portion: :D

    else for ( int i = 0; i != NUM; 
      image(pieces[i], (int) (i/GRID) * jigX, i++ % GRID * jigY) );
    

    could be adapted to replace this whole complicated slicing creation portion: X_X

    final int diff = img.height - (jigY>>2);
    int i = 0, jx = 0, jy = 0;
    
    while (i != NUM) {
      pieces[i++] = img.get(jx, jy, jigX, jigY);
    
      if ((jy += jigY) > diff) {
        jx += jigX;
        jy = 0;
      }
    }
    

    So here's new simplified v2.70: ^:)^

        /* @pjs pauseOnBlur = "true"; 
         preload = "/static/uploaded_resources/p.6273/searichter.jpg"; */
        
        /** 
         * Sliced Image (v2.71)
         * by  MatzeWagner (2013/Oct)
         * mod GoToLoop
         * 
         * forum.processing.org/two/discussion/586/slicing-image-to-array
         * studio.processingtogether.com/sp/pad/export/ro.9$MTikWt80-9w/latest
         */
        
        final static int GRID = 10, NUM = GRID*GRID;
        final PImage[] pieces = new PImage[NUM];
        
        int jigX, jigY;
        boolean isShuffling = true;
        
        final static String HOST = "http:/" + "/3.bp.blogspot.com";
        
        final static String PATH = "/-fGkhXK9efpM/TmaRMG2mQpI/AAAAAAAAB5w/zEjlbty8zGM/s1600/";
        //final static String PATH = "/static/uploaded_resources/p.6273/";
        
        final static String NAME = "searichter.jpg";
        
        void setup() {
          size(806, 809);
          frameRate(.5);
        
          final PImage img = loadImage(HOST + PATH + NAME);
          //final PImage img = loadImage(PATH + NAME);
          //final PImage img = loadImage(NAME);
        
          jigX = (int) (img.width/GRID);  // (int) is to force integer division for JS!
          jigY = (int) (img.height/GRID);
        
          for ( int i = 0; i != NUM; 
            pieces[i] = img.get((int) (i/GRID) * jigX, i++ % GRID * jigY, jigX, jigY) );
        }
        
        void draw() {
          if (isShuffling) for ( int i = 0; i != NUM; 
            image(pieces[i++], (int) random(GRID)*jigX, (int) random(GRID)*jigY) );
        
          else for ( int i = 0; i != NUM; 
            image(pieces[i], (int) (i/GRID) * jigX, i++ % GRID * jigY) );
        }
        
        void mousePressed() {
          isShuffling = !isShuffling;
        }
        
        void keyPressed() {
          mousePressed();
        }
    
  • slick! Any thoughts on slowing down the shuffling speed (i.e. about once every 2 seconds), without affecting frameRate() ? =D>

  • edited May 2016

    How about this -> if (frameCount % FREQ != 0) return; :bz
    Just adjust FREQ in relation to FPS. The greater FREQ compared to FPS, the slowest shuffle gets! :D
    So for example,FREQ = 4*FPS gets ya 1 shuffle each 4 seconds:

        /* @pjs pauseOnBlur = "true"; 
         preload = "/static/uploaded_resources/p.6273/searichter.jpg"; */
        
        /** 
         * Sliced Image (v2.91)
         * by  MatzeWagner (2013/Oct)
         * mod GoToLoop
         * 
         * forum.processing.org/two/discussion/586/slicing-image-to-array
         * studio.processingtogether.com/sp/pad/export/ro.9$MTikWt80-9w/latest
         */
        
        final static int FPS  = 30, FREQ = 2*FPS;
        final static int GRID = 10, NUM  = GRID*GRID;
        final PImage[] pieces = new PImage[NUM];
        
        int jigX, jigY;
        boolean isShuffling = true;
        
        final static String HOST = "http:/" + "/3.bp.blogspot.com";
        
        final static String PATH = "/-fGkhXK9efpM/TmaRMG2mQpI/AAAAAAAAB5w/zEjlbty8zGM/s1600/";
        //final static String PATH = "/static/uploaded_resources/p.6273/";
        
        final static String NAME = "searichter.jpg";
        
        void setup() {
          size(806, 809);
          frameRate(FPS);
        
          final PImage img = loadImage(HOST + PATH + NAME);
          //final PImage img = loadImage(PATH + NAME);
          //final PImage img = loadImage(NAME);
        
          jigX = img.width/GRID >> 0;  // >> 0 forces integer division for JS!
          jigY = img.height/GRID | 0;  // |  0 forces integer division for JS!
        
          // 
  • Almost there... First, thanks again (big time), and that makes sense. I probably should have been a little clearer in regards to shuffling speed. I achieved the same thing with a counter, whereas your solution is much more elegant. But, lastly, I plan on having the grid move in space, for which I would need to put background() inside void draw(). In the current situation, the grid flashes up for one frame every few seconds. What is the best approach for displaying the tiles constantly, but only changing their position every few seconds. Again, thank you already for the obvious time and effort you put into this!!! I shall be eternally grateful ^:)^

  • edited May 2016

    You gotta take a snapshot of current canvas every time you change the tiles.
    Then store it in a PImage variable, and use that as background()! :-\"

        /* @pjs pauseOnBlur = "true"; 
         preload = "/static/uploaded_resources/p.6273/searichter.jpg"; */
        
        /** 
         * Sliced Image (v3.03)
         * by  MatzeWagner (2013/Oct)
         * mod GoToLoop
         * 
         * forum.processing.org/two/discussion/586/slicing-image-to-array
         * studio.processingtogether.com/sp/pad/export/ro.9$MTikWt80-9w/latest
         */
        
        final static int FPS  = 30, FREQ = 2*FPS;
        final static int GRID = 10, NUM  = GRID*GRID;
        final PImage[] pieces = new PImage[NUM];
        
        PImage bg;
        
        int jigX, jigY;
        boolean isShuffling = true;
        
        final static String HOST = "http:/" + "/3.bp.blogspot.com";
        
        final static String PATH = "/-fGkhXK9efpM/TmaRMG2mQpI/AAAAAAAAB5w/zEjlbty8zGM/s1600/";
        //final static String PATH = "/static/uploaded_resources/p.6273/";
        
        final static String NAME = "searichter.jpg";
        
        void setup() {
          size(806, 809);
          frameRate(FPS);
        
          final PImage img = loadImage(HOST + PATH + NAME);
          //final PImage img = loadImage(PATH + NAME);
          //final PImage img = loadImage(NAME);
        
          jigX = img.width/GRID >> 0;  // >> 0 forces integer division for JS!
          jigY = img.height/GRID | 0;  // |  0 forces integer division for JS!
        
          // 
  • edited October 2013

    Cool, sorry to keep bugging, but the problem is partially existent in the following way. Let's say I have a global variable r , which I decrease to move the entire grid by translate( 0, 0, r); Now it only updates that screen along with the grid according to FREQ. void draw() {

              translate(0, 0, r); 
    
              if (frameCount % FREQ == 0) { // either recreate tiles each FREQ frames.
                if (isShuffling) for ( int i = 0; i != NUM; 
                image(pieces[i++], (int) random(GRID)*jigX, (int) random(GRID)*jigY) );
    
                else for ( int i = 0; i != NUM; 
                image(pieces[i], (i/GRID << 0) * jigX, i++ % GRID * jigY) );
    
                bg = get(); // gets a hard-copy of current canvas!
              }
              else background(bg); // or clear canvas using previous bg snapshot.
              //else image(bg, 0, 0); // JS patched version!
              // Put the rest of drawings below:
    
              r--;
            }
    

    Is there a way to move/transform the whole thing (which now works beautifully, btw) independently of FREQ ? Or am I missing something?

  • Maybe this is getting a little complex, but what if I created a class for each tile, have it move (rather than shuffle) around the grid in certain time increments and load each instance with a different tile from pieces[i] ?

Sign In or Register to comment.