c++ - 使用 OpenCV 从图像中检测最大矩形

标签 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;
}

最佳答案

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

关于c++ - 使用 OpenCV 从图像中检测最大矩形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15754583/

相关文章:

C++ 编程 - 这种分配是不可避免的内存泄漏吗?

python - 从 C 运行并行 python 脚本

Python 字典 - 将数组附加到字典中的特定键。

c - 关于 OpenCV 坐标

performance - 我的代码中是否有开销使我的线程运行速度变慢[C++]

c++ - Visual Studio 调试幽灵光标 - 程序进入调试但看不到当前行或变量

c++ - DirectX 12 SDK LNK2001

python - groupby.apply() 的不一致行为

python - 尝试使用 CV2 从网络摄像头捕获视频时出错

Matlab在OpenCV中的radon()等价函数