1

I'm trying to divide an image into a grid, and save the individual pieces. At the moment I loop through the piece number and get a sub-image, which I then save.

Can someone explain how to get the sub-images properly? I've been following similar posts on stackoverflow, but my code keeps failing an assertion which checks the bounds of the sub-image vs. the original.

int unitWidth = image.rows / n;
int unitHeight = image.cols / n;
for(int i=0; i<n; i++) {
    //Take the next tile in the nxn grid. Unit is the width and height of
    //each tile. i%n and i/n are just fancy ways of a double x,y for loop
    Mat subImage = image(Rect((i % n) * unitWidth, (i / n) * unitHeight, unitWidth,unitHeight));

    ostringstream oss;
    oss << i << "_" << n << ".jpg";
    string name = oss.str();
    imwrite(name, subImage);
}

p.s. the first subimage doesn't break the program, but the second does (for a 2x2 grid, so an end piece). I've shortening the sub-image by 10, but that still broke the machine.

Mirror318
  • 11,875
  • 14
  • 64
  • 106
  • "i%n and i/n are just fancy ways of a double x,y for loop". Since `i%n==i` and `i/n==0`, and the loop iterates n times instead of the required nxn times, how is that a fancy doouble loop. Even if it was, it would be just obfuscation for no advantage. – Bull Sep 06 '13 at 01:26

2 Answers2

3

Below is your code fixed so that it breaks the image into nxn tiles.

Firstly you calculation of unitWidth and unitHeight is incorrect, and that is the cause of the assertion failure. It should be:

int unitWidth = image.cols / n;  // you had image.rows / n;
int unitHeight = image.rows / n; //  "   "  image.cols / n;

Furthermore, if you want an nxn tiling, you need to loop n^2 times, not just n times. THe easiest way to do this is to just have two loops, one inside the other, one loping n times for the rows and the other looping n times for the columns.

for(int i = 0; i < n; i++) {  //i is row index
    // inner loop added so that more than one row of tiles written
    for(int j = 0; j < n; j++) { // j is col index
        //Take the next tile in the nxn grid. Unit is the width and height of
        //each tile. i%n and i/n are just fancy ways of a double x,y for loop

        // Mat subImage = image(Rect((i % n) * unitWidth, (i / n) * unitHeight, unitWidth, unitHeight));
        // I didn't understand the above line, as ((i % n)==i and (i / n)==0.
        // 
        Mat subImage = image(Rect(j * unitWidth, i * unitHeight, unitWidth, unitHeight));

        ostringstream oss;
        oss << i << "_" << j << ".jpg";
        string name = oss.str();
        imwrite(name, subImage);
    }
}

The easiest way to debug code like this is to make the Rect a separate object so that you can print out its x,y,width,height and check them against the OpenCV assertion message. Have you compile your code in debug mode?

        cv::Rect roi(j * unitWidth, i * unitHeight, unitWidth, unitHeight);
        cout << "(i, j) = (" << i << ", " << j << ")" << endl;
        cout << "(i %n) = " << i%n  << endl;
        cout << "(i/n) = " << i/n << endl;
        cout << "roi.x = " << roi.x << endl;
        cout << "roi.y = " << roi.y << endl;
        cout << "roi.width = " << roi.width << endl;
        cout << "roi.height = " << roi.height << endl;
        Mat subImage = image(roi);
Bull
  • 11,771
  • 9
  • 42
  • 53
  • This is the same thing, you just use 2 loops instead of my 1 loop. Using the code you put here, I get the same error. On the last iteration of the first row (the one where the rect touches the end of the mat) it crashes. – Mirror318 Sep 06 '13 at 01:11
  • @Mirror318 this is not the same as your code. Your loop could only write n images instead of the n^2 required for an nxn tiling. Also `(i%n)==i` so why not just use `j`; and `(i/n)==0` so your code can only ever tile the first row. Furthermore, your calculation of unitWidth and unitHeight is wrong and that is what causes the assertion to fail. The code I posted has been tested and it works fine. – Bull Sep 06 '13 at 01:19
  • Right, the for loop was supposed to go to n*n. Anyway, the main problem was the values I had stored as width and height, thanks for the help! – Mirror318 Sep 06 '13 at 02:19
0
for(int i = 0; i < n-unitHeight; i++) {  
    for(int j = 0; j < n-unitWidth; j++) {
        ...........
        ...........
        ...........
    }
}
Navnath Godse
  • 2,233
  • 2
  • 23
  • 32