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]