marco
marco

Reputation: 975

How can I extract internal contours (holes) with python opencv?

is there an easy and direct way to extract the internal contours (holes) from an image using opencv 3.1 python ?

I know that I can use "area" as a condition. However, if I change the image resolution, the "areas" are not the same.

For instance, with this image: enter image description here How can I extract the internal holes?

_, contours, hier_ = cv2.findContours(img,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE)
areas = [cv2.contourArea(c) for c in millCnts]
max_area = np.max(areas)
Mask = np.ones(img.shape[:2], dtype="uint8") * 255

   # I can do something like this (currently not working, just to show an example)
for c in contours:
    if(( cv2.contourArea(c) > 8) and (cv2.contourArea(c)< 100000)):
        cv2.drawContours(Mask ,[c],-1,0,1)

Upvotes: 2

Views: 11806

Answers (1)

api55
api55

Reputation: 11420

As I explained in my comment, you have to check the hierarchy return variable. After find contours you will get the contours (List of List of Points) and hierarchy (List of List).

The documentation is very clear in this:

hierarchy – Optional output vector, containing information about the image topology. It has as many elements as the number of contours. For each i-th contour contours[i] , the elements hierarchy[i][0] , hiearchy[i][1] , hiearchy[i][2] , and hiearchy[i][3] are set to 0-based indices in contours of the next and previous contours at the same hierarchical level, the first child contour and the parent contour, respectively. If for the contour i there are no next, previous, parent, or nested contours, the corresponding elements of hierarchy[i] will be negative.

So, this means that for each countour[i] you should get a hierarchy[i] that contains a List with 4 variables:

  • hierarchy[i][0]: the index of the next contour of the same level
  • hierarchy[i][1]: the index of the previous contour of the same level
  • hierarchy[i][2]: the index of the first child
  • hierarchy[i][3]: the index of the parent

So, saying that, in your case, there should be one without a parent, and you can check which one by checking the hierarchy[i][3] if it is negative.

It should be something like (untested code):

holes = [contours[i] for i in range(len(contours)) if hierarchy[i][3] >= 0]

* UPDATE:*

To summarize what we discussed in the chat,

  • The image was too big, and the contours had small holes: solved with dilate and erode with a kernel of size 75
  • The image needed to be inverted since OpenCV expects for dilate a black background
  • The algorithm was giving 2 big contours, one outside (as expected) and one inside (almost the same as the outside one), this is probably due to the image having some external (and closed) bumps. This was solved by removing the contour without a parent and its first child.

Upvotes: 7

Related Questions