Detects Magic: The Gathering cards in images and outputs JSON as
{
"name": "Counterspell",
"set": "lea", // The unique set code. E.g. lea = Limited Edition Alpha
"number": "54", // The collectors number in the set
"id": "0df55e3f-14de-46ef-b6b1-616618724d9e" // The id from the Scryfall API
}
or if it cannot detect any card it will output
{
"error": "COULD_NOT_DETECT_ANY_CARDS"
}
There are two tools:
phash-generator.py
: Generates phashes from a set of card scans/pictures. This is needed for the dector to work.detector.py
: Detects cards in an image (this is your end goal).
pip install -r requirements.txt
Note: you first need to generate phashes of pictures/scans of the cards you want to detect. Read the next usage sections first.
usage: detector.py [--help] --phash PHASH [--continuous] [--input_path PATH]
You will either need to use --continuous
or --input_path
--continuous
: The program will keep running and you will need to pass paths to file throught stdin--input_path PATH
: The program will run only on those files in that folder
Example 1:
In a long-running setup you will most likely not want to keep starting the detector, but keep it running and send paths to it over stdin when there is a card you need to detect.
$ echo "test/limited_edition_alpha/3_6f9ea46a-411f-40ce-a873-a905180093f4_Balance.jpg" | ./detector.py --phash test/lea_phashes.dat --continuous
{"name": "Balance", "set": "lea", "number": "3", "id": "6f9ea46a-411f-40ce-a873-a905180093f4", "recognition_score": 1.066549935262097}
Example 2:
This example can run out of the box, if you have generated the .dat
file first running the above.
$ ./detector.py --phash test/lea_phashes.dat --input_path test/test-pictures
ready
{"name": "Counterspell", "set": "lea", "id": "0df55e3f-14de-46ef-b6b1-616618724d9e", "number": "54"}
{"name": "Instill Energy", "set": "lea", "id": "5bd38716-874c-4e3c-a315-837839a6258c", "number": "202"}
{"name": "Island", "set": "lea", "id": "90a57c0e-fa61-45ef-955d-d296403967d5", "number": "288"}
...
You need to generate a .dat
file with phashes of pictures before you can detect cards.
It is important that the files are structured in a correct way for this to work correctly. You can see /test/limited_edition_alpha
to see how files are correctly named.
Generally they should be named COLLECTOR-NUMBER_SCRYFALL-ID_NAME.jpg
. The underscores are important. An example for Black Lotus
from Alpha
is 232_b0faa7f2-b547-42c4-a810-839da50dadfe_Black Lotus.jpg
. This ensures that the returned JSON will look sound.
usage: phash-generator.py [-h] --set SET --folder FOLDER --output OUTPUT [--append]
This example can run out of the box, with the alpha cards provided in this repo.
$ ./phash-generator.py --set lea --folder test/lea --output lea_phashes.dat
You can generate a phash file which contains all of your cards if you use --sets-in-subfolders
.
To do this, you need to have sorted your card scans into subfolders like this:
/sets
/lea
/232_b0faa7f2-b547-42c4-a810-839da50dadfe_Black Lotus.jpg
...
/ktk
/98_c57534fb-2591-4003-aeec-6452faa4a759_Arrow Storm.jpg
...
...
Then you can run
$ ./phash-generator.py --folder sets --output all_phashes.dat --sets-in-subfolders
[1/869] Generating phash from images from the "pmh2" set
[2/869] Generating phash from images from the "iko" set
...
I've tested locally where I created a database of all images of all ~80k Magic card, and it took roughly 15 minutes to generate an all_phashes.dat
that was 70mb large
With an all_phashes.dat
of 70mb it still only took ~1 second to find a card in an image when using --input_path
. So it's pretty fast.
For a long-running or production setup, you will probably want to use --continuous
.
$ python test/test.py
Some test cases to test both phash-generator.py
and detector.py
This has been forked from https://github.com/tmikonen/magic_card_detector.
I've changed the way it work quite a bit, but the nitty gritty difficult part of actually gnerates phashes and detecting images was made by the @tmikonen.