Skip to content

Instantly share code, notes, and snippets.

@Lokno
Created September 27, 2024 21:36
Show Gist options
  • Save Lokno/c0b36f8b97b78f4a9932d91901d96d07 to your computer and use it in GitHub Desktop.
Save Lokno/c0b36f8b97b78f4a9932d91901d96d07 to your computer and use it in GitHub Desktop.
Python to detect the rank and value of a playing card
# Author: Lokno Ketchup
# Description : Script to detect the rank and value of a playing card
# using OpenCV 2.4.12 template matching. User must provide
# a local directory "templates" with cropped PNG files
# of each rank and suit, labeled using the keys in
# dictionaries 'ranks' and 'suits' below. For example,
# the image for the ace rank template will be A.png
#
# Rotation, distance, and perspective are not accounted for,
# so the templates must match roughly what the camera will
# capture.
import sys
import cv2
import numpy as np
# script expects a folder 'templates' with PNGs labeled with the keys of these dictionaries
ranks = { 'A' : None, '2' : None, '3' : None, '4' : None, '5' : None, '6' : None,
'7' : None, '8' : None, '9' : None, '10' : None, 'J' : None, 'Q' : None, 'K' : None }
suits = { 'D' : None, 'S' : None, 'C' : None, 'H' : None }
# translates shorthand for labels to display
suitsFull = { 'D' : 'Diamonds', 'S' : 'Spades', 'C' : 'Clubs', 'H' : 'Hearts' }
valuesFull = { 'A' : 'Ace', '2' : '2', '3' : '3', '4' : '4', '5' : '5', '6' : '6',
'7' : '7', '8' : '8', '9' : '9', '10' : '10',
'J' : 'Jack', 'Q' : 'Queen', 'K' : 'King' }
# checks an image against a template and check for best match
def checkTemplate(img, template, method, idx, bestIdx, bestVal):
res = cv2.matchTemplate(img,template,method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
if bestVal < max_val:
bestVal = max_val
bestIdx = idx
return bestVal,bestIdx
# determine the suit and rank of a playing card in img, using method
# and requiring a minimum value of at least threshold
def determine( img, method, threshold = 0.8 ):
bestRank = 0
bestSuit = 0
rankValue = 0
suitValue = 0
# determine rank
c = 0
for t in ranks.keys():
rankValue,bestRank = checkTemplate(img, ranks[t], method, c, bestRank, rankValue)
c += 1
# determine suit
c = 0
for t in suits.keys():
suitValue,bestSuit = checkTemplate(img, suits[t], method, c, bestSuit, suitValue)
c += 1
ret = ''
if suitValue > threshold and rankValue > threshold:
ret = '%s of %s' % (valuesFull[ranks.keys()[bestRank]], suitsFull[suits.keys()[bestSuit]])
else:
ret = 'Cannot Read Card'
return ret
# load template images
for t in ranks.keys():
ranks[t] = cv2.imread('templates/' + t + '.png',0)
if ranks[t] == None:
print 'ERROR : Could not load template images'
sys.exit(-1)
for t in suits.keys():
suits[t] = cv2.imread('templates/' + t + '.png',0)
if suits[t] == None:
print 'ERROR'
# The method I used because it worked best in my case
method = cv2.TM_CCOEFF_NORMED
font = cv2.FONT_HERSHEY_SIMPLEX
# Main Loop
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
# get grayscale image
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# resize to half size (640x400 on test camera)
img = cv2.resize(gray,None,fx=0.5, fy=0.5, interpolation = cv2.INTER_AREA)
# process card
cardID = determine( img, method )
# add result to image for display
cv2.putText(img,cardID,
(200,30), # postion of text in image
font, 1, (255,255,255),2)
# Display the resulting frame
cv2.imshow('Template Matching',img)
# quits on escape (in window focus)
if cv2.waitKey(1) & 0xFF == 27:
break
cv2.destroyAllWindows()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment