Monday, June 18, 2012

Contours - 4 : Ultimate


This is the fourth and final article on Contours. This is the continuation of below articles:

1 - Contours - 1 : Getting Started
2 - Contours - 2 : Brotherhood
3 - Contours - 3 : Extraction

In this article we will deal with PointPolygonTest and Convexity Defects.

1 - PointPolygonTest :

This function finds the shortest distance between a point in the image and a contour. It returns the distance which is negative when point is outside the contour, positive when point is inside and zero if point is on the contour.

For example, we can check the point (50,50) as follows:

dist = cv2.pointPolygonTest(cnt,(50,50),True)

In the function, third argument is " measureDist ". If it is True, it finds the signed distance. If False, it finds only if the point is inside or outside or on the contour.

And if you don't want to find the distance, make sure third argument is False, because, it is a time consuming process. So, making it False gives about 2-3X performance boost.

I have written another article on how to speed up programs using Numpy techniques where I have taken PointPolygonTest as the test case.

Visit : Fast Array Manipulation in Numpy

2 - Convexity Defects :

I have already explained convex hull. Any deviation of the object from this hull can be considered as convexity defect. I have explained it with the help of images in second part of this series. ( Please read it ).

OpenCV comes with a ready-made function for this, cv2.convexityDefects(). Let's see how we can use it.

hull = cv2.convexHull(cnt,returnPoints = False)
defects = cv2.convexityDefects(cnt,hull)

Notice that "returnPoints = False" in first line to get indices of the contour points, because input to convexityDefects() should be these indices, not original points.

It returns a defects structure, an array of four values - [ start point, end point, farthest point, approximate distance to farthest point ]

We can visualize it using an image. We draw a line joining start point and end point, then draw a circle at the farthest point.

Now we take each row of the defects, then from that draw, extract four values, draw line using first two values, then draw the point using third value. Remember first three values returned are indices of cnt. So we have to bring those values from cnt.

for i in range(defects.shape[0]):
    s,e,f,d = defects[i,0]
    start = tuple(cnt[s][0])
    end = tuple(cnt[e][0])
    far = tuple(cnt[f][0])

And below are the various results :

So these are two functions I wanted to discuss. With this article, series on Contours is over.

I would like to hear your feedback, comments, suggestions etc.

With Regards,


  1. Which version of opencv are you using? I can't find cv2.convexityDefects (ubuntu 12.04+python 2.7+opencv 2.3.1).

    Thanks for your tutorials.

    1. Most Welcome. I am using OpenCV 2.4.1 (which was latest when I wrote this tutorial). But now, 2.4.2 is released. But I think in Ubuntu, still repo uses 2.3.1.

      Since my Ubuntu is 64-bit, i have some problem with the Python bindings, which is supposed to support only 32-bit python. So at present, I use it in Windows only.

    2. Thank you,
      I can test your examples now with OpenCV 2.4.2. I am a bit surprised by the behaviour of convexityDefects(), the function detects points very close to the convex hull (, would you have an idea to fix this?

    3. Hi,

      If I understood your question correctly, you want to avoid detecting very close defects. Well, it can't be shutdown inside the function, but when you mark the convexity defects on your image, you can put a constraint that distance to farthest point should be more than a minimum threshold value, Otherwise neglect that point or remove it from the set of defect points.

    4. ok, I'll try that. thank you.

  2. Abid,

    your tutorial helped me a lot! :)
    Thx for your effort!