Ask Your Question

eliminate unwanted contours opencv

asked 2017-08-10 09:51:10 -0500

thatc0der gravatar image

I am working on a program that extracts the stickers on the puzzle and then later on finds the RGB of them. Currently, I am at the point where I want to remove any contours that aren't "square" like. I was wondering how I could do this.

What I do is I load the image, gray it, blur it, canny edge detection, dilate it find contours and draw them.

Is there a way I can draw around the contours instead of filling them in? And remove contours that aren't roughly the same size around or have almost 90 degree angles?

public static void main(String[] args) {


        Mat capturedFrame = Imgcodecs.imread("first.png");

        Mat gray = new Mat();
        Imgproc.cvtColor(capturedFrame, gray, Imgproc.COLOR_BGR2GRAY);

        Mat blur = new Mat();
        Imgproc.blur(gray, blur, new Size(3,3));
        //Canny image
        Mat canny = new Mat();
        Imgproc.Canny(blur, canny, 20, 40, 3, true);

        Imgcodecs.imwrite("test.png", canny);

        Mat kernel = Imgproc.getStructuringElement(1, new Size(3,3));
        Mat dilated = new Mat();
        Imgproc.dilate(canny,dilated, kernel);

        List<MatOfPoint> contours = new ArrayList<>();
        //find contours
        Imgproc.findContours(dilated, contours, new Mat(), Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_NONE);
        //draw contours

        Imgproc.cvtColor(capturedFrame, capturedFrame, Imgproc.COLOR_BGR2RGB);
        for(int i = 0; i < contours.size(); i++){
            Imgproc.drawContours(capturedFrame, contours, i, new Scalar(0, 0, 255), -1);

        Imgcodecs.imwrite("after.png", capturedFrame);

        Imshow img = new Imshow("firstImg");;


Here is the initial image:

enter image description here

Here is the image with the contours drawn:

enter image description here

edit retag flag offensive close merge delete

2 answers

Sort by ยป oldest newest most voted

answered 2017-08-10 10:07:12 -0500

Ziri gravatar image

I suggest using color thresholding (inRange() ) then get contours.

Now you want to filter unwanted contours right ?

1 -loop through all contours

2- calculate contour Area or Length

3- eliminate unwanted contours

for( int n = 0; n< contours.size(); n++ )
     double Area = contourArea( contours[i],false);  



Hope it helps

edit flag offensive delete link more


Thanks this helps, however is there a way I could make it more "flexible" like looking if it has some sort of square shape, like the lengths of the sides are the same and or has almost 90 degrees in the contour? The reason I ask is because the image won't always be this one because it is a captured frame the cube could be captured closer or further away.

thatc0der gravatar imagethatc0der ( 2017-08-10 10:11:35 -0500 )edit

There are many ways to approach this case but the easiest is calculating bounding rectangle :

check documentation :

Ziri gravatar imageZiri ( 2017-08-10 10:39:13 -0500 )edit

answered 2017-08-10 11:17:06 -0500

Pedro Batista gravatar image

updated 2017-08-10 11:23:38 -0500

Ziri's answer is valid, just want to add that there is a way to evaluate "squareness" of a blob,

Given a blob, you can calculate the Shape Factor

image description

You can use cv::contourArea() to obtain A and cv::arcLength() to obtain p.

If I remember correctly, for circled blobs you are expected to get values very close to 1. For triangled blobs you are going to get low values around 0.3. For squared blobs you are expected to get values around 0.7-0.8. This will allow you to filter some unwanted blobs.

Hope this helps.

edit flag offensive delete link more


Thank you for the extra help :) So I tired doing something like this

    for(int i = 0; i < contours.size(); i++){

             double area = Imgproc.contourArea( contours.get(i),false); 
             MatOfPoint2f contour2f = new MatOfPoint2f( contours.get(i).toArray());

             double arch = Imgproc.arcLength(contour2f, true);

             double squareness = 4 * Math.PI * area / Math.pow(arch,2);

             System.out.println("Squareness: " + squareness);

             if(squareness <= 0.7 && squareness >=  0.8){

thatc0der gravatar imagethatc0der ( 2017-08-10 13:04:29 -0500 )edit

That is not right, the denominator in the equation is the arch squared, not the square root.

Also, if you don't multiply the result by 100, squareness will be between 0 and 1, so that condition will never verify

But you should first verify the values you are getting for the blobs to create the threshold. The values I wrote in my answer are just indicative.

Pedro Batista gravatar imagePedro Batista ( 2017-08-10 13:51:32 -0500 )edit

Ah, just saw the edit, now its right :)

Pedro Batista gravatar imagePedro Batista ( 2017-08-10 13:52:02 -0500 )edit
Login/Signup to Answer

Question Tools

1 follower


Asked: 2017-08-10 09:51:10 -0500

Seen: 100 times

Last updated: Aug 10