5

After running my code I get the error message contours tuple must have length 2 or 3, otherwise opencv changed their return signature yet again. I am currently running ver 3.4.3.18 of opencv. The issue occurs when I grab the contours running imutils ver 0.5.2

The code finds the countours and returns the contours found after doing some edge detection. The algorithm then uses imutils to grab the contours. Is this the right way of going about it or is there some up to date way of getting the contours instead of using imutils?

Please see an example below:

image, contours, hier = cv.findContours(edged.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)


cnts = imutils.grab_contours(contours)

cnts = sorted(contours, key = cv.contourArea, reverse = True)[:5]
davidism
  • 121,510
  • 29
  • 395
  • 339
James Phelps
  • 45
  • 1
  • 2

4 Answers4

1

Depending on the OpenCV version, findContours() has varying return signatures.

In OpenCV 3.4.X, findContours() returns 3 items

image, contours, hierarchy = cv.findContours(image, mode, method[, contours[, hierarchy[, offset]]])

In OpenCV 4.1.X, findContours() returns 2 items

contours, hierarchy = cv.findContours(image, mode, method[, contours[, hierarchy[, offset]]])

To manually get contours without using imutils, you can check the amount of items in the returned tuple

items = cv.findContours(edged.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
contours = items[0] if len(items) == 2 else items[1]
nathancy
  • 42,661
  • 14
  • 115
  • 137
0

Do it this way

items = cv.findContours(edged.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(items)

Instead

image, contours, hier = cv.findContours(edged.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(contours)
0

I learned this way from @nathancy in Python/OpenCV. It takes care of both ways.

contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
fmw42
  • 46,825
  • 10
  • 62
  • 80
0

findContours returns a tuple. This tuple contains either 2 values or 3 values, depending on the version of the cv2 you have installed. (as was mentioned by @nathancy)

grab_contours as the name suggest grabs contour value from that tuple, but since you already unpacked your tuple into three variables (image, contours, hier) there is nothing to grab.

In order for this method to work don't unpack your tuple.

cnt = cv.findContours(edged.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

Now you get your return values in one tuple. One of the return values are actually contours. So now you can use your grab_contours method to retrieve contours out of your tuple.

cnts = imutils.grab_contours(cnt)

Now you cnts variable contains your contour values and you can go ahead and sort them.

P.S. If you use PyCharm as your IDE you can look at the source code by selecting the method you want to look at and pressing 'command+B' on the mac. It will help you to understand code better.

I hope it helped. Cheers.