Home > Software engineering >  How to remove unwanted contours using opencv?
How to remove unwanted contours using opencv?

Time:12-20

I am able to find the contours and labelled all of them. Now I want to remove some contours from the image and need some specific contours only using opencv.

I have used following code to get the contours. This code is working fine for me to get the contours and its labels: as you see the binary image and its contours in the picture. Here, I want to remove contours which are above contour 45 and below contour 22. Basically, I need the center part between the two long horizontal lines.


int main(int argc, char *argv[])
{
    if (argc != 2) {
        cerr << "usage: "<<argv[0]<< "<input_file with path>"<<endl;
        return -1;
    }
    cv::Mat im_bw = cv::imread(argv[1],cv::IMREAD_GRAYSCALE); //loading an image//

    // Binarize the output image
    cv::Mat binarized_image;
    cv::threshold(im_bw, binarized_image, 128, 255, cv::THRESH_BINARY);

    cv::imshow("binary_image.png", binarized_image);
    cv::waitKey(0);
    
    vector<vector<cv::Point>> contours;
    vector<cv::Vec4i> hierarchy;
    
    cv::findContours(binarized_image,contours,hierarchy,cv::RETR_TREE,cv::CHAIN_APPROX_SIMPLE);
    
    cv::Mat mask = cv::Mat::zeros(im_bw.size(),CV_8UC3);
    
    cv::drawContours(mask,contours,-1,cv::Scalar(0,255,255),1);
    
    for( int i=0; i<contours.size(); i  )
    {
        cv::putText(mask,to_string(i),contours[i][0],1,1,cv::Scalar(255,0,0),1);
    }
    
    cout<<"Contours : "<<contours.size()<<endl;
    for(cv::Vec4i k:hierarchy)
    {
        cout<<k<<endl;
    }
    
    cv::imshow("Contours_binary_image.png", mask);
    cv::waitKey(0);
    
    return 0;
}

Contour Image

CodePudding user response:

There are probably a few ways you could do it depending on what you care about. Do you want it to be fast, or accurate?

Here is a way you could do it geometrically that should be fairly accurate, and with some optimizations, could be pretty fast.

You'll need a way to identify contours 45 and 22. In the question you identified them as the two large horizontal lines. That is a good place to start.

A simple way to do it would be to iterate through all the contours and keep track of the min and max point values. The horizontal lines will be the largest distance in the min/max X direction and have a relatively small distance between min and max Y. It will probably requires some tweaking and defining some more rules for what is allowed to be considered a "horizontal line".

Once you have the horizontal lines identified, the next step is removing all the ones above and below them. Doing this for the top and bottom will be the same, just in opposite directions. I'll walk through how you could do it with the top line.

Each contour is made up of smaller individual line segments. For each linesegment in the horizontal line's contour, check that every other contour (each segment in said contour) is either above it, or intersects with it. If either is true, then you can remove it. For a large number of contours, or very complex contours, this will be quite slow. There are a number of optimizations you could make. You could simplify the contour shapes. Or compute bounding boxes around them and check the bounding box is above the horizontal line, if it intersects, you can look at it closer and see if the line itself intersects.

CodePudding user response:

Here are the steps I can suggest you to handle this issue:

  1. First you need to get the mass center of each contour by using opencv moments. This will give you the weighted centeral point of contours as x,y coordinates.
  2. Then make a filter according to the mass center's y-axis. Between 45th and 22th contour's y-axis values will be the valid contours.
  3. Only draw the contours which are valid according to your filter.

This may help to find the mass centers.

  • Related