0

I have a picture with a table in it and I need to extract the boxes with the handwriting in it then crop them,because I need to recognise the handwriting in those boxes one by one but the problem is the findSquare function gives me an output of too many squares with the same coordinates(+-5 pixels) beacuse of the several threshold levels.I already reduced the number of squares from 300 to 90 by searching in only one channel.The teacher told me to filter the extra squares by their coordinates,if the difference between the square coordinates is less then 10 pixels it means it's the same box. The picture with the table is here https://ibb.co/Ms8YP8n And instead of 20 boxes it crops me around 90 and most of them are the same. So I was trying to go through the squares vector in a for loop and eliminate the squares that are seen twice.

Here is the code that I was trying with

vector<vector<Point> > same;
same.clear();
same = squares;
int sq = squares.size();

for (int i = 0; i < sq; i++) {

    for (int j = 1; j < sq-1; j++) {
        if (-5 < (same[i][0].x - same[j][0].x) < 5 && -5 < (same[i][0].y - same[j][0].y) < 5 &&
            -5 < (same[i][1].x - same[j][1].x) < 5 && -5 < (same[i][1].y - same[j][1].y) < 5 &&
            -5 < (same[i][2].x - same[j][2].x) < 5 && -5 < (same[i][2].y - same[j][2].y) < 5 &&
            -5 < (same[i][3].x - same[j][3].x) < 5 && -5 < (same[i][3].y - same[j][3].y) < 5) {
            squares.erase(same.begin() + j);
        }
    }
}

The "same" vector is just a copy of "squares".

The error that gives me is "Vector erase iterator outside range". You can find this code in the drawSquare function bellow where you can see the full code too.

I need the pictures for future proccessing, I need to recognise the handwritten numbers.

Can anybody please help me?With another method or ideeas or some fixes in this code...

Thank you !

static void findSquares(const Mat& image, vector<vector<Point> >& squares)
{
    squares.clear();
    Mat pyr, timg, timb, gray0(image.size(), CV_8UC1), gray;
    pyrDown(image, pyr, Size(image.cols / 2, image.rows / 2));
    pyrUp(pyr, timg, image.size());

    vector<vector<Point> > contours;

    // find squares in every color plane of the image
    for (int c = 0; c < 1; c++)
    {
        int ch[] = { c, 0 };
        mixChannels(&timg, 1, &gray0, 1, ch, 1);


        // try several threshold levels
        for (int l = 0; l < N; l++)
        {
            // hack: use Canny instead of zero threshold level.
            // Canny helps to catch squares with gradient shading
            if (l == 0)
            {
                // apply Canny. Take the upper threshold from slider
                // and set the lower to 0 (which forces edges merging)
                Canny(gray0, gray, 0, thresh, 5);
                // dilate canny output to remove potential
                // holes between edge segments
                dilate(gray, gray, Mat(), Point(-1, -1));
            }
            else
            {
                // apply threshold if l!=0:
                //  tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
                gray = gray0 >= (l + 1) * 255 / N;
                //          imshow("graaay0", gray);
            }

            // find contours and store them all as a list
            findContours(gray, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);

            vector<Point> approx;

            // test each contour
            for (int i = 0; i < contours.size(); i++)
            {
                // approximate contour with accuracy proportional
                // to the contour perimeter
                approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);

                // square contours should have 4 vertices after approximation
                // relatively large area (to filter out noisy contours)
                //// and be convex.
                // Note: absolute value of an area is used because
                // area may be positive or negative - in accordance with the
                // contour orientation
                if (approx.size() >= 4 && approx.size() <= 6 &&
                    fabs(contourArea(Mat(approx))) > 5000 && fabs(contourArea(Mat(approx))) < 8000 &&
                    isContourConvex(Mat(approx)))
                {
                    double maxCosine = 0;

                    for (int j = 2; j < 5; j++)
                    {
                        // find the maximum cosine of the angle between joint edges
                        double cosine = fabs(angle(approx[j % 4], approx[j - 2], approx[j - 1]));
                        maxCosine = MAX(maxCosine, cosine);
                    }

                    // if cosines of all angles are small
                    // (all angles are ~90 degree) then write quandrange
                    // vertices to resultant sequence
                    if (maxCosine >= 0 && maxCosine < 0.2)
                        squares.push_back(approx);
                }
            }
        }
    }

    }


    // the function draws all the squares in the image


 static void drawSquares(Mat& image, vector<vector<Point> > &squares)
    {

    vector<vector<Point> > same;
    same.clear();
    same = squares;
    int sq = squares.size();

    for (int i = 0; i < sq; i++) {

        for (int j = 1; j < sq; j++) {
            if (-5 < (same[i][0].x - same[j][0].x) < 5 && -5 < (same[i][0].y - same[j][0].y) < 5 &&
                -5 < (same[i][1].x - same[j][1].x) < 5 && -5 < (same[i][1].y - same[j][1].y) < 5 &&
                -5 < (same[i][2].x - same[j][2].x) < 5 && -5 < (same[i][2].y - same[j][2].y) < 5 &&
                -5 < (same[i][3].x - same[j][3].x) < 5 && -5 < (same[i][3].y - same[j][3].y) < 5) {
                squares.erase(same.begin() + j);
            }
        }
    }




    for (int i = 0; i < squares.size(); i++)
    {

        const Point* p = &squares[i][0];
        int n = (int)squares[i].size();
        polylines(image, &p, &n, 1, true, Scalar(0, 255, 0), 3, LINE_AA);

    }

    imshow("Plate with green", image);

    }



Mat ImageExtract(Mat& image, vector<vector<Point> >& squares)
    {

    char file_name[100];
    int x = squares.size();
    printf("squaree %d", x);


    Mat roi;
    for (int i = 0; i < squares.size(); i++)
    {

        sprintf(file_name, "cropped%d.jpg", i + 1);
        Rect r = boundingRect(squares[i]);
        roi = Mat(image, r);
        imwrite(file_name, roi);

    }
    return roi;

    }


void Preprocessing() {

    char fname[MAX_PATH];
    openFileDlg(fname);
    Mat img = imread(fname, 1);
    std::vector<std::vector<Point> > squares;

    findSquares(img, squares);
    ImageExtract(img, squares);
    drawSquares(img, squares);



    waitKey(0);
    }

int main() {
       Preprocessing();
    return 0;
    }


  [1]: https://i.stack.imgur.com/mwvxX.png
  • 1
    So... what is the exact problem? Where are you trying to filter the squares? Make sure to provide a [mcve]. Please pay extra attention to the *Minimal* nad *Complete* parts – Fureeish Jan 05 '19 at 17:29
  • Hi,I am sorry , I am new here , I have rewritten it ,I hope I did it good this time – Balaj Cristian Jan 05 '19 at 18:13
  • `-5 < (same[i][0].x - same[j][0].x) < 5` does not do what you think it does. It does not check if `(same[i][0].x - same[j][0].x)` is withing range `(5, 5)`. You need to split such logic into two checks. Additionally, it is unsafe to erase elements from a collection that is iterated over, unless both iteration and erasing is done with iterators. I would advise you to: **1** - fix the logic in your `if()` statement, **2** - use [erase-remove idiom](https://stackoverflow.com/a/347478/7151494). – Fureeish Jan 05 '19 at 18:26

0 Answers0