OpenCV C++ - 具有不规则边的矩形检测

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26583649/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 11:38:43  来源:igfitidea点击:

OpenCV C++ - Rectangle detection which has irregular side

c++opencvdetection

提问by stranger

enter image description here

enter image description here

Hi.. I have problem with rectangle detection which has irregular side (not straight) like figure above. actually with method houghline can detect lines on the rectangle with some parameter configuration. After compute intersect and get 4 corner, I can rotate it to normal position.

嗨.. 我有矩形检测问题,它有不规则的边(不是直的),如上图。实际上使用houghline方法可以通过一些参数配置检测矩形上的线条。计算相交并获得 4 个角后,我可以将其旋转到正常位置。

But if I change the image with another rectangle (different size and still has irregular side), I need to reconfigure the parameters again. This is because the line is not detected on four sides, beside that the line can be more than 4.

但是如果我用另一个矩形(不同大小并且仍然有不规则边)更改图像,我需要再次重新配置参数。这是因为没有在四个边上检测到线,此外线可以超过 4。

is there any other method beside houghline which is more simple (does not require reconfiguration / difficult configuration)?

除了 houghline 之外还有其他更简单的方法吗(不需要重新配置/困难的配置)?

回答by Micka

This way is to compute the rotated rectangle that holds all your rectangle pixels.

这种方法是计算包含所有矩形像素的旋转矩形。

Maybe you can combine that with vasanth's answer, so you can first approximate the polynome to get a regular border and afterwards extract the rotated rectangle with cv::minAreaRect

也许您可以将其与 vasanth 的答案结合起来,这样您就可以首先近似多项式以获得规则边界,然后使用 cv::minAreaRect

Here's my code:

这是我的代码:

int main()
{
    cv::Mat input = cv::imread("../inputData/RotatedRect.png");

    // convert to grayscale (you could load as grayscale instead)
    cv::Mat gray;
    cv::cvtColor(input,gray, CV_BGR2GRAY);

    // compute mask (you could use a simple threshold if the image is always as good as the one you provided)
    cv::Mat mask;
    cv::threshold(gray, mask, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);

    // find contours (if always so easy to segment as your image, you could just add the black/rect pixels to a vector)
    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;
    cv::findContours(mask,contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

    /// Draw contours and find biggest contour (if there are other contours in the image, we assume the biggest one is the desired rect)
    // drawing here is only for demonstration!
    int biggestContourIdx = -1;
    float biggestContourArea = 0;
    cv::Mat drawing = cv::Mat::zeros( mask.size(), CV_8UC3 );
    for( int i = 0; i< contours.size(); i++ )
    {
        cv::Scalar color = cv::Scalar(0, 100, 0);
        drawContours( drawing, contours, i, color, 1, 8, hierarchy, 0, cv::Point() );

        float ctArea= cv::contourArea(contours[i]);
        if(ctArea > biggestContourArea)
        {
            biggestContourArea = ctArea;
            biggestContourIdx = i;
        }
    }

    // if no contour found
    if(biggestContourIdx < 0)
    {
        std::cout << "no contour found" << std::endl;
        return 1;
    }

    // compute the rotated bounding rect of the biggest contour! (this is the part that does what you want/need)
    cv::RotatedRect boundingBox = cv::minAreaRect(contours[biggestContourIdx]);
    // one thing to remark: this will compute the OUTER boundary box, so maybe you have to erode/dilate if you want something between the ragged lines



    // draw the rotated rect
    cv::Point2f corners[4];
    boundingBox.points(corners);
    cv::line(drawing, corners[0], corners[1], cv::Scalar(255,255,255));
    cv::line(drawing, corners[1], corners[2], cv::Scalar(255,255,255));
    cv::line(drawing, corners[2], corners[3], cv::Scalar(255,255,255));
    cv::line(drawing, corners[3], corners[0], cv::Scalar(255,255,255));

    // display
    cv::imshow("input", input);
    cv::imshow("drawing", drawing);
    cv::waitKey(0);

    cv::imwrite("rotatedRect.png",drawing);

    return 0;
}

giving this result:

给出这个结果:

enter image description here

enter image description here

回答by bikz05

Using elementary geometry, you need to find the co-ordinate where

使用基本几何,您需要找到坐标

  • Black pixel location with smallest x co-ordinate
  • Black pixel location with largest x co-ordinate
  • Black pixel location with smallest y co-ordinate
  • Black pixel location with largest y co-ordinate
  • 具有最小 x 坐标的黑色像素位置
  • x 坐标最大的黑色像素位置
  • y 坐标最小的黑色像素位置
  • y 坐标最大的黑色像素位置

These 4 points will be the edges of your rectangle.

这 4 个点将是矩形的边缘。

回答by Vasanth

Try this:

尝试这个:

1.Run findCountourson the image.

1.在图像上运行findCountours

2.Apply approxPolyDPto approximate the contour to a rectangle. The contour sides will be a lot more regular.

2.适用approxPolyDP近似轮廓为矩形。轮廓边将更加规则。

3.Segment the rectangular contours using momentsand/or geometry.

3.使用力矩和/或几何体分割矩形轮廓。