The problem is only in visualization: drawContours expects an array (a list in the case of python) of contours, and not just a single numpy array (which is returned from approxPolyDP ).
The solution is as follows: replacement
cv2.drawContours(canvas, approx, -1, (0, 0, 255), 3)
to
cv2.drawContours(canvas, [approx], -1, (0, 0, 255), 3)
source share