Ask Your Question
1

Removed contours aren't gone

asked 2017-08-11 07:01:01 -0500

thatc0der gravatar image

updated 2017-08-11 07:05:21 -0500

berak gravatar image

I am trying to remove any contours that aren't in a square like shape. I check the image before and after to see if any contours have been removed. I use the circularity formula and values between 0.7 and 0.8 are square shaped. I expect to see that some contour lines are removed but none are

Here is what I have done so far.

public static void main(String[] args) {


        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

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

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

        //Blur
        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);

        //Dilate image to increase size of lines
        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);

        //convert image 
        Imgproc.cvtColor(capturedFrame, capturedFrame, Imgproc.COLOR_BGR2RGB);


        //Draw contours on original image
        for(int n = 0; n < contours.size(); n++){
            Imgproc.drawContours(capturedFrame, contours, n, new Scalar(255, 0 , 0), 1);
        }

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

        //display image with all contours
        Imshow showImg = new Imshow("displayImage");
        showImg.show(capturedFrame);


        //Remove contours that aren't close to a square shape.
        for(int i = 0; i < contours.size(); i++){

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

            //Found squareness equation on wiki... 
            // https://en.wikipedia.org/wiki/Shape_factor_(image_analysis_and_microscopy)
            double squareness = 4 * Math.PI * area / Math.pow(perimeter, 2);

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


            if(squareness <= 0.7 && squareness >=  0.8){
                contours.remove(i);
            }
        }


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

        showImg.show(capturedFrame);
        Imgcodecs.imwrite("remove.png", capturedFrame);

    }

Here is the original image:

enter image description here

Here is the image before any contours are removed:

enter image description here

Here is the image final image where contours some contours should be removed:

enter image description here

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
4

answered 2017-08-11 07:48:35 -0500

eshirima gravatar image

updated 2017-08-11 09:17:37 -0500

I am not well versed with the implementation of Java's Collections but I doubt contours.remove(i) is doing exactly what you are thinking its doing.

You are removing an element from a container whilst iterating over it. If this even works, then i will have an offset of sorts because the container might be changing lengths after each iteration. I would recommend the following methods:

Method 1: Creating another list to hold the found squares as shown below

List<MatOfPoint> squareContours = new ArrayList<>();

    //Remove contours that aren't close to a square shape.
    for(int i = 0; i < contours.size(); ++i)
    {
        double area = Imgproc.contourArea(contours.get(i)); 
        MatOfPoint2f contour2f = new MatOfPoint2f(contours.get(i).toArray());
        double perimeter = Imgproc.arcLength(contour2f, true);

        //Found squareness equation on wiki... 
        // https://en.wikipedia.org/wiki/Shape_factor_(image_analysis_and_microscopy)
        double squareness = 4 * Math.PI * area / Math.pow(perimeter, 2);

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

        if(squareness >= 0.7 && squareness <=  0.8)
        {
            squareContours.add(contours[i]); // similar to squareContours.add(contours.get(i))
        }
    }

Then use squareContours from this point onwards

Method 2: Looping over your container with an iterator then using it to remove elements

ListIterator <MatOfPoint> iter = contours.listIterator();

while(iter.hasNext())
{
    MatOfPoint contour = iter.next(); // this gets the actual element the iterator is pointing @
    // then you can go ahead and perform other tasks.
    double area = Imgproc.contourArea(contour);
    ..................
    if(squareness >= 0.7 && squareness <=  0.8)
    {
        iter.remove(); // this removes that particular element the iterator is pointing @
    }
}

This and this might be helpful in understanding iterators in Java

edit flag offensive delete link more

Comments

Thanks for the help I used your earlier listed method also for any one that ends up looking at this in the future. My condition also wasn't correct. IF I want to add the squareContours between 0.7 and 0.8 the condition would be if(squareness >= 0.7 && squareness <= 0.8) .

thatc0der gravatar imagethatc0der ( 2017-08-11 08:27:16 -0500 )edit

Good catch.. Added it to the answer.. Please don't forget to mark as answer & upvote if it helped resolve your question.. Happy coding, cheers mate :)

eshirima gravatar imageeshirima ( 2017-08-11 09:34:30 -0500 )edit

sorry did do that just now :) the Internet was down thank you for all the help :)

thatc0der gravatar imagethatc0der ( 2017-08-11 10:07:08 -0500 )edit
Login/Signup to Answer

Question Tools

1 follower

Stats

Asked: 2017-08-11 07:01:01 -0500

Seen: 58 times

Last updated: Aug 11