Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Calibrate a page

Hello,

I'm trying to find whenever checkboxes on a scanned sheet of paper are checked or not. Before analyzing the average color of the checkbox and compare it to the average color of blank area on the page, I need to find position of checkboxes.

To do so, I need to "calibrate" my page (because the page can be slightly rotated, and because the scanner autocrop the sheet of paper, not everytime the same way) . I have drawn 3 black squares on the sheet of paper, that I have put near the top right corner, bottom left corner and bottom right corner of the page. I'm trying to find the position of this 3 squares to be able to find the position of checkboxes (I know their position in centimeter, relativly to the calibrating squares, and I know the distance in centimeter between the calibrating squares).

I used the findsquares function from opencv square example. It works, but it finds multiples times the same square (It detect about 500 to 1000 time each square). So I need to filter the results from findsquares. I tried first to write some code to detect square which is most on the top and on the right and the same for the 2 other squares. But I realized after some trials, that it is not possible to define a"top right" corner when there is more than 3 squares (i got thousand of them) randomly disposed on a plane.

Then, I tried to find which squares are really close of the other and delete them. But I got error on execution (list iterator not incrementable), as I must be out of range in some way. Below the code i use. The "squares" variable comes from findSquares(const Mat& image, vector<vector<point> >& squares) from opencv example.

std::list<vector<Point>> liste_square(squares.begin(), squares.end());

for (list<vector<Point>>::iterator x = liste_square.begin(); x != liste_square.end();x++) {
        vector<Point> rect1 = *x;
    for (list<vector<Point>>::iterator y = x++; y != liste_square.end();) 
    {


        vector<Point> rect2 = *y;
        Point middle1 = (rect1[0] + rect1[2])*0.5;
        Point middle2 = (rect2[0] + rect2[2])*0.5;

        Point littlediag = rect1[2] - rect1[0]; //diag of a square
        Point bigdiag = middle2 - middle1; //vector between the two centers of squares

        double diago = cv::sqrt(littlediag.x*littlediag.x + littlediag.y*littlediag.y);
        double distance = cv::sqrt(bigdiag.x*bigdiag.x + bigdiag.y*bigdiag.y);

        if (distance  <= diago)
        {
            y = liste_square.erase(y);
        }
        else
        {
            y++;
        }

    }


}

So now, I'm a little bit lost. I don't know which way is the better : Try to fix the "list iterator not incrementable" error, find another way to calibrate the page than 3 black squares, improve findsquares function...

Do you have any suggestion?

Thanks

Calibrate a page

Hello,

I'm trying to find whenever checkboxes on a scanned sheet of paper are checked or not. Before analyzing the average color of the checkbox and compare it to the average color of blank area on the page, I need to find position of checkboxes.

To do so, I need to "calibrate" my page (because the page can be slightly rotated, and because the scanner autocrop the sheet of paper, not everytime the same way) . I have drawn 3 black squares on the sheet of paper, that I have put near the top right corner, bottom left corner and bottom right corner of the page. I'm trying to find the position of this 3 squares to be able to find the position of checkboxes (I know their position in centimeter, relativly to the calibrating squares, and I know the distance in centimeter between the calibrating squares).

I used the findsquares function from opencv square example. It works, but it finds multiples times the same square (It detect about 500 to 1000 time each square). So I need to filter the results from findsquares. I tried first to write some code to detect square which is most on the top and on the right and the same for the 2 other squares. But I realized after some trials, that it is not possible to define a"top right" corner when there is more than 3 squares (i got thousand of them) randomly disposed on a plane.

Then, I tried to find which squares are really close of the other and delete them. But I got error on execution (list iterator not incrementable), as I must be out of range in some way. Below the code i use. The "squares" variable comes from findSquares(const Mat& image, vector<vector<point> >& squares) from opencv example.

std::list<vector<Point>> liste_square(squares.begin(), squares.end());

for (list<vector<Point>>::iterator x = liste_square.begin(); x != liste_square.end();x++) {
        vector<Point> rect1 = *x;
    for (list<vector<Point>>::iterator y = x++; y != liste_square.end();) 
    {


        vector<Point> rect2 = *y;
        Point middle1 = (rect1[0] + rect1[2])*0.5;
        Point middle2 = (rect2[0] + rect2[2])*0.5;

        Point littlediag = rect1[2] - rect1[0]; //diag of a square
        Point bigdiag = middle2 - middle1; //vector between the two centers of squares

        double diago = cv::sqrt(littlediag.x*littlediag.x + littlediag.y*littlediag.y);
        double distance = cv::sqrt(bigdiag.x*bigdiag.x + bigdiag.y*bigdiag.y);

        if (distance  <= diago)
        {
            y = liste_square.erase(y);
        }
        else
        {
            y++;
        }

    }


}

So now, I'm a little bit lost. I don't know which way is the better : Try to fix the "list iterator not incrementable" error, find another way to calibrate the page than 3 black squares, improve findsquares function...

Do you have any suggestion?

EDIT: As requested, the image : page_to_scan

It's not the original image, as it makes 3.2Mo and 25048x3507 and I cannot upload such big image. I resized the original image using Lanczos filter in Irfanview. In my code, i take the orignal image and resize it in order to : speed up the process, make the QRCode detection works using zbar::ImageScanner (if image is too big, it fails).

    src_big = imread("Start_Empty0001.jpg", 1);
resize(src_big, src, Size(), 0.3, 0.3, INTER_AREA);

The rule to build the document is that checkboxes are always inside the calibration square (defined by the 3 little black squares)

Thanks