Giter VIP home page Giter VIP logo

opencv-playing-card-detector's Introduction

OpenCV-Playing-Card-Detector

This is a Python program that uses OpenCV to detect and identify playing cards from a PiCamera video feed on a Raspberry Pi. Check out the YouTube video that describes what it does and how it works:

https://www.youtube.com/watch?v=m-QPjO-2IkA

Usage

Download this repository to a directory and run CardDetector.py from that directory. Cards need to be placed on a dark background for the detector to work. Press 'q' to end the program.

The program was originally designed to run on a Raspberry Pi with a Linux OS, but it can also be run on Windows 7/8/10. To run on Windows, download and install Anaconda (https://www.anaconda.com/download/, Python 3.6 version), launch Anaconda Prompt, and execute the program by launching IDLE (type "idle" and press ENTER in the prompt) and opening/running the CardDetector.py file in IDLE. The Anaconda environment comes with the opencv and numpy packages installed, so you don't need to install those yourself. If you are running this on Windows, you will also need to change the program to use a USB camera, as described below.

The program allows you to use either a PiCamera or a USB camera. If using a USB camera, change line 38 in CardDetector.py to:

videostream = VideoStream.VideoStream((IM_WIDTH,IM_HEIGHT),FRAME_RATE,2,0).start()

The card detector will work best if you use isolated rank and suit images generated from your own cards. To do this, run Rank_Suit_Isolator.py to take pictures of your cards. It will ask you to take a picture of an Ace, then a Two, and so on. Then, it will ask you to take a picture of one card from each of the suits (Spades, Diamonds, Clubs, Hearts). As you take pictures of the cards, the script will automatically isolate the rank or suit and save them in the Card_Imgs directory (overwriting the existing images).

Files

CardDetector.py contains the main script

Cards.py has classes and functions that are used by CardDetector.py

PiVideoStream.py creates a video stream from the PiCamera, and is used by CardDetector.py

Rank_Suit_Isolator.py is a standalone script that can be used to isolate the rank and suit from a set of cards to create train images

Card_Imgs contains all the train images of the card ranks and suits

Dependencies

Python 3.6

OpenCV-Python 3.2.0 and numpy 1.8.2: See https://www.pyimagesearch.com/2016/04/18/install-guide-raspberry-pi-3-raspbian-jessie-opencv-3/ for how to build and install OpenCV-Python on the Raspberry Pi

picamera library:

sudo apt-get update
sudo apt-get install python-picamera python3-picamera

opencv-playing-card-detector's People

Contributors

edjeelectronics avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

opencv-playing-card-detector's Issues

I need help. But firstly, thank you for your program.

So I have a homework that has to detect something with openCV. And I'm interested in your study.
I've followed the instructions that you made to detect cards. After messing around with errors. I successfully detected cards. But there's a problem for me:
Not all the time I show the card it can be detected. In your video, you need a dark background. But I'm using my laptop's cam so I just show the cards in front of it. When the lights on my room's off, the program's working just fine. But when I turn on the lights (maybe my background's lighter?), it cannot detect contours and identify cards.
What should I do to make it work all the time?
Thank you for reading. Hope you can help me out!

C# Version Using EmguCV

Hello, it's possible to provide a C# version using EmguCV ?
because i found hard to convert some Python libs like 'numpy' in C#, but 'cv2' it's easy.

Error

[
OpenCV Error: Sizes of input arguments do not match (The operation is neither 'array op array' (where arrays have the same size and the same number of channels), nor 'array op scalar', nor 'scalar op array') in cv::arithm_op, file C:\projects\opencv-python\opencv\modules\core\src\arithm.cpp, line 659
Traceback (most recent call last):
File "C:/Users/Haziq/PycharmProjects/CardDetector/CardDetector.py", line 86, in '<'module'>'
k].suit_diff = Cards.match_card(cards[k], train_ranks, train_suits)
File "D:\OpenCV-Playing-Card-Detector-master\Cards.py", line 260, in match_card
diff_img = cv2.absdiff(qCard.rank_img, Trank.img)
cv2.error: C:\projects\opencv-python\opencv\modules\core\src\arithm.cpp:659: error: (-209) The operation is neither 'array op array' (where arrays have the same size and the same number of channels), nor 'array op scalar', nor 'scalar op array' in function cv::arithm_op
]
I got the error above when a card enter the camera's sight and immediately closed.
p/s= Remove the " ' " from the module.
Thanks in advance.

Detect card by card edge only

HI,
Is it possible to make it read the card value based on the edge only(Not the whole card image).

Screen Shot 2019-03-26 at 9 40 08 AM
Please give me some guidance on this.
Thanks

"findContours" and "LINE_AA" error

This project is so cool.
I tried to run the project on my Mac, it gives error in findContours and LINE_AA syntax. I delete the "dummy" and change LINE_AA to CV_AA, the program finally works. But when it recognize any card, it will putText "Unknow of Unknow" on the card. I am learning C++ not Python, so I don't know how this happens. Can anyone help?

ValueError: need more than 2 values to unpack

Traceback (most recent call last):
    File "CardDetector.py", line 66, in <module>
        cnts_sort, cnt_is_card = Cards.find_cards(pre_proc)
    File "/home/ismail/Documents/OpenCV-Playing-Card-Detector/Cards.py", line 135, in find_cards
        dummy,cnts,hier = cv2.findContours(thresh_image,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
ValueError: need more than 2 values to unpack

run with screen streaming as input (mss())

Hi.
I love your thing
I'm just learning python, i tried to set an mss stream as input.
I couldnt get the Rank_suit_detector properly, so i make it run with a folder of png file, that gave me a correct Cards-img folder...
But When i run CardDetector, i get only Unknown of Unknown, and i have to zoom in the card to have some response (but totally inacurate)...
Do you know what i'm struggling with ...?
here the modified rankSuitIsolator

### Takes a card picture and creates a top-down 200x300 flattened image
### of it. Isolates the suit and rank and saves the isolated images.
### Runs through A - K ranks and then the 4 suits.

# Import necessary packages
import cv2
import numpy as np
import time
import Cards
import os
``

from mss import mss
from PIL import Image
mon = {'top': 160, 'left': 160, 'width': 600, 'height': 600}
sct = mss()

imagepath=[
"image/S01.png","image/S01.png","image/S03.png","image/S04.png","image/S05.png","image/S06.png","image/S07.png","image/S08.png","image/S09.png","image/S10.png","image/S11.png","image/S12.png","image/S13.png",
"image/S01.png","image/D05.png",
"image/C04.png","image/H01.png"]
img_path = os.path.dirname(os.path.abspath(__file__)) + '/Card_Imgs/'
IM_WIDTH = 1280;IM_HEIGHT = 720;RANK_WIDTH = 70;RANK_HEIGHT = 125;SUIT_WIDTH = 70;SUIT_HEIGHT = 100

# If using a USB Camera instead of a PiCamera, change PiOrUSB to 2
PiOrUSB = 2

# Use counter variable to switch from isolating Rank to isolating Suit
i = 1

for image in imagepath:
    filename = image
    image = Image.open(image)
    image = np.array(image)
    # print(image)
    # Pre-process image
    gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray,(5,5),0)
    retval, thresh = cv2.threshold(blur,100,255,cv2.THRESH_BINARY)

    # Find contours and sort them by size
    dummy,cnts,hier = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    cnts = sorted(cnts, key=cv2.contourArea,reverse=True)

    # Assume largest contour is the card. If there are no contours, print an error
    flag = 0
    image2 = image.copy()

    if len(cnts) == 0:
        print('No contours found!')
        quit()

    card = cnts[0]

    # Approximate the corner points of the card
    peri = cv2.arcLength(card,True)
    approx = cv2.approxPolyDP(card,0.01*peri,True)
    pts = np.float32(approx)

    x,y,w,h = cv2.boundingRect(card)

    # Flatten the card and convert it to 200x300
    warp = Cards.flattener(image,pts,w,h)

    # Grab corner of card image, zoom, and threshold
    corner = warp[0:84, 0:32]
    # corner_gray = cv2.cvtColor(corner,cv2.COLOR_BGR2GRAY)
    corner_zoom = cv2.resize(corner, (0,0), fx=4, fy=4)
    corner_blur = cv2.GaussianBlur(corner_zoom,(5,5),0)
    retval, corner_thresh = cv2.threshold(corner_blur, 155, 255, cv2. THRESH_BINARY_INV)

    # Isolate suit or rank
    if i <= 13: # Isolate rank
        rank = corner_thresh[20:185, 0:128] # Grabs portion of image that shows rank
        dummy, rank_cnts, hier = cv2.findContours(rank, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
        rank_cnts = sorted(rank_cnts, key=cv2.contourArea,reverse=True)
        x,y,w,h = cv2.boundingRect(rank_cnts[0])
        rank_roi = rank[y:y+h, x:x+w]
        rank_sized = cv2.resize(rank_roi, (RANK_WIDTH, RANK_HEIGHT), 0, 0)
        final_img = rank_sized

    if i > 13: # Isolate suit
        suit = corner_thresh[186:336, 0:128] # Grabs portion of image that shows suit
        dummy, suit_cnts, hier = cv2.findContours(suit, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
        suit_cnts = sorted(suit_cnts, key=cv2.contourArea,reverse=True)
        x,y,w,h = cv2.boundingRect(suit_cnts[0])
        suit_roi = suit[y:y+h, x:x+w]
        suit_sized = cv2.resize(suit_roi, (SUIT_WIDTH, SUIT_HEIGHT), 0, 0)
        final_img = suit_sized

    cv2.imshow("Image",final_img)

    # Save image
    print('Press "c" to continue.')
    key = cv2.waitKey(0) & 0xFF
    if key == ord('c'):
        cv2.imwrite(img_path+filename,final_img)

    i = i + 1

cv2.destroyAllWindows()

Not enough values to unpack error?

Traceback (most recent call last):
File "E:\OpenCV-Playing-Card-Detector-master\CardDetector.py", line 66, in
cnts_sort, cnt_is_card = Cards.find_cards(pre_proc)
File "E:\OpenCV-Playing-Card-Detector-master\Cards.py", line 135, in find_cards
dummy,cnts,hier = cv2.findContours(thresh_image,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
ValueError: not enough values to unpack (expected 3, got 2)

Variable error in preprocess_card() of Cards.py

def preprocess_image(image):
    img_w, img_h = np.shape(image)[:2]
    return thresh

should be change to

def preprocess_image(image): 
    img_h, img_w = np.shape(image)[:2]
    return thresh

np.shape() will actually return height than width

This is pretty cool man

So I'm not so hot with python, but would it be possible to use an "if" statement while the image is being compared to the training images to assign the cards "count value" in a string? then later "print" the sum of that string? I know this is your end goal but i just thought i would ask. And thanks this is an awesome project and i'm working on it tonight!

Use Screenshot as input => Readjust size value in findCards function

Hi there,

I wanted to try this on a screenshot, being succesfull just to decission of cards, my size value of my contours has about 355 and the minimum size is above 25000 I guess.

What do I need to readjust here? have i missed some scaling?

for i in range(len(cnts_sort)):
size = cv2.contourArea(cnts_sort[i]) // has size of 300 and min size is 25000
peri = cv2.arcLength(cnts_sort[i],True)
approx = cv2.approxPolyDP(cnts_sort[i],0.01*peri,True)

Licence

Hi,
which software licence is this project offered under?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.