Spaces:
Sleeping
Sleeping
Upload 9 files
Browse files- Dockerfile +25 -0
- app.py +80 -0
- cards_classification.pkl +3 -0
- requirements.txt +197 -0
- test_images/ace_of_diamonds.jpg +0 -0
- test_images/ace_of_spades.jpg +0 -0
- test_images/jack_of_spades.jpg +0 -0
- test_images/king_of_diamonds.jpg +0 -0
- test_images/three_of_hearts.jpg +0 -0
Dockerfile
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.12.3
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
COPY ./requirements.txt /app/requirements.txt
|
| 6 |
+
|
| 7 |
+
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
|
| 8 |
+
|
| 9 |
+
# Set up a new user named "user" with user ID 1000
|
| 10 |
+
RUN useradd -m -u 1000 user
|
| 11 |
+
|
| 12 |
+
# Switch to the "user" user
|
| 13 |
+
USER user
|
| 14 |
+
|
| 15 |
+
# Set home to the user's home directory
|
| 16 |
+
ENV HOME=/home/user \
|
| 17 |
+
PATH=/home/user/.local/bin:$PATH
|
| 18 |
+
|
| 19 |
+
# Set the working directory to the user's home directory
|
| 20 |
+
WORKDIR $HOME/app
|
| 21 |
+
|
| 22 |
+
# Copy the current directory contents into the container at $HOME/app setting the owner to the user
|
| 23 |
+
COPY --chown=user ./cards_classification.pkl ./app.py ./test_images/ ./
|
| 24 |
+
|
| 25 |
+
CMD ["python", "app.py"]
|
app.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from fastai.vision.all import load_learner, PILImage
|
| 3 |
+
import os
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
import pathlib
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
if os.name == "nt": # Windows
|
| 9 |
+
pathlib.PosixPath = pathlib.WindowsPath
|
| 10 |
+
|
| 11 |
+
model_path = os.path.join(os.getcwd(), "cards_classification.pkl")
|
| 12 |
+
print(f"model path: ", model_path)
|
| 13 |
+
learn = load_learner(model_path, cpu=True)
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def classify_image(image):
|
| 17 |
+
if image is None:
|
| 18 |
+
return {}
|
| 19 |
+
img = PILImage.create(image)
|
| 20 |
+
pred_class, pred_idx, probs = learn.predict(img)
|
| 21 |
+
|
| 22 |
+
return {learn.dls.vocab[i]: float(probs[i]) for i in range(len(probs))}
|
| 23 |
+
# return (str(pred_class))
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
CARDS = ['ace of clubs', 'ace of diamonds', 'ace of hearts', 'ace of spades', 'eight of clubs', 'eight of diamonds', 'eight of hearts', 'eight of spades', 'five of clubs', 'five of diamonds', 'five of hearts', 'five of spades', 'four of clubs', 'four of diamonds', 'four of hearts', 'four of spades', 'jack of clubs', 'jack of diamonds', 'jack of hearts', 'jack of spades', 'joker', 'king of clubs', 'king of diamonds', 'king of hearts', 'king of spades', 'nine of clubs', 'nine of diamonds', 'nine of hearts', 'nine of spades', 'queen of clubs', 'queen of diamonds', 'queen of hearts', 'queen of spades', 'seven of clubs', 'seven of diamonds', 'seven of hearts', 'seven of spades', 'six of clubs', 'six of diamonds', 'six of hearts', 'six of spades', 'ten of clubs', 'ten of diamonds', 'ten of hearts', 'ten of spades', 'three of clubs', 'three of diamonds', 'three of hearts', 'three of spades', 'two of clubs', 'two of diamonds', 'two of hearts', 'two of spades']
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
# Create the interface with detailed description
|
| 30 |
+
with gr.Blocks() as iface:
|
| 31 |
+
gr.Markdown(
|
| 32 |
+
"""
|
| 33 |
+
🃏 Playing Card Image Classifier
|
| 34 |
+
|
| 35 |
+
This AI model can recognize and classify images of standard playing cards using deep learning.
|
| 36 |
+
|
| 37 |
+
### How it works:
|
| 38 |
+
Upload an image of a playing card, and the model will predict which card it is from a full deck of cards.
|
| 39 |
+
|
| 40 |
+
### Supported Cards:
|
| 41 |
+
The model can identify **all standard playing cards**, including:
|
| 42 |
+
- Aces, numbers (2–10), Jacks, Queens, and Kings
|
| 43 |
+
- All four suits: Clubs, Diamonds, Hearts, and Spades
|
| 44 |
+
- Joker card
|
| 45 |
+
|
| 46 |
+
(In total: 53 classes)
|
| 47 |
+
|
| 48 |
+
### Tips for best results:
|
| 49 |
+
- Use clear, high-resolution images
|
| 50 |
+
- Make sure the card is fully visible
|
| 51 |
+
- Avoid heavy glare, blur, or occlusion
|
| 52 |
+
- One card per image works best
|
| 53 |
+
"""
|
| 54 |
+
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
+
with gr.Row():
|
| 58 |
+
with gr.Column():
|
| 59 |
+
input_image = gr.Image(type="pil", label="Upload Card Image")
|
| 60 |
+
submit_btn = gr.Button("🔍 Identify Card", variant="primary")
|
| 61 |
+
with gr.Column():
|
| 62 |
+
output_label = gr.Label(num_top_classes=3, label="Predictions")
|
| 63 |
+
|
| 64 |
+
gr.Examples(
|
| 65 |
+
examples=[
|
| 66 |
+
"./test_images/king_of_diamonds.jpg",
|
| 67 |
+
"./test_images/jack_of_spades.jpg",
|
| 68 |
+
"./test_images/ace_of_diamonds.jpg",
|
| 69 |
+
"./test_images/three_of_hearts.jpg",
|
| 70 |
+
"./test_images/ace_of_spades.jpg"
|
| 71 |
+
],
|
| 72 |
+
inputs=input_image,
|
| 73 |
+
label="Try an example"
|
| 74 |
+
)
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
submit_btn.click(fn=classify_image, inputs=input_image, outputs=output_label)
|
| 78 |
+
|
| 79 |
+
if __name__ == "__main__":
|
| 80 |
+
iface.launch(server_name="0.0.0.0", server_port=7860)
|
cards_classification.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:81f2dbdbe89108b9b15235aa90f915b4e8936f27dbff7393651e20c109f754d0
|
| 3 |
+
size 103294112
|
requirements.txt
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
aiofiles==24.1.0
|
| 2 |
+
aiohappyeyeballs==2.6.1
|
| 3 |
+
aiohttp==3.13.2
|
| 4 |
+
aiosignal==1.4.0
|
| 5 |
+
annotated-doc==0.0.4
|
| 6 |
+
annotated-types==0.7.0
|
| 7 |
+
anyio==4.12.0
|
| 8 |
+
argon2-cffi==25.1.0
|
| 9 |
+
argon2-cffi-bindings==25.1.0
|
| 10 |
+
arrow==1.4.0
|
| 11 |
+
asttokens==3.0.1
|
| 12 |
+
astunparse==1.6.3
|
| 13 |
+
async-lru==2.0.5
|
| 14 |
+
attrs==25.4.0
|
| 15 |
+
babel==2.17.0
|
| 16 |
+
beartype==0.22.9
|
| 17 |
+
beautifulsoup4==4.14.3
|
| 18 |
+
bleach==6.3.0
|
| 19 |
+
blis==1.3.3
|
| 20 |
+
brotli==1.2.0
|
| 21 |
+
build==1.3.0
|
| 22 |
+
catalogue==2.0.10
|
| 23 |
+
certifi==2025.11.12
|
| 24 |
+
cffi==2.0.0
|
| 25 |
+
charset-normalizer==3.4.4
|
| 26 |
+
click==8.3.1
|
| 27 |
+
cloudpathlib==0.23.0
|
| 28 |
+
cloudpickle==3.1.2
|
| 29 |
+
comm==0.2.3
|
| 30 |
+
confection==0.1.5
|
| 31 |
+
contourpy==1.3.3
|
| 32 |
+
cycler==0.12.1
|
| 33 |
+
cymem==2.0.13
|
| 34 |
+
datasets==4.4.2
|
| 35 |
+
debugpy==1.8.19
|
| 36 |
+
decorator==5.2.1
|
| 37 |
+
defusedxml==0.7.1
|
| 38 |
+
dill==0.4.0
|
| 39 |
+
execnb==0.1.16
|
| 40 |
+
executing==2.2.1
|
| 41 |
+
fastai==2.8.6
|
| 42 |
+
fastapi==0.128.0
|
| 43 |
+
fastcore==1.9.5
|
| 44 |
+
fastdownload==0.0.7
|
| 45 |
+
fastjsonschema==2.21.2
|
| 46 |
+
fastprogress==1.0.3
|
| 47 |
+
fasttransform==0.0.2
|
| 48 |
+
ffmpy==1.0.0
|
| 49 |
+
filelock==3.20.1
|
| 50 |
+
fonttools==4.61.1
|
| 51 |
+
fqdn==1.5.1
|
| 52 |
+
frozenlist==1.8.0
|
| 53 |
+
fsspec==2025.10.0
|
| 54 |
+
ghapi==1.0.8
|
| 55 |
+
gradio==6.2.0
|
| 56 |
+
gradio_client==2.0.2
|
| 57 |
+
graphviz==0.21
|
| 58 |
+
groovy==0.1.2
|
| 59 |
+
h11==0.16.0
|
| 60 |
+
hf-xet==1.2.0
|
| 61 |
+
httpcore==1.0.9
|
| 62 |
+
httpx==0.28.1
|
| 63 |
+
huggingface-hub==0.36.0
|
| 64 |
+
idna==3.11
|
| 65 |
+
isoduration==20.11.0
|
| 66 |
+
jedi==0.19.2
|
| 67 |
+
Jinja2==3.1.6
|
| 68 |
+
joblib==1.5.3
|
| 69 |
+
json5==0.12.1
|
| 70 |
+
jsonpointer==3.0.0
|
| 71 |
+
jsonschema==4.25.1
|
| 72 |
+
jsonschema-specifications==2025.9.1
|
| 73 |
+
kiwisolver==1.4.9
|
| 74 |
+
lark==1.3.1
|
| 75 |
+
lxml==6.0.2
|
| 76 |
+
markdown-it-py==4.0.0
|
| 77 |
+
MarkupSafe==3.0.3
|
| 78 |
+
matplotlib==3.10.8
|
| 79 |
+
matplotlib-inline==0.2.1
|
| 80 |
+
mdurl==0.1.2
|
| 81 |
+
mistune==3.1.4
|
| 82 |
+
mpmath==1.3.0
|
| 83 |
+
multidict==6.7.0
|
| 84 |
+
multiprocess==0.70.18
|
| 85 |
+
murmurhash==1.0.15
|
| 86 |
+
nbclient==0.10.3
|
| 87 |
+
nbconvert==7.16.6
|
| 88 |
+
nbdev==2.4.7
|
| 89 |
+
nbformat==5.10.4
|
| 90 |
+
nest-asyncio==1.6.0
|
| 91 |
+
networkx==3.6.1
|
| 92 |
+
numpy==2.4.0
|
| 93 |
+
nvidia-cublas-cu12==12.8.4.1
|
| 94 |
+
nvidia-cuda-cupti-cu12==12.8.90
|
| 95 |
+
nvidia-cuda-nvrtc-cu12==12.8.93
|
| 96 |
+
nvidia-cuda-runtime-cu12==12.8.90
|
| 97 |
+
nvidia-cudnn-cu12==9.10.2.21
|
| 98 |
+
nvidia-cufft-cu12==11.3.3.83
|
| 99 |
+
nvidia-cufile-cu12==1.13.1.3
|
| 100 |
+
nvidia-curand-cu12==10.3.9.90
|
| 101 |
+
nvidia-cusolver-cu12==11.7.3.90
|
| 102 |
+
nvidia-cusparse-cu12==12.5.8.93
|
| 103 |
+
nvidia-cusparselt-cu12==0.7.1
|
| 104 |
+
nvidia-nccl-cu12==2.27.5
|
| 105 |
+
nvidia-nvjitlink-cu12==12.8.93
|
| 106 |
+
nvidia-nvshmem-cu12==3.3.20
|
| 107 |
+
nvidia-nvtx-cu12==12.8.90
|
| 108 |
+
orjson==3.11.5
|
| 109 |
+
packaging==25.0
|
| 110 |
+
pandas==2.3.3
|
| 111 |
+
pandocfilters==1.5.1
|
| 112 |
+
parso==0.8.5
|
| 113 |
+
pexpect==4.9.0
|
| 114 |
+
pillow==12.0.0
|
| 115 |
+
platformdirs==4.5.1
|
| 116 |
+
plum-dispatch==2.6.1
|
| 117 |
+
preshed==3.0.12
|
| 118 |
+
prometheus_client==0.23.1
|
| 119 |
+
prompt_toolkit==3.0.52
|
| 120 |
+
propcache==0.4.1
|
| 121 |
+
psutil==7.1.3
|
| 122 |
+
ptyprocess==0.7.0
|
| 123 |
+
pure_eval==0.2.3
|
| 124 |
+
pyarrow==22.0.0
|
| 125 |
+
pycparser==2.23
|
| 126 |
+
pydantic==2.12.5
|
| 127 |
+
pydantic_core==2.41.5
|
| 128 |
+
pydub==0.25.1
|
| 129 |
+
Pygments==2.19.2
|
| 130 |
+
pyparsing==3.2.5
|
| 131 |
+
pyproject_hooks==1.2.0
|
| 132 |
+
python-dateutil==2.9.0.post0
|
| 133 |
+
python-json-logger==4.0.0
|
| 134 |
+
python-multipart==0.0.21
|
| 135 |
+
pytz==2025.2
|
| 136 |
+
PyYAML==6.0.3
|
| 137 |
+
pyzmq==27.1.0
|
| 138 |
+
referencing==0.37.0
|
| 139 |
+
regex==2025.11.3
|
| 140 |
+
requests==2.32.5
|
| 141 |
+
rfc3339-validator==0.1.4
|
| 142 |
+
rfc3986-validator==0.1.1
|
| 143 |
+
rfc3987-syntax==1.1.0
|
| 144 |
+
rich==14.2.0
|
| 145 |
+
rpds-py==0.30.0
|
| 146 |
+
safehttpx==0.1.7
|
| 147 |
+
safetensors==0.7.0
|
| 148 |
+
scikit-learn==1.8.0
|
| 149 |
+
scipy==1.16.3
|
| 150 |
+
semantic-version==2.10.0
|
| 151 |
+
Send2Trash==1.8.3
|
| 152 |
+
sentencepiece==0.2.1
|
| 153 |
+
setuptools==80.9.0
|
| 154 |
+
shellingham==1.5.4
|
| 155 |
+
six==1.17.0
|
| 156 |
+
smart_open==7.5.0
|
| 157 |
+
soupsieve==2.8.1
|
| 158 |
+
spacy==3.8.11
|
| 159 |
+
spacy-legacy==3.0.12
|
| 160 |
+
spacy-loggers==1.0.5
|
| 161 |
+
srsly==2.5.2
|
| 162 |
+
stack-data==0.6.3
|
| 163 |
+
starlette==0.50.0
|
| 164 |
+
sympy==1.14.0
|
| 165 |
+
terminado==0.18.1
|
| 166 |
+
thinc==8.3.10
|
| 167 |
+
threadpoolctl==3.6.0
|
| 168 |
+
tinycss2==1.4.0
|
| 169 |
+
tokenizers==0.22.1
|
| 170 |
+
tomlkit==0.13.3
|
| 171 |
+
torch==2.9.1
|
| 172 |
+
torchvision==0.24.1
|
| 173 |
+
tornado==6.5.4
|
| 174 |
+
tqdm==4.67.1
|
| 175 |
+
traitlets==5.14.3
|
| 176 |
+
transformers==4.57.3
|
| 177 |
+
triton==3.5.1
|
| 178 |
+
typer==0.21.0
|
| 179 |
+
typer-slim==0.20.1
|
| 180 |
+
typing-inspection==0.4.2
|
| 181 |
+
typing_extensions==4.15.0
|
| 182 |
+
tzdata==2025.3
|
| 183 |
+
uri-template==1.3.0
|
| 184 |
+
urllib3==2.6.2
|
| 185 |
+
uvicorn==0.40.0
|
| 186 |
+
wasabi==1.1.3
|
| 187 |
+
watchdog==6.0.0
|
| 188 |
+
wcwidth==0.2.14
|
| 189 |
+
weasel==0.4.3
|
| 190 |
+
webcolors==25.10.0
|
| 191 |
+
webencodings==0.5.1
|
| 192 |
+
websocket-client==1.9.0
|
| 193 |
+
wheel==0.45.1
|
| 194 |
+
widgetsnbextension==4.0.15
|
| 195 |
+
wrapt==2.0.1
|
| 196 |
+
xxhash==3.6.0
|
| 197 |
+
yarl==1.22.0
|
test_images/ace_of_diamonds.jpg
ADDED
|
test_images/ace_of_spades.jpg
ADDED
|
test_images/jack_of_spades.jpg
ADDED
|
test_images/king_of_diamonds.jpg
ADDED
|
test_images/three_of_hearts.jpg
ADDED
|