9

I am currently working on image processing project. I am using Opencv2.3.1 with VC++. I have written the code such that, the input image is filtered to only blue color and converted to a binary image. The binary image has some small objects which I don't want. I wanted to eliminate those small objects, so i used openCV's cvFindContours() method to detect contours in Binary image. but the problem is I cant eliminate the small objects in the image output. I used cvContourArea() function , but didn't work properly.. , erode function also didn't work properly.

So please someone help me with this problem..

The binary image which I obtained :

enter image description here

The result/output image which I want to obtain :

enter image description here

karlphillip
  • 92,053
  • 36
  • 243
  • 426
Manoj M
  • 99
  • 1
  • 2
  • 4

6 Answers6

10

Ok, I believe your problem could be solved with the bounding box demo recently introduced by OpenCV.

enter image description here

As you have probably noticed, the object you are interested at should be inside the largest rectangle draw in the picture. Luckily, this code is not very complex and I'm sure you can figure it all out by investigating and experimenting with it.

karlphillip
  • 92,053
  • 36
  • 243
  • 426
8

Here is my solution to eliminate small contours. The basic idea is check the length/area for each contour, then delete the smaller one from vector container.

normally you will get contours like this

Mat canny_output; //example from OpenCV Tutorial
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Canny(src_img, canny_output, thresh, thresh*2, 3);//with or without, explained later.
findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0,0));

With Canny() pre-processing, you will get contour segments, however each segment is stored with boundary pixels as a closed ring. In this case, you can check the length and delete the small one like

for (vector<vector<Point> >::iterator it = contours.begin(); it!=contours.end(); )
{
    if (it->size()<contour_length_threshold)
        it=contours.erase(it);
    else
        ++it;
}

Without Canny() preprocessing, you will get contours of objects. Similarity, you can also use area to define a threshold to eliminate small objects, as OpenCV tutorial shown

vector<Point> contour = contours[i];
double area0 = contourArea(contour);

this contourArea() is the number of non-zero pixels

Mass Zhou
  • 349
  • 3
  • 6
1

Are you sure filtering by small contour area didn't work? It's always worked for me. Can we see your code?

Also, as sue-ling mentioned, it's a good idea to use both erode and dilate to approximately preserve area. To remove small noisy bits, use erode first, and to fill in holes, use dilate first.

And another aside, you may want to check out the new C++ versions of the cv* functions if you weren't aware of them already (documentation for findContours). They're much easier to use, in my opinion.

fferen
  • 499
  • 3
  • 8
  • Thanks for the suggestion, but I am not getting to how to write the code to find area of each blob/ contour which has been detected. The code which I have written is in the following link. Can u please correct it and reply. : http://textuploader.com/?p=6&id=YwRl . – Manoj M Apr 20 '12 at 02:16
  • oh! I just forgot , the header and cpp file for cvutility can be found in these links :http://textuploader.com/?p=6&id=Dtnvj http://textuploader.com/?p=6&id=TSlRQ Please include them in source directory and include paths . – Manoj M Apr 20 '12 at 02:28
  • I'm not too familiar with the C api, but it looks like you are just calculating the area of the first contour. You need to iterate through the contours and only draw the ones with area > some threshold. If you are just trying to find that one object, you should draw the contour with the largest area. – fferen Apr 20 '12 at 03:09
0

Judging by the before and after images, you need to determine the area of all the white areas or blobs, then apply a threshold area value. This would eliminate all areas less than the value and leave only the large white region which is seen in the 2nd image. After using the cvFindContours function, try using 0 order moments. This would return the area of the blobs in the image. This link might be helpful in implementing what I've just described. http://www.aishack.in/2010/07/tracking-colored-objects-in-opencv/

sue-ling
  • 399
  • 2
  • 11
  • 21
  • Thanks for the suggestion, but Iam not getting to how to write the code to find area of each blob/ contour which has been detected. – Manoj M Apr 20 '12 at 02:09
  • Thanks for the suggestion, but I am not getting to how to write the code to find area of each blob/ contour which has been detected. The code which I have written is in the following link. Can u please correct it and reply. : http://textuploader.com/?p=6&id=YwRl . – Manoj M Apr 20 '12 at 02:16
  • oh! I just forgot , the header and cpp file for cvutility can be found in these links :http://textuploader.com/?p=6&id=Dtnvj http://textuploader.com/?p=6&id=TSlRQ Please include them in source directory and include paths . – Manoj M Apr 20 '12 at 02:28
  • The link is now dead. – sunside Aug 12 '17 at 16:13
0

I believe you can use morphological operators like erode and dilate (read more here)

You need to perform erosion with a kernel size near to the radius of the circle on the right (the one you want to eliminate). followed by dilation using the same kernel to fill the gaps created by the erosion step.

FYI erosion followed by dilation using the same kernel is called opening.

the code will be something like this

int erosion_size = 30; // adjust with you application
Mat erode_element = getStructuringElement( MORPH_ELLIPSE,
                         Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                         Point( erosion_size, erosion_size ) );
erode( binary_img, binary_img, erode_element );
dilate( binary_img, binary_img, erode_element );
Ashraf Saleh
  • 404
  • 1
  • 3
  • 19
0

It is not a fast way but may be usefull in some cases. There is a new function in OpencCV 3.0 - connectedComponentsWithStats. With it we can get area of connected components and eliminate unnecessary. So we can easy remove circle with holes, with the same bounding box as solid circle.

Nick
  • 329
  • 3
  • 12