TCG card corner detector

Finds a trading card in a photo and returns its four corners — top-left, top-right, bottom-right, bottom-left — so you can flatten the card to a front-facing view with one cv2.getPerspectiveTransform.

The corner order is fixed by keypoint index, so the output is ready to use: no sorting step, no ambiguity about which point is which.

A photograph of a card with its four detected corners, beside the flattened card

Usage

pip install ultralytics huggingface_hub opencv-python
import cv2, numpy as np
from huggingface_hub import hf_hub_download
from ultralytics import YOLO

weights = hf_hub_download("duclvQ/tcg-card-detector", "card_pose_yolov8n.pt")
model = YOLO(weights)
img = cv2.imread("photo.jpg")

res = model.predict(img, imgsz=480, conf=0.25)[0]
if len(res.boxes):
    best = int(res.boxes.conf.argmax())
    quad = res.keypoints.xy.cpu().numpy()[best]     # (4, 2) TL, TR, BR, BL

    dst = np.float32([[0, 0], [200, 0], [200, 280], [0, 280]])
    M = cv2.getPerspectiveTransform(quad.astype(np.float32), dst)
    card = cv2.warpPerspective(img, M, (200, 280))  # flat 200x280 card

quad is [[x_tl, y_tl], [x_tr, y_tr], [x_br, y_br], [x_bl, y_bl]] in pixels of the original image.

For more than one card in a photo, iterate instead of taking the best box:

for quad in res.keypoints.xy.cpu().numpy():
    ...

Nano-sized: 6.4 MB, ~36 ms per image at imgsz=480 on a desktop GPU.

card_pose_480.onnx (ONNX Runtime) and card_pose_480.mlmodel (CoreML, iOS) are the same model exported at the same input size. The CoreML file has not been verified on Apple hardware — test it before shipping.

On real photographs

Every image on this page is a real photograph — a physical card, real lighting, real background. None are rendered or composited.

Two photographs of single cards with the detected corners drawn on

On a set of 186 photographs of Pokémon cards, 183 produced a usable quadrilateral. Cards from other games are found too, as above — the model reads the card's shape, not any one game's artwork.

A card that stands clear of its surroundings is what this model is good at. It is much weaker once cards pile up; see Limitations.

Limitations

Three crowded tabletop photographs where nothing is detected

Crowded scenes are the weak spot. Cards that are clearly separated are found confidently. Fanned hands, stacks, binder pages and heavy overlap usually return nothing at all.

A card with no corner in the frame cannot be found. An extreme macro crop leaves nothing to locate.

Plain, borderless card-like rectangles are less reliable. Real cards from every game tested are found; a card-shaped object with no border at all is much weaker.

Heavy blur plus occlusion — a card behind a hand, badly out of focus — is also missed.

Photo credits

The example photographs are from Wikimedia Commons and keep their own licences, which are separate from the model's. Attribution as those licences require:

photo by licence
Digimon_Omnimon_X_Anti_body_Card.jpg slgckgc CC BY 2.0
Japanese_magic_the_gathering_cards_block.jpg Like_the_Grand_Canyon CC BY-NC 2.0
Digimon_Omnimon_X_Anti_body_Card.jpg slgckgc CC BY 2.0
Brian_Kibler_USA_vs_Daniel_Antoniou_Cyprus_jpg.jpg EuropeanTalent CC BY 4.0
Bruce_Spraggins_a_logistics_planner_with_Multinational.jpg 1st Lt. Casey Staheli Public domain
Daniel_Antoniou_jpg.jpg EuropeanTalent CC BY 4.0

Licence

AGPL-3.0, inherited from Ultralytics YOLOv8. Commercial use on other terms requires a licence from Ultralytics.

Trained on images of Pokémon cards, which are copyright The Pokémon Company / Nintendo. No card artwork is distributed here — this repository contains only detector weights, which locate a card-shaped quadrilateral and do not reproduce card images.

Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support