Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCV: Is it possible to detect rectangle from corners?

I have a photo where a person holds a sheet of paper. I'd like to detect the rectangle of that sheet of paper.

enter image description here

I have tried following different tutorials from OpenCV and various SO answers and sample code for detecting squares / rectangles, but the problem is that they all rely on contours of some kind.

If I follow the squares.cpp example, I get the following results from contours:

enter image description here

As you can see, the fingers are part of the contour, so the algorithm does not find the square.

I, also, tried using HoughLines() approach, but I get similar results to above:

enter image description here

I can detect the corners, reliably though:

enter image description here

There are other corners in the image, but I'm limiting total corners found to < 50 and the corners for the sheet of paper are always found.

Is there some algorithm for finding a rectangle from multiple corners in an image? I can't seem to find an existing approach.

like image 691
Misha M Avatar asked Dec 20 '15 04:12

Misha M


1 Answers

You can apply a morphological filter to close the gaps in your edge image. Then if you find the contours, you can detect an inner closed contour as shown below. Then find the convexhull of this contour to get the rectangle.

Closed edges:

closed

Contour:

contour

Convexhull:

hull

In the code below I've just used an arbitrary kernel size for morphological filter and filtered out the contour of interest using an area ratio threshold. You can use your own criteria instead of those.

Code

Mat im = imread("Sh1Vp.png", 0); // the edge image
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(11, 11));
Mat morph;
morphologyEx(im, morph, CV_MOP_CLOSE, kernel);

int rectIdx = 0;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(morph, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
for (size_t idx = 0; idx < contours.size(); idx++)
{
    RotatedRect rect = minAreaRect(contours[idx]);
    double areaRatio = abs(contourArea(contours[idx])) / (rect.size.width * rect.size.height);
    if (areaRatio > .95)
    {
        rectIdx = idx;
        break;
    }
}
// get the convexhull of the contour
vector<Point> hull;
convexHull(contours[rectIdx], hull, false, true);

// visualization
Mat rgb;
cvtColor(im, rgb, CV_GRAY2BGR);
drawContours(rgb, contours, rectIdx, Scalar(0, 0, 255), 2);
for(size_t i = 0; i < hull.size(); i++)
{
    line(rgb, hull[i], hull[(i + 1)%hull.size()], Scalar(0, 255, 0), 2);
}
like image 114
dhanushka Avatar answered Nov 11 '22 01:11

dhanushka