9

This is example image:

screenshot

and I use opencv to detect contours:

>>> fc = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
>>> contours = fc[0]

For detecting closed contour I thought to check start and end points in each contour returned by opencv, while I noticed that regardless the shape of object opencv seem to outline each object, so I get this result:

>>> for contour in contours:
>>>    print(contour[0,:,:], contour[-1,:,:])
[[246  38]] [[247  38]]
[[92 33]] [[93 33]]

or each found contour has closed path.

I searched for additional constants to available methods in findContour() function, but it seems all return closed paths.

So is there some general way of detecting if found contour is closed?


I googled before asking and didn't got results, but I see good candidate in similar questions at the right side: How can i know if a contour is open or closed in opencv? where it is suggested I use cv2.isContourConvex(contour), but:

>>> for contour in contours:
>>>    print(cv2.isContourConvex(contour))
False
False

yet another update: contourArea looks like it may provide answer (at least for simple contours) but I didn't tested on anything else then above example image:

>>> for contour in contours:
>>>     print(cv2.contourArea(contour))
0.0
12437.5
1
  • I'm not quite sure, but did you try checking convex using the output of convexHull()? like contourhulled=cv2.convexHull(contour); cv2.isContourConvex(contourhulled).
    – Jason
    Commented Dec 5, 2016 at 5:37

4 Answers 4

8

I came across this problem myself and I found a work around...

Going through this..

for i in contours:
   print(cv2.contourArea(i), cv2.arcLength(i,True))

I've noticed that closed contours (e.g. circles) have a higher contourArea than arcLength, whilst open contours (e.g. lines) have a lower contourArea than arcLength, so you can filter them as such...

closed_contours = []
open_contours = []
for i in contours:
    if cv2.contourArea(i) > cv2.arcLength(i, True):
        closed_contours.append(i)
    else:
        open_contours.append(i)

I know this was asked over 3 years ago but for anybody else needing an idea this worked for me!

0
1

If your example image is a bitmap, even a single pixel has an area already, so it also has a contour. The closed circle even has two contours, one on the inside, one on the outside. The half circle has just one, spanning inside and outside and making a U-turn at the ends.

I guess you want to treat these two circles as curves that indeed have no area and just one "contour". The circle would then be a closed curve, the half circle would be open. If that is the case, your new problem is turning a bitmap into curves. This isn't trivial, even though we humans easily perceive the curve there, because it requires defining an algorithm and parameters that turn an area into a curve.

One approach I know is deriving a skeleton from the bitmap, which basically peels off layers of pixels on the outside until you have just a bunch of connected points left. I'm not familiar with opencv, but I could imagine that it already has some utilities for that. Also, searching for "curve line detect opencv" turned up opencv-identifying-lines-and-curves as a first link here, and a bunch of other hits.

0

A closed contour will, by definition, have a separate internal contour.
Look at the hierarchy argument of findContours():

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] , hiearchyi , 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.

3
  • Not exactly, as you can see in my example (cv2.RETR_EXTERNAL) there are no internal contours. Anyhow, if you can deduce a method from documentation you quoted please present it unambiguously, so that we can see your idea in action. Thanks
    – theta
    Commented Jul 5, 2013 at 14:06
  • The contour will never have a repeating point. This is by design. Try dilating your image by a pixel or 2 to avoid 1-pixel thick lines. This should give you an internal contour.
    – Adi Shavit
    Commented Jul 5, 2013 at 14:58
  • What you wrote doesn't seem correct. Regardless dilatation, cv2.RETR_EXTERNAL always returns just external contour, while even if contour lines are 1px wide, other modes will always return both external and internal contours.
    – theta
    Commented Jul 5, 2013 at 16:38
0

This isn't exactly a python answer and probably too late. From my experience with Emgu, any contour with zero area is not closed. You can also compare the area with its perimeter as an extra check, if it's very small then it's most definitely not closed. Irregular shapes sometimes have a tiny little closed area somewhere along its contour.

Contour Area can be obtained from

cvContourArea

Contour Perimeter in Emgu is defined as

cvArcLength(contour, CV_WHOLE_SEQ, 1);

Not the answer you're looking for? Browse other questions tagged or ask your own question.