pythonopencvcontourline-segment

Segmenting overlapping thick lines on a binary image


I do have a binary image as shown below after applying various preprocessing and detection pipelines onto original image.

Intersecting Runways

As seen in the picture there are actually 2 runways (tarmacs) for planes which are crossing each other on an intersection region. What I need is to split both runways and return their contours. I've checked opencv functions regarding contour features but had no luck. cv2.fitLine seems ok but it only works if there is only a single line in the contour. Resulting image when the masks are applied should be looking like this: enter image description here


Solution

  • I tried to solve your problem with C++ referencing my old answer.

    some steps:

    --after finding contours find defect points by convexityDefects
    
    approxPolyDP(contours[i], contours[i], 9, true);
    convexHull(contours[i], contoursHull, true);
    convexityDefects(contours[i], contoursHull, defects);
    

    enter image description here

    create two copy of binary image and draw lines using defect points

    Vec4i defpoint0 = defects[0];
    Vec4i defpoint1 = defects[1];
    Vec4i defpoint2 = defects[2];
    Vec4i defpoint3 = defects[3];
    line(bw0, contours[i][defpoint0[2]], contours[i][defpoint1[2]], Scalar(0), 2);
    line(bw0, contours[i][defpoint2[2]], contours[i][defpoint3[2]], Scalar(0), 2);
    
    line(bw1, contours[i][defpoint0[2]], contours[i][defpoint3[2]], Scalar(0), 2);
    line(bw1, contours[i][defpoint1[2]], contours[i][defpoint2[2]], Scalar(0), 2);
    

    enter image description here

    enter image description here

    find contours from images and draw them ( i hardcoded found contour index, need to be improved )

    findContours(bw0, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
    drawContours(src, contours, 1, Scalar((rand() & 255), (rand() & 255), (rand() & 255)), 2);
    
    findContours(bw1, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
    drawContours(src, contours, 2, Scalar((rand() & 255), (rand() & 255), (rand() & 255)), 2);
    

    enter image description here

    #include <opencv2/highgui.hpp>
    #include <opencv2/imgproc.hpp>
    #include <iostream>
    
    using namespace cv;
    using namespace std;
    
    int main(int argc, char** argv)
    {
        Mat src = imread("e:/test/crossing_lines.png");
        if (src.empty())
            return -1;
    
        Mat bw,bw0,bw1;
        cvtColor(src, bw, COLOR_BGR2GRAY);
        bw = bw > 127;
        bw0 = bw.clone();
        bw1 = bw.clone();
        // Find contours
        vector<vector<Point> > contours;
        vector<int> contoursHull;
        vector<Vec4i> defects;
        findContours(bw, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
    
        for (size_t i = 0; i < contours.size(); i++)
        {
            if (contourArea(contours[i]) > 500)
            {
                approxPolyDP(contours[i], contours[i], 9, true);
                convexHull(contours[i], contoursHull, true);
                convexityDefects(contours[i], contoursHull, defects);
     
                Vec4i defpoint0 = defects[0];
                Vec4i defpoint1 = defects[1];
                Vec4i defpoint2 = defects[2];
                Vec4i defpoint3 = defects[3];
                line(bw0, contours[i][defpoint0[2]], contours[i][defpoint1[2]], Scalar(0), 2);
                line(bw0, contours[i][defpoint2[2]], contours[i][defpoint3[2]], Scalar(0), 2);
    
                line(bw1, contours[i][defpoint0[2]], contours[i][defpoint3[2]], Scalar(0), 2);
                line(bw1, contours[i][defpoint1[2]], contours[i][defpoint2[2]], Scalar(0), 2);
            }
        }
        findContours(bw0, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
        drawContours(src, contours, 1, Scalar((rand() & 255), (rand() & 255), (rand() & 255)), 2);
    
        findContours(bw1, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
        drawContours(src, contours, 2, Scalar((rand() & 255), (rand() & 255), (rand() & 255)), 2);
        imshow("src", src);
        imshow("bw0", bw0);
        imshow("bw1", bw1);
        waitKey();
        return 0;
    }