forked from dofire/OpenCV-Playing-Card-Detection
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit fae1069
Showing
55 changed files
with
817 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
__pycache__/ | ||
|
||
.idea | ||
temp/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Git LFS file not shown
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
Oops, something went wrong.