Hough line transform to find polygons in an image

2.3k views Asked by At

I am trying to find all the polygons (including the filled in one) in the image below. Currently, I'm trying to use Hough Transform to accomplish this, but it does not detect all the lines in the image. In addition, because of how wide the lines are, it counts each line twice. Is there a way to apply some filters to the image to make the Hough Transform perform better or is there an entirely different way to find the polygons that I'm missing? Thanks!

Here is the picture I am processing,

and my code is below.

import cv2
import numpy as np

img = cv2.imread('test.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
minLineLength = 100
maxLineGap = 10
lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap)
for num in range (0, len(lines)):
    for x1,y1,x2,y2 in lines[num]:
        cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)

cv2.imwrite('houghlines.jpg',img)
1

There are 1 answers

0
StereoMatching On BEST ANSWER

I think using findContours is easier for this problem.

Following are the solution, I write down the comments, if you have any questions, please ask.

void detect_by_contour()
{
    //Following comments are written for non c++ programmers
    auto img = cv::imread("../forum_quest/data/yd8pA.png");
    if(img.empty()){
        throw std::runtime_error("cannot open image");
    }

    cv::Mat gray_img;
    cv::cvtColor(img, gray_img, CV_BGR2GRAY);
    cv::Mat thin_img;
    //make your lines as thin as possible
    morphology_skeleton(gray_img, thin_img);

    std::vector<std::vector<cv::Point>> contours;
    cv::findContours(thin_img, contours, cv::RETR_EXTERNAL,
                     cv::CHAIN_APPROX_SIMPLE);
    //remove contour if the area less than 100
    auto it = std::remove_if(std::begin(contours), std::end(contours),
                   [](std::vector<cv::Point> const &a)
    {
        return cv::boundingRect(a).area() < 100;
    });
    //remove_if move unwanted elements to the backyard of the containers
    //you need to call the erase function of the containers to remove
    //unwanted elements
    contours.erase(it, std::end(contours));

    //contour_analyzer is a class used to print out statistic info
    //of the contour
    ocv::contour_analyzer analyzer;
    //print_contour_attribute_name print out the attribute names
    //of the contours as following
    //CArea   |   BArea   | Perimeter |   Aspect  |   Extent  |  Solidity |  PolySize
    ocv::print_contour_attribute_name(std::cout);
    for(size_t i = 0; i != contours.size(); ++i){
        cv::drawContours(img, contours, static_cast<int>(i), {0,255,0}, 2);        
        std::cout<<analyzer.analyze(contours[i], 0.1);
        cv::imshow("img", img);
        cv::waitKey();
    }
    cv::imwrite("polygon.jpg", img);
}

If you run the program(I am using opencv3 clone from github).You will find out there are 5 contours

The contours found by the algorithm

Their attributes are

attributes of countour

You can try to figure out the types of the polygon by these attributes.

The codes of detect_by_contour and morphology_skeleton located at forum_quest. The codes of ocv::contour_analyzer analyzer and ocv::contour_analyzer located at ocv_libs.