使用OpenCV从图像中检测最大的矩形

时间:2013-04-02 01:19:49

标签: c++ python opencv image-processing

我问过上一个问题here,并按照答案的建议,我建立了下面的程序,我认为它会检测到大矩形,但根本没有检测到矩形。它确实适用于此image

Original Image

Desired Image

我希望解决方案不仅适用于此图像,还适用于此类图像。以下代码的主要部分来自SO

的不同答案

我的完整计划:

#include <cv.h>
#include <highgui.h>
using namespace cv;
using namespace std;

double angle(  Point pt1,  Point pt2,  Point pt0 ) {
    double dx1 = pt1.x - pt0.x;
    double dy1 = pt1.y - pt0.y;
    double dx2 = pt2.x - pt0.x;
    double dy2 = pt2.y - pt0.y;
    return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}

void find_squares( Mat& image,  vector< vector< Point> >& squares)
{
    // blur will enhance edge detection
    Mat blurred(image);
    medianBlur(image, blurred, 9);

     Mat gray0(blurred.size(), CV_8U), gray;
     vector< vector< Point> > contours;

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

        // try several threshold levels
        const int threshold_level = 2;
        for (int l = 0; l < threshold_level; l++)
        {
            // Use Canny instead of zero threshold level!
            // Canny helps to catch squares with gradient shading
            if (l == 0)
            {
                 Canny(gray0, gray, 10, 20, 3); // 

                // Dilate helps to remove potential holes between edge segments
                 dilate(gray, gray,  Mat(),  Point(-1,-1));
            }
            else
            {
                    gray = gray0 >= (l+1) * 255 / threshold_level;
            }

            // Find contours and store them in a list
             findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

            // Test contours
             vector< Point> approx;
            for (size_t 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);

                    // 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 &&
                            fabs(contourArea( Mat(approx))) > 1000 &&
                            isContourConvex( Mat(approx)))
                    {
                            double maxCosine = 0;

                            for (int j = 2; j < 5; j++)
                            {
                                    double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
                                    maxCosine = MAX(maxCosine, cosine);
                            }

                            if (maxCosine < 0.3)
                                    squares.push_back(approx);
                    }
            }
        }
    }
}

void find_largest_square(const vector<vector <Point> >& squares, vector<Point>& biggest_square) {
    if (!squares.size()) {
        return;
    }

    int max_width = 0;
    int max_height = 0;
    int max_square_idx = 0;
    const int n_points = 4;

    for (size_t i = 0; i < squares.size(); i++) {
        Rect rectangle = boundingRect(Mat(squares[i]));
        if ((rectangle.width >= max_width) && (rectangle.height >= max_height)) {
            max_width = rectangle.width;
            max_height = rectangle.height;
            max_square_idx = i;
        }
    }
    biggest_square = squares[max_square_idx];

}

int main(int argc, char* argv[])
{
    Mat img =  imread(argv[1]);
    if (img.empty())
    {
         cout << "!!! imread() failed to open target image" <<  endl;
        return -1;        
    }
    vector< vector< Point> > squares;
    find_squares(img, squares);
    vector<Point> largest_square;
    find_largest_square(squares, largest_square);
    for (int i = 0; i < 4; ++i) {
        line(img, largest_square[i], largest_square[(i+1)%4], Scalar(0, 255, 0), 1, CV_AA);
    }
    imwrite("squares.png", img);
    imshow("squares", img);
    waitKey(0);
    return 0;
}

1 个答案:

答案 0 :(得分:1)

我认为你可以使用findContours函数轻松完成 - http://docs.opencv.org/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.html最大的轮廓(或最终的第二大轮廓)应该是黑色矩形的轮廓。然后找到围绕这个轮廓的最小矩形(只找到最大/最小x / y坐标的点)。