ML engineering · 3 min read

20,953 Pokémon cards, one iPhone, no server: building an offline card scanner

cards in the catalog
20,953
to the first tile
~1 s
for a full page
~5 s
per scan, no server
$0
The results screen: 8 cards confirmed and 1 unsure, with a tile per card
8 confirmed, 1 unsure. Each tile opens the price page.

Photograph a binder page of Pokémon cards and every card is identified on the phone in about 5 seconds, with no server and no cost per scan. How it works, what moved the numbers, and the only model I trained.

Ken Ruiz Inoue · October 2026

1

Photo in, answers out

Collectors keep their Pokémon cards in 9-pocket binder pages, and pricing a page means looking up every card by hand. Another Scanner does it from one photo: it finds every card, names the exact printing out of 20,953 English cards, and opens its price page. It all runs on the phone, so it works offline, costs nothing per scan, and photos never leave the device.

The check screen: the detector found the 9 cards of a binder page
The detector finds all 9 cards and fits the page grid.
The results screen: 8 cards confirmed and 1 unsure, with a tile per card
8 confirmed, 1 unsure. Each tile opens the price page.
2

How a card gets identified

A small detector finds every card in the photo and straightens it. Then each card is narrowed down from the whole catalog to a single answer, going only as far as it needs; glare, sleeves and foil take extra steps.

One card, from 20,953 to one answer
  1. Shortlist by look

    20,953

    Every card in the catalog, ranked by a pretrained model

  2. Check the keypoints

    200

    The closest look-alikes, checked against the flat card

  3. Answer

    1

    A verified match, for most cards in about a second

Weak match or a twin printing? The printed number on the card decides.

3

Only 1 of 4 pieces was trained

I trained a model only where nothing off the shelf fit a phone. The rest is a pretrained model used as is, classic computer vision, and the text recognition built into iOS.

  • Trained by me

    Find the cards

    CardNet

    40 minutes of training on 131 photos, 12.8 MB.

  • Pretrained, used as is

    Shortlist by look

    DINOv2-small

    Never fine-tuned; shrunk from 88 MB to 24 MB.

  • Classic computer vision

    Check the geometry

    ORB + RANSAC

    No training: an exact yes or no for a flat card.

  • Built into iOS

    Read the text

    Apple Vision

    Free and on device, used only for hard cards.

4

What moved the numbers

Three changes, each measured on the same real cards before and after.

The geometry check

Right by name, same 75 real cards

Fingerprint only64%
With the check77%

The vote fix

Right card in top 25, of 205 crops

Strongest keypoints96
Weakest keypoints154

A faster fitter

Seconds per page, lower is better

RANSAC14 s
USAC1.5 s
5

Where it stands

A tester scanned 16 binder pages with the app; the result is below. On holdout pages the system was never tuned on, it scores 73 of 86, and the misses come from glare and sparse pages.

Phone test: 16 binder pages, 139 cards

135 of 139 right

  • 135 right
  • 3 unsure
  • 1 wrong

The point

Most of the accuracy came from engineering, not training: a pretrained model to shortlist, geometry to decide, the printed text for what the picture cannot settle, and a number for every change. Start cheap, measure on real inputs, and train only where nothing else works. Pokémon is the test case; the same pipeline should carry over to any large catalog of look-alike printed items, such as other card games.

Pokémon and Pokémon card names and images are trademarks and copyrights of Nintendo, Creatures Inc., GAME FREAK inc. and The Pokémon Company. Another Scanner is an independent open-source project and is not affiliated with, sponsored or endorsed by them or by TCGplayer.

Building something like this?

I build AI systems and mobile apps for companies that ship software. Tell me what you want to build and get a fixed quote.

Book a free 30-minute call

On Google Meet, in English, Spanish or Japanese.