OpenCV C++/Obj-C: Detecting a sheet of paper / Square Detection

前端 未结 6 1171
离开以前
离开以前 2020-11-22 01:47

I successfully implemented the OpenCV square-detection example in my test application, but now need to filter the output, because it\'s quite messy - or is my code wrong?

6条回答
  •  情深已故
    2020-11-22 02:24

    This is a recurring subject in Stackoverflow and since I was unable to find a relevant implementation I decided to accept the challenge.

    I made some modifications to the squares demo present in OpenCV and the resulting C++ code below is able to detect a sheet of paper in the image:

    void find_squares(Mat& image, vector >& squares)
    {
        // blur will enhance edge detection
        Mat blurred(image);
        medianBlur(image, blurred, 9);
    
        Mat gray0(blurred.size(), CV_8U), gray;
        vector > 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 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);
                        }
                }
            }
        }
    }
    

    After this procedure is executed, the sheet of paper will be the largest square in vector >:

    opencv paper sheet detection

    I'm letting you write the function to find the largest square. ;)

提交回复
热议问题