'OpenCV version 4.1.0 drawContours error: (-215:Assertion failed) npoints > 0 in function 'drawContours'

I have the following code that worked well with OpenCV 3.4.1 and now is not working with OpenCV 4.1.0 and gives an error. I do not know how to adapt the code with the newer version, can you help me with that? Thanks a lot

def ImageProcessing(image):
    image = cv2.absdiff(image, background)
    h, gray = cv2.threshold(image, 65, 255, cv2.THRESH_BINARY_INV);
    gray = cv2.medianBlur(gray,5)

    kernel = np.ones((3,3), np.uint8)

    gray = cv2.erode(gray, kernel, iterations=1)#1

    des = cv2.bitwise_not(gray)
    tmp = cv2.findContours(des,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE)
    contour, hier = tmp[1], tmp[0]

    for cnt in contour:
        cv2.drawContours(des,[cnt],0,255,-1)

    gray = cv2.bitwise_not(des)

    gray = cv2.dilate(gray, kernel, iterations=1)#1

    return gray

The error is

cv2.error: OpenCV(4.1.0) /io/opencv/modules/imgproc/src/drawing.cpp:2509: error: (-215:Assertion failed) npoints > 0 in function 'drawContours'



Solution 1:[1]

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

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

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

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

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

You can easily obtain the contours regardless of the version like this:

cnts = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

Since the last two values are always the same, we can further condense it into a single line using [-2:] to extract the contours from the tuple returned by cv2.findContours()

cnts, _ = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2:]

Solution 2:[2]

The following snippet will work irrespective of the OpenCV version installed in your system/environment and will also store all the tuples in individual variables.

First, get the version of OpenCV installed (we don't want the entire version just the major number either 3 or 4) :

import cv2
version = cv2.__version__[0]

Based on the version either of the following two statements will be executed and the corresponding variables will be populated:

if version == str(4):
    contours, hierarchy = cv2.findContours(binary_img, cv2.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

elif version == str(3):
    im, contours, hierarchy = cv2.findContours(binary_img, cv2.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

The contours returned from the function in either scenarios will be stored in contours.

Note: the above snippet is written assuming either version 3 or 4 of OpenCV is installed. For older versions, please refer to the documentation or update to the latest.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2