I have a Pi camera pointed at a card on a white background. However, local shadows seem to be preventing the closing of the contours that I use for card detection, which means detection fails overall. Here's a screenshot of what I mean:
You can see it gets ragged around the bottom corners in particular. This is the code I'm using to get this far:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.blur(gray, (5,5))
gray = cv2.bilateralFilter(gray, 11, 17, 17) #blur. very CPU intensive.
cv2.imshow("Gray map", gray)
edges = cv2.Canny(gray, 30, 120)
cv2.imshow("Edge map", edges)
#find contours in the edged image, keep only the largest
# ones, and initialize our screen contour
# use RETR_EXTERNAL since we know the largest (external) contour will be the card edge.
_, cnts, _ = cv2.findContours(edges.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:1]
screenCnt = None
# loop over our contours
for c in cnts:
# approximate the contour
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.3 * peri, True)
cv2.drawContours(image, [cnts[0]], -1, (0, 255, 0), 2)
# if our approximated contour has four points, then
# we can assume that we have found our card
if len(approx) == 4:
screenCnt = approx;
break
Is there a way to force it to close specific contours? If I blur the image more to smooth the shadows that doesn't work either since it simply ignores those corners as not having an edge. It's annoying that it's merely a few pixels away from closing the contours, yet it never does...
edit: I now have a more realistic setup where the background is a beige colour and with a lot more shadows interfering. Beige is necessary because there are some cards with white borders, so white wouldn't work. The edge detection fails mostly in the left side where the shadows are.