├── .gitignore ├── LICENSE ├── README.md ├── convert_voc_yolo.py ├── creating_playing_cards_dataset.ipynb ├── data ├── .gitignore └── cards.names ├── img ├── convex_hull.jpg ├── ex_generated_image.png ├── gen_2_cards.jpg ├── gen_3_cards.jpg └── measures.png └── test ├── .gitignore ├── 2c.avi ├── extracted_card.png └── scene.png /.gitignore: -------------------------------------------------------------------------------- 1 | dtd-r1.0.1.tar.gz 2 | .ipynb_checkpoints/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 geaxgx 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # playing-card-detection 2 | Generating a dataset of playing cards to train a neural net. 3 | 4 | The notebook **creating_playing_cards_dataset.ipynb** is a guide through the creation of a dataset of playing cards. The cards are labeled with their name (ex: "2s" for "2 of spades", "Kh" for King for hearts) and with the bounding boxes delimiting their printed corners. 5 | 6 | This dataset can be used for the training of a neural net intended to detect/localize playing cards. It was used on the project __[Playing card detection with YOLO v3](https://youtu.be/pnntrewH0xg)__ 7 | 8 | Example of generated image 9 | 10 | -------------------------------------------------------------------------------- /convert_voc_yolo.py: -------------------------------------------------------------------------------- 1 | import xml.etree.ElementTree as ET 2 | import pickle 3 | import os 4 | from os import listdir, getcwd 5 | from os.path import join 6 | import sys 7 | from glob import glob 8 | 9 | 10 | 11 | def convert(size, box): 12 | dw = 1./size[0] 13 | dh = 1./size[1] 14 | x = (box[0] + box[1])/2.0 15 | y = (box[2] + box[3])/2.0 16 | w = box[1] - box[0] 17 | h = box[3] - box[2] 18 | x = x*dw 19 | w = w*dw 20 | y = y*dh 21 | h = h*dh 22 | return (x,y,w,h) 23 | 24 | def convert_annotation(xml_fn): 25 | in_file = open(xml_fn) 26 | txt_fn=xml_fn.replace(".xml",".txt") 27 | out_file = open(txt_fn, 'w') 28 | tree=ET.parse(in_file) 29 | root = tree.getroot() 30 | size = root.find('size') 31 | w = int(size.find('width').text) 32 | h = int(size.find('height').text) 33 | 34 | for obj in root.iter('object'): 35 | difficult = obj.find('difficult').text 36 | cls = obj.find('name').text 37 | if cls not in classes or int(difficult) == 1: 38 | continue 39 | cls_id = classes.index(cls) 40 | xmlbox = obj.find('bndbox') 41 | b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text)) 42 | bb = convert((w,h), b) 43 | #out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n') 44 | out_file.write(f"{cls_id} {bb[0]:0.6f} {bb[1]:0.6f} {bb[2]:0.6f} {bb[3]:0.6f}\n") 45 | #print(f"{txt_fn} created") 46 | in_file.close() 47 | out_file.close() 48 | 49 | if len(sys.argv) != 4: 50 | print(f"Usage: {sys.argv[0]} images_dir classes.names list.txt") 51 | print(f"Ex: {sys.argv[0]} data/cards/train data/cards.names data/train.txt") 52 | print("From xml files in images_dir, convert them in txt files with annotation information and build list.txt file") 53 | sys.exit(1) 54 | images_dir=sys.argv[1] 55 | classes_fn=sys.argv[2] 56 | list_fn=sys.argv[3] 57 | if not os.path.isfile(classes_fn): 58 | print(f"Classes file {classes_fn} is not a file") 59 | sys.exit(1) 60 | if not os.path.isdir(images_dir): 61 | print(f"{images_dir} is not a directory") 62 | sys.exit(1) 63 | with open(classes_fn,"r") as f: 64 | classes=f.read().split("\n") 65 | classes=[c for c in classes if c!=''] 66 | print(classes,len(classes)) 67 | 68 | list_file = open(list_fn,"w") 69 | 70 | for i,xml_fn in enumerate(glob(images_dir+"/*.xml")): 71 | img_fn=xml_fn.replace(".xml",".jpg") 72 | convert_annotation(xml_fn) 73 | list_file.write(f"{img_fn}\n") 74 | if (i+1)%100==0: 75 | print(i+1) 76 | list_file.close() 77 | 78 | 79 | -------------------------------------------------------------------------------- /data/.gitignore: -------------------------------------------------------------------------------- 1 | backgrounds.pck 2 | cards/ 3 | cards.pck 4 | scenes/ 5 | val.txt 6 | video/ 7 | -------------------------------------------------------------------------------- /data/cards.names: -------------------------------------------------------------------------------- 1 | Ah 2 | Kh 3 | Qh 4 | Jh 5 | 10h 6 | 9h 7 | 8h 8 | 7h 9 | 6h 10 | 5h 11 | 4h 12 | 3h 13 | 2h 14 | Ad 15 | Kd 16 | Qd 17 | Jd 18 | 10d 19 | 9d 20 | 8d 21 | 7d 22 | 6d 23 | 5d 24 | 4d 25 | 3d 26 | 2d 27 | Ac 28 | Kc 29 | Qc 30 | Jc 31 | 10c 32 | 9c 33 | 8c 34 | 7c 35 | 6c 36 | 5c 37 | 4c 38 | 3c 39 | 2c 40 | As 41 | Ks 42 | Qs 43 | Js 44 | 10s 45 | 9s 46 | 8s 47 | 7s 48 | 6s 49 | 5s 50 | 4s 51 | 3s 52 | 2s 53 | -------------------------------------------------------------------------------- /img/convex_hull.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geaxgx/playing-card-detection/68c3c15fe4ba71cd4b19212da52992a62fcf952a/img/convex_hull.jpg -------------------------------------------------------------------------------- /img/ex_generated_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geaxgx/playing-card-detection/68c3c15fe4ba71cd4b19212da52992a62fcf952a/img/ex_generated_image.png -------------------------------------------------------------------------------- /img/gen_2_cards.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geaxgx/playing-card-detection/68c3c15fe4ba71cd4b19212da52992a62fcf952a/img/gen_2_cards.jpg -------------------------------------------------------------------------------- /img/gen_3_cards.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geaxgx/playing-card-detection/68c3c15fe4ba71cd4b19212da52992a62fcf952a/img/gen_3_cards.jpg -------------------------------------------------------------------------------- /img/measures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geaxgx/playing-card-detection/68c3c15fe4ba71cd4b19212da52992a62fcf952a/img/measures.png -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | 2c/ 2 | -------------------------------------------------------------------------------- /test/2c.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geaxgx/playing-card-detection/68c3c15fe4ba71cd4b19212da52992a62fcf952a/test/2c.avi -------------------------------------------------------------------------------- /test/extracted_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geaxgx/playing-card-detection/68c3c15fe4ba71cd4b19212da52992a62fcf952a/test/extracted_card.png -------------------------------------------------------------------------------- /test/scene.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geaxgx/playing-card-detection/68c3c15fe4ba71cd4b19212da52992a62fcf952a/test/scene.png --------------------------------------------------------------------------------