Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
dofire committed Dec 21, 2023
0 parents commit fae1069
Show file tree
Hide file tree
Showing 55 changed files with 817 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
main.ipynb filter=lfs diff=lfs merge=lfs -text

assets/** filter=lfs diff=lfs merge=lfs -text
test/** filter=lfs diff=lfs merge=lfs -text
imgs/** filter=lfs diff=lfs merge=lfs -text

*.h5 filter=lfs diff=lfs merge=lfs -text
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
__pycache__/

.idea
temp/
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Playing Card Detection

The user simply puts the card on a flat surface, and the program will
- threshold the image
- find the card
- isolate the corners
- split it into rank and suit
- compare with the stored rank/suit images and then return the result

It can identify as many cards as can fit on a frame, and different sets of decks can be used too

### Used Packages
- `Python 3.11.5` (newer versions may or may not work)
- `opencv`
- `numpy`
- `matplotlib`



### References
- [EdjeElectronics/OpenCV-Playing-Card-Detector](https://github.com/EdjeElectronics/OpenCV-Playing-Card-Detector)
- [dharm1k987/Card_Recognizer](https://github.com/dharm1k987/Card_Recognizer)
- [youtube](https://www.youtube.com/watch?v=s2jYdsjWirs)

3 changes: 3 additions & 0 deletions imgs/ranks/10.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/ranks/2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/ranks/3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/ranks/4.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/ranks/5.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/ranks/6.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/ranks/7.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/ranks/8.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/ranks/9.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/ranks/A.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/ranks/J.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/ranks/K.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/ranks/Q.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/suits/Clubs.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/suits/Diamonds.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/suits/Hearts.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions imgs/suits/Spades.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions main.ipynb
Git LFS file not shown
110 changes: 110 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import time

import cv2
import numpy as np

from processing import process
from utils import display
from utils.Loader import Loader

frameWidth = 640
frameHeight = 480

debug = True

# url = 'https://192.168.1.173:8080'

# change to 1 if using USB webcam
cap = cv2.VideoCapture("test/vid4.mp4")
# cap = cv2.VideoCapture(url + "/video")
frame_rate = 30

cap.set(3, frameWidth) # width is id number 3
cap.set(4, frameHeight) # height is id 4
cap.set(10, 150) # change brightness to 150

flatten_card_set = []

prev = 0

train_ranks = Loader.load_ranks('imgs/ranks')
train_suits = Loader.load_suits('imgs/suits')

black_img = np.zeros((300, 200))

while True:
time_elapsed = time.time() - prev

success, img = cap.read()

if time_elapsed > 1. / frame_rate:
prev = time.time()

imgResult = img.copy()
imgResult2 = img.copy()

thresh = process.get_thresh(img)
four_corners_set = process.find_corners_set(thresh, imgResult, draw=True)
flatten_card_set = process.find_flatten_cards(imgResult2, four_corners_set)
cropped_images = process.get_corner_snip(flatten_card_set)

if debug:
if len(flatten_card_set) <= 0:
cv2.imshow('flat', black_img)

for flat in flatten_card_set:
cv2.imshow('flat', flat)

ranksuit_list: list = list()

if debug and len(cropped_images) <= 0:
cv2.imshow("crop", black_img)
cv2.imshow("rank-suit", black_img)

for i, (img, original) in enumerate(cropped_images):

if debug:
hori = np.concatenate((img, original), axis=1)
cv2.imshow("crop", hori)

drawable = img.copy()
original_copy = original.copy()

ranksuit = process.split_rank_suit(drawable, original_copy, debug=debug)

ranksuit_list.append(ranksuit)

try:
for rank, suit in ranksuit_list:
rank = cv2.resize(rank, (70, 100), 0, 0)
suit = cv2.resize(suit, (70, 100), 0, 0)
if debug:
h = np.concatenate((rank, suit), axis=1)
cv2.imshow("rank-suit", h)
except:
cv2.imshow("rank-suit", black_img)

rs = list[str]()

for _rank, _suit in ranksuit_list:
predict_rank, predict_suit = process.template_matching(_rank, _suit, train_ranks, train_suits)
prediction = f"{predict_rank} {predict_suit}"
rs.append(prediction)
print(prediction)

process.show_text(
predictions=rs,
four_corners_set=four_corners_set,
img=imgResult
)

# show the overall image
time.sleep(0.05)
cv2.imshow('Result', display.stack_images(0.55, [imgResult, thresh]))

wait = cv2.waitKey(1)
if wait & 0xFF == ord('q'):
break

cv2.destroyAllWindows()
cap.release()
84 changes: 84 additions & 0 deletions processing/Augment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import cv2
import numpy as np
from scipy.ndimage import zoom


class Augment:

@staticmethod
def brightness_img(img, value):
# convert to HSV
bgr = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
hsv = cv2.cvtColor(bgr, cv2.COLOR_BGR2HSV)

# add the value in the value channel
h, s, v = cv2.split(hsv)
v = cv2.add(v, value)
v[v > 255] = 255
v[v < 0] = 0

# convert image back to gray
final_hsv = cv2.merge((h, s, v))
img = cv2.cvtColor(final_hsv, cv2.COLOR_HSV2BGR)
return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

@staticmethod
def contrast(img, value):
brightness = 30
shadow = brightness
highlight = 255

# add the brightness
alpha_b = (highlight - shadow) / 255
gamma_b = shadow
img = cv2.addWeighted(img, alpha_b, img, 0, gamma_b)

# add the constrast
f = 131 * (value + 127) / (127 * (131 - value))
alpha_c = f
gamma_c = 127 * (1 - f)
img = cv2.addWeighted(img, alpha_c, img, 0, gamma_c)

return img

@staticmethod
def zoom_img(img, zoom_factor):
# https://stackoverflow.com/questions/37119071/scipy-rotate-and-zoom-an-image-without-changing-its-dimensions
h, w = img.shape[:2]
zoom_tuple = (zoom_factor,) * 2 + (1,) * (img.ndim - 2)
zh = int(np.round(h / zoom_factor))
zw = int(np.round(w / zoom_factor))
top = (h - zh) // 2
left = (w - zw) // 2

out = zoom(img[top:top + zh, left:left + zw], zoom_tuple)

# `out` might still be slightly larger than `img` due to rounding, so
# trim off any extra pixels at the edges
trim_top = ((out.shape[0] - h) // 2)
trim_left = ((out.shape[1] - w) // 2)
out = out[trim_top:trim_top + h, trim_left:trim_left + w]

return out

@staticmethod
def horizontal_flip(img):
return np.fliplr(img)

@staticmethod
def noise_img(img):
gaussian = np.random.normal(0, 20, (img.shape[0], img.shape[1]))
return img + gaussian

@staticmethod
def blur_image(img):
return cv2.GaussianBlur(img, (11, 11), 0)

@staticmethod
def rotation(img, angle):
# rotate image about its center
image_center = tuple(np.array(img.shape[1::-1]) / 2)
rot_mat = cv2.getRotationMatrix2D(image_center, angle, 1.0)
result = cv2.warpAffine(img, rot_mat, img.shape[1::-1], flags=cv2.INTER_LINEAR)
result = Augment.zoom_img(result, 1.2)
return result
12 changes: 12 additions & 0 deletions processing/ColorHelper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import cv2


class ColorHelper:

@staticmethod
def gray2bin(img):
return cv2.threshold(img, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]

@staticmethod
def reverse(img):
return cv2.bitwise_not(img)
Loading

0 comments on commit fae1069

Please sign in to comment.