0
votes

I want to write a program which can correct an answer sheet by opencv in C++.

But as I use cvFindContours() the contours' border-points hasn't been completely found.

I mean, I don't have closed-objects. (I use cvDilate and cvErode, without know their real functionality, but dilate omit some contours and erode add some extra, unwanted contours)

And the bigger problem is that I want to find a center-dot in each contour (to compare the location of answers with predefined left & down sidebars), but some contours are not symmetric so the center-dot's location is not exactly in the middle.

Look at the black picture, on the left, in the second contour, some of the bottom points are detected but the top ones are not detected.

This is the Answer sheet:

First 8 answers

cvCvtColor(pic, blackpic, CV_BGR2GRAY);
cvResize(blackpic, src0);
cvSmooth(src0, src0, CV_GAUSSIAN, 3, 3);
cvThreshold(src0, src, 140, 255, CV_THRESH_BINARY);


//Find Contour
CvMemStorage* st = cvCreateMemStorage();
CvSeq* first_contour = NULL;
cvFindContours(src, st, &first_contour, sizeof(CvContour), CV_RETR_LIST);

vector <vector <CvPoint> > cont;
vector <CvPoint> dot;

for (CvSeq* s = first_contour; s != NULL; s = s->h_next)
    if (s -> total > C_MIN_SIZE && cvContourArea(s) > C_MIN_AREA)
    {
        cont.push_back(vector <CvPoint>()); //convert seq to vector
        CvPoint c = cvPoint(0,0);
        for (int i = 0; i < s -> total; i++)
        {
            CvPoint* p = CV_GET_SEQ_ELEM(CvPoint, s, i);
            cont.back().push_back(*p);
            CV_IMAGE_ELEM(test, uchar, p -> y, p -> x) = 255; //drawing each contour's point
            c.x += p -> x; //find the center point by average
            c.y += p -> y;
        }
        c.x = floor(c.x / s -> total);
        c.y = floor(c.y / s -> total);
        dot.push_back(c);
    }
  • Although I am using C++, but I use IplImage* and CvPoint (c structres for opencv) insted of cv::Mat and cv::Point (C++ stractures), if it is possible, please don't use Mat and C++ mode.

  • I don't understand that when I draw contours by cvDrawContours() the contours are completely drawn, but when I personally iterate over the contours' points and draw them point by point, it seems that most of them are not detected!

1
findContours has different ways to represent the contour. One way (default) is to only save "some" of the points and interpolate between them by assuming straight lines. Most probably, drawContours will fill those lines but you don't. In c++ to save ALL points, use method CV_CHAIN_APPROX_NONE. According to docs.opencv.org/modules/imgproc/doc/… C syntax uses exatcly the same parameter.Micka
I thought that ,by default all of the points are stored. Thank youMilad R
+ Why you stackoverflow members just like the questions with extraordinary issues in a way that you hardly understand their title? "All of the easy question will be downvoted" I think this must be your first principle in stackoverflow. I searched, tried for hours, and got confused! So it's my right to be able to ask! But you think that my question is not an epic in computer industry, so let's downvote it immediately!Milad R

1 Answers

2
votes

For your first question, you can have thousands of links on the internet that explain Erode, Dilate and all the other basic image processing pillars, take your time while reading the documentation don't jump over steps .

Second question :

I am not sure what do you expect from the contour center ? do you think you will have a point exactly at the center of those ellipses ? NO, that will never happen and if it is the case, congratulations for this big heap in Image Processing history !!

What I suggest to do, is a simple manipulation that resolves your issue :

  1. find the contours (exactly like you are doing now)
  2. calculate the center of each contour
  3. when you compare the answers with centers location don't compare using a == b because this never happens !! rather, use a comparison in of distance (threshold) to ensure the operation of your software

Example :

bool correct;
CvPoint answer, center;
double distance = sqrt((answer.X - center.X)^2 + (answer.Y - center.Y)^2); // Euclidean distance

// judge using this distance 

if (distance <= 5)    // here you select the number as you (want) i gave example 5
{
    correct = true; // correct answer :)
}

Good luck