Detect centre and angle of rectangles in an image using Opencv

后端 未结 3 1453
名媛妹妹
名媛妹妹 2020-12-05 08:36

I have an image as below :

I need to find out the number of rectangles,centre of each rectangle and the measure the angle between the axis parallel to the l

3条回答
  •  执笔经年
    2020-12-05 09:07

    This is how you can do it with minAreaRect function of openCV. It's written in C++ but probably you can adapt that easily, since nearly only OpenCV functions were used.

        cv::Mat input = cv::imread("../inputData/rectangles.png");
    
        cv::Mat gray;
        cv::cvtColor(input,gray,CV_BGR2GRAY);
    
        // since your image has compression artifacts, we have to threshold the image
        int threshold = 200;
        cv::Mat mask = gray > threshold;
    
        cv::imshow("mask", mask);
    
        // extract contours
        std::vector > contours;
        cv::findContours(mask, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
    
        for(int i=0; i

    resulting in this image:

    as you can see, the angles are probably not what you want (because they randomly use the longer or the smaller line as reference). You can instead extract the longer sides of the rectangles and compute the angle manually.

    If you choose the longer edge of the rotated rects and compute the angle from it it looks like this:

    // choose the longer edge of the rotated rect to compute the angle
            cv::Point2f edge1 = cv::Vec2f(rect_points[1].x, rect_points[1].y) - cv::Vec2f(rect_points[0].x, rect_points[0].y);
            cv::Point2f edge2 = cv::Vec2f(rect_points[2].x, rect_points[2].y) - cv::Vec2f(rect_points[1].x, rect_points[1].y);
    
            cv::Point2f usedEdge = edge1;
            if(cv::norm(edge2) > cv::norm(edge1))
                usedEdge = edge2;
    
            cv::Point2f reference = cv::Vec2f(1,0); // horizontal edge
    
    
            angle = 180.0f/CV_PI * acos((reference.x*usedEdge.x + reference.y*usedEdge.y) / (cv::norm(reference) *cv::norm(usedEdge)));
    

    giving this result, which should be what you are looking for!

    EDIT: It looks like the op doesn't use the input image he posted, because reference rectangle centres would lie outside of the image.

    Using this input (manually rescaled but probably still not optimal):

    I get those results (blue dots are reference rectangle centers provided by the op):

    Comparing the reference with the detections:

    reference (x,y,angle)    detection (x,y,angle)
    (320,240,0)              (320, 240, 180) // angle 180 is equal to angle 0 for lines
    (75,175,90)              (73.5, 174.5, 90)
    (279,401,170)            (279.002, 401.824, 169.992)
    (507,379,61)             (507.842, 379.75, 61.1443)
    (545,95,135)             (545.75, 94.25, 135)
    (307,79,37)              (306.756, 77.8384, 37.1042)
    

    I would love to see the REAL input image though, maybe the result will be even better.

提交回复
热议问题