Skip to content
Advertisement

Filter contour area with smaller area

I would like to filter out cnts with small area. But I got the an error. What is the proper way to use filter?

code

def drawCnts(img, cnts):
    cnts = filter(lambda cnt: cv2.contourArea(cnt)> 400, cnts) # adding this line gets error
    cv2.drawContours(img, cnts, -1, (0, 255, 0), 3)
    imshow(img)
import imUtils
import configure as cfg
import cv2

folder = 'test_images/'
img = imUtils.imread(folder + '1.cr3')
gray = cv2.cvtColor(imUtils.toOpenCVU8(img.copy()), cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(gray,255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV,27,9)
# apply close morphology
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
imUtils.imshow(thresh, 'thresh')

(cnts, _) = cv2.findContours(thresh.copy(),
                                cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
imUtils.drawCnts(img.copy(), cnts)

error

cv2.drawContours(img, cnts, -1, (0, 255, 0), 3)
cv2.error: OpenCV(4.6.0) :-1: error: (-5:Bad argument) in function 'drawContours'
> Overload resolution failed:
>  - Can't parse 'contours'. Input argument doesn't provide sequence protocol
>  - Can't parse 'contours'. Input argument doesn't provide sequence protocol

Advertisement

Answer

The filter function returns a generator but the drawContours function expects a list. To fix this, use the list command.

cnts = list(filter(lambda cnt: cv2.contourArea(cnt)> 400, cnts))

Another solution is to use a list comprehension to build the list, like this:

[cnt for cnt in cnts if cv2.contourArea(cnt) > 400]
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement