4

I need to retrieve the outermost contour of several silhouettes, possibly storing the contour coordinates in a clockwise or counterclockwise order. From what I've read, this kind of result can be archived by using OpenCV's Canny + findContours. Unfortunately, the majority of silhouettes I have to elaborate has jagged edges or holes, therefore, the "standard procedure" is not working properly. For instance, if my image is quite simple and without holes, the result is exactly as I want it (just the outermost contour and ordered coordinates): Cup example

In case of pictures with holes, I get a segmented outermost contour (different colours , see attached pictures) and it still displays the inner holes in the final image. I get the worst results with jagged edges. The holes are displayed and the contour is highly segmented (Cat). Holes and jagged edges

Code:

//add a small padding. Otherwise, in case of images where the border  is partially cut out it won't be considered as a "closed" contour
int topbottom = (int) (0.05*image.rows);
int rightleft = (int) (0.05*image.cols);
copyMakeBorder( image, image, topbottom, topbottom, rightleft, rightleft, BORDER_CONSTANT);

//consider only alpha channel to create a silhouette
Mat silhouette;
vector<Mat> ch;
split(image, ch);

Canny(ch[3], silhouette, 100, 200);

vector<vector<Point>> contours;
vector<Vec4i> hierarchy;

//find only the external contour
findContours( silhouette, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

RNG rng(12345);
Mat drawing = Mat::zeros(silhouette.size(), CV_8UC3);
for(int i = 0; i < contours.size(); i++)
{
    Scalar colour = Scalar(rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255));
    drawContours(drawing, contours, i, colour, 1, 8, hierarchy, 0, Point());
}

Is there a way to avoid segmentation and remove the contours of the holes?

Dainius Šaltenis
  • 1,264
  • 13
  • 27
Izzy88
  • 93
  • 8
  • 3
    Can you post please only the image that you want to get the contour from without the extra images of the contour result. – Amitay Nachmani Aug 01 '16 at 12:37
  • Sure! These are some of them [First sample pic (Bed)](http://labelmaterial.s3.amazonaws.com/shapes/2KGnQ5RjIoXZXmoXr723dXz.png) [Second sample pic (Cat)](http://labelmaterial.s3.amazonaws.com/shapes/2NXvn0zPaDGXLIoQJ9LuyVT.png) – Izzy88 Aug 01 '16 at 13:03
  • You have got good threshold image(2nd image in Holes and jagged edges).Now just find biggest contour from all contours and draw it.You will get only one outer side contour which you want. – Sagar Patel Aug 01 '16 at 13:29
  • @Sagar Patel in both pics the different colours of the final segments represent all the different segments derived from _findContours_ . Accordingly, especially if you consider the Cat example, the biggest contour (the bone shaped collar) does not always concide with the outer contour :( – Izzy88 Aug 01 '16 at 13:49
  • 1
    Why do you use canny edge? just segment the image 255 for areas that are part of the object and 0 otherwise and than use findContours( silhouette, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); – Amitay Nachmani Aug 01 '16 at 14:32
  • @AmitayNachmani thank you so much!!!!! It works perfectly without using Canny edge detection. I thought it could have helped improving the final result but apparently I was wrong, it was useless in this case. Thank you agan! – Izzy88 Aug 01 '16 at 14:44

1 Answers1

1

OpenCV has a function called cv2.contourArea(), which allows you to count the area of the input contour. If you have more than one contour, use this function to find areas of all your contours and delete all except the largest contour (one with largest area, because contours inside that large contour will not have larger area). After that you will have only the largest outer contour left.

Dainius Šaltenis
  • 1,264
  • 13
  • 27