Search code examples
carraysmultidimensional-arraychunks

C - How to copy [600][400] array into [4][4] array, then randomize element positions?


I'm trying to make a function that shuffles an image as shown below: shuffle

Its argument takes three 600x400 RGB arrays to create the pixel colors. I have been trying to brainstorm this for so many hours but I'm so confused about methods to do it. Here's an idea I've tried working out, but I got overwhelmed and stumped with:

Copy each RGB array (R[][], G[][], and B[][] separately which combined makes a colored image) into their respective temporary arrays. Split the temporary arrays into a 4x4. Each element would contain its own 2D array with a block of the original image. Then using the random library I can assign the elements to new locations within the 4x4. I have no idea how to do this without making 42 arrays (16 arrays per color in the 4x4, but 42 arrays for R, G, and B). I would appreciate any advice or Here is the code I currently have, but I paused (or possibly abandoned) working on:

            void Shuffle(unsigned char R[WIDTH][HEIGHT], unsigned char G[WIDTH][HEIGHT], unsigned char B[WIDTH][HEIGHT]){

            // Initialize 150x100 inner shuffle arrays. These arrays are chunks of the original image
            int shuffArrR[150][100] = {0};
            int shuffArrG[150][100] = {0};
            int shuffArrB[150][100] = {0};

            int row = 0, col = 0;

        /*
                                BOUNDARY INFO FOR 4x4 ARRAY:

                                 C1: C2: C3: C4:    hBound# (row):
                                -------------------->   1
                           R1:  |   |   |   |   |
                                -------------------->   2
                           R2:  |   |   |   |   |
                                -------------------->   3                       
                           R3:  |   |   |   |   |
                                -------------------->   4
                           R4:  |   |   |   |   |
                                -------------------->   5
                                |   |   |   |   |
                                v   v   v   v   v

                vBound# (col):  1   2   3   4   5

                            vBound:         hBound:         
                            #:  col:        #:  row:
                            1    0          1    0
                            2   150         2   100
                            3   300         3   200
                            4   450         4   300
                            5   600         5   400
        */
            // Define boundaries
            int const vBound1 = 0, vBound2 = 150, vBound3 = 300, vBound4 = 450;
            int const hBound1 = 0, hBound2 = 100, hBound3 = 200, hBound4 = 300;

            for(row; row < HEIGHT; row++){
                for(col; col < WIDTH; col++){

                    // Copy RGB arrays to shuffle arrays
                    shuffArrR[col][row] = R[col][row];
                    shuffArrG[col][row] = G[col][row];
                    shuffArrB[col][row] = B[col][row];

                    // Define 16 blocks in 4x4 array ------------------

                    // If in R1
                    if(row >= hBound1 && row <= hBound2){

                        // And in C1
                        if(col >= vBound1 && col <= vBound2){
                            // ** I stopped here after I realized how many arrays I'd have to make to account for every element in the 4x4 **
                        }

                    }
                }
            }

        }

Solution

    1. Label each block with an ID, 0, 1, 2, ...15 .

      -----------------
      | 12| 13| 14| 15|
      -----------------
      | 8 | 9 | 10| 11|
      -----------------                      
      | 4 | 5 | 6 | 7 |
      -----------------
      | 0 | 1 | 2 | 3 |
      -----------------
      
    2. Put all ID in an array, then shuffle the array. shuffle like this. Then traversal the array and swap content of each block.

      int arr[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
      arr_shuffle(arr, 16);
      int i;
      for (i = 0; i < 16; i++) {
          swap_block(i, arr[i]);
      }
      
    3. Now the problem will be how to swap two block. Let's say we have block A and block B. Both size should be 100(height) * 150(width). Then think A is an array like A[100][150], and B is B[100][150]. swap this array will be like below.

      for (i = 0; i < 100; i++) {
          for (j = 0; j < 150; j++) {
              swap(A[i][j], B[i][j];
          }
      }
      
    4. The final step should be convert A[i][j] and B[i][j] to the real element in array R/G/B. This can be done simply by math.

      void get_real_id(int block_id, int x, int y, int *real_x, int *real_y)
      {
          int row, col;
      
          row = block_id / 4;   // convert block id to row number
          col = block_id % 4;   // convert block id to col number
      
          // find BLOCK[y][x] in array R, which should be R[real_y][real_x]
          *real_x = (col * (WIDTH/4)) + x;  
          *real_y = (row * (HEIGHT/4)) + y;
      }
      
    5. The sample code in below will work for array R. The define of R is R[HEIGHT][WEIGHT], not R[WEIGHT][HEIGHT] (This define should work too but I can't think with it).

      int R[HEIGHT][WIDTH];
      
      int arr_shuffle(int *arr, int len)
      {
          size_t i;
          for (i = 0; i < len - 1; i++)
          {
              size_t j = i + rand() / (RAND_MAX / (len - i) + 1);
              int t = arr[j];
              arr[j] = arr[i];
              arr[i] = t;
          }
      }
      
      void get_real_id(int block_id, int x, int y, int *real_x, int *real_y)
      {
          int row, col;
      
          row = block_id / 4;
          col = block_id % 4;
      
          *real_x = (col * (WIDTH/4)) + x;
          *real_y = (row * (HEIGHT/4)) + y;
      }
      
      void swap_block(int src, int dst)
      {
          int w_len = WIDTH / 4;  // should be 150
          int h_len = HEIGHT / 4; // should be 100
      
          int i, j;
      
          for (i = 0; i < h_len; i++) {
              for (j = 0; j < w_len; j++) {
                  int real_src_x;
                  int real_src_y;
      
                  int real_dst_x;
                  int real_dst_y;
      
                  get_real_id(src, j, i, &real_src_x, &real_src_y);
                  get_real_id(dst, j, i, &real_dst_x, &real_dst_y);
      
                  // swap two point.
                  int r = R[real_src_y][real_src_x];
                  R[real_src_y][real_src_x] = R[real_dst_y][real_dst_x];
                  R[real_dst_y][real_dst_x] = r;
              }
          }
      }
      
      int Shuffle()
      {
          int i;
          int arr[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
      
          arr_shuffle(arr, 16);
      
          for (i = 0; i < 16; i++) {
              int src_block_id = i;
              int dst_block_id = arr[i];
      
              swap_block(src_block_id, dst_block_id);
          }
      }
      
    6. I should mention there is chance that after the Shuffle nothing changes.