Skip to content

Inventaire des algorithmes de scan ​

Dernière mise à jour : 2026-05-23.

Cette page relie les choix visibles dans le scanner mobile aux vrais moteurs de reconnaissance derrière. Elle clarifie aussi où se trouvent les photos de fixture du POC et si elles participent au matching de production.

Résumé Exécutif ​

L'app a actuellement quatre familles de scan visibles :

Source mobileType d'objetPath runtimeRôle
SKNCardfan-out lab, compat, tormknd, combined, frameComparer tous les paths carte côte à côte.
SKNSlabmêmes paths que CardComportement temporaire. Il n'y a pas encore de reconnaissance slab dédiée.
SKNSealedsealed seulementReconnaissance générique de scellés dans le backend SKN.
Booster LabBoostertcgapp2-booster seulementScanner booster façon Tormknd, isolé du path scellé SKN.

La prise de photo et l'import d'image sont seulement des sources d'entrée. Une fois l'image choisie, les deux passent dans le même plan de scan actif pour le type d'objet sélectionné.

Algorithmes Actuels ​

Lab ​

  • Mode mobile : lab
  • Endpoint : POST /scan-lab sur l'API Node/Fastify SKN, port 8080
  • Objet : photo brute de carte TCG
  • Pré-traitement : décodage JPEG côté serveur, détection OpenCV du contour de carte, crop/warp si une zone carte est trouvée
  • Embedding : DINOv2 small, 384 dimensions, via le sidecar embeddings
  • Index : PostgreSQL pgvector, table card_embeddings_lab, index HNSW cosine
  • Catalogue : Pokémon, One Piece, Magic, Lorcana, Flesh and Blood
  • Décision : signal visuel unique par embedding
  • Force : path carte SKN rapide, large couverture catalogue et filtres SQL avant recherche de voisins
  • Faiblesse : peut faire des faux positifs sur des cartes visuellement proches, car il ne confirme pas avec OCR ou pHash

C'est le path carte principal de SKN. Il teste proprement notre stack DINOv2 plus pgvector.

Compat ​

  • Mode mobile : compat
  • Endpoint : POST /scan-compat sur le sidecar Python tcg-vision, port 8000
  • Objet : photo brute de carte TCG
  • Pré-traitement : correction perspective OpenCV façon Tormknd
  • Embedding : DINOv2 small, 384 dimensions
  • Index : FAISS IndexFlatIP en mémoire, avec un faiss_index.bin préconstruit
  • Catalogue : catalogue embarqué dans le sidecar, surtout Pokémon, One Piece et un peu de Lorcana
  • Décision : signal visuel unique par embedding
  • Force : path rollback/A-B utile, sans dépendance à pgvector
  • Faiblesse : couverture plus étroite, artefact FAISS figé, filtrage plus faible que SQL

Compat est notre version forkée et intégrée du path tgc-app de ton ami. Il adapte la réponse au contrat mobile SKN et peut enrichir les résultats avec nos métadonnées.

Tormknd / tgc-app ​

  • Mode mobile : tormknd
  • Endpoint : POST /scan sur le sidecar Tormknd non modifié, port 8002
  • Objet : photo brute de carte TCG
  • Pré-traitement : correction perspective OpenCV upstream tgc-app
  • Embedding : DINOv2 small, 384 dimensions
  • Index : FAISS IndexFlatIP et mapping upstream
  • Décision : signal visuel unique par embedding
  • Force : référence immuable pour comparer notre fork et nos changements backend
  • Faiblesse : réponse non enrichie pour la production SKN, catalogue plus étroit, désactivé par défaut derrière le profil Docker tormknd

Dans nos discussions on l'appelle parfois tcg-app, mais le repo local de référence est tgc-app. On le traite comme repo de référence et on ne le modifie pas pour le comportement SKN.

Combined ​

  • Mode mobile : combined
  • Endpoint : POST /scan sur l'API Node/Fastify SKN, port 8080
  • Objet : photo brute de carte TCG
  • Pré-traitement : crop serveur, puis plusieurs signaux indépendants
  • Signaux : pHash, OCR, embedding DINOv2
  • Index embedding : même table pgvector card_embeddings_lab que Lab
  • Décision : cascade multi-signal via decideMatch
  • Force : meilleur path debug pour comprendre pourquoi une photo est acceptée ou refusée
  • Faiblesse : plus strict et plus lent que Lab; peut rejeter une image acceptée par un path embedding-only

Combined est l'ancien path production. Il peut matcher via pHash quasi-duplicate, identifiants imprimés lus par OCR, ou rescue par embedding. Il est très utile quand l'app doit expliquer une ambiguïté.

Frame ​

  • Mode mobile : frame
  • Endpoint : POST /scan-frame sur l'API Node/Fastify SKN, port 8080
  • Objet : photo de carte après rectification côté client
  • Pré-traitement : OpenCV natif Android detectQuad puis warpQuad, puis upload du crop redressé
  • Embedding : DINOv2 small, 384 dimensions
  • Index : même table pgvector card_embeddings_lab que Lab
  • Décision : signal visuel unique par embedding
  • Force : isole l'impact du crop/warp fait sur le téléphone
  • Faiblesse : lent ou fragile si le détecteur quadrilatère côté client rate la carte ou croppe la mauvaise zone

Frame est le Path #5. C'est un path lab pour mesurer si le téléphone peut produire un meilleur crop canonique que le backend.

Sealed ​

  • Mode mobile : sealed
  • Endpoint : POST /scan-sealed-lab sur l'API Node/Fastify SKN, port 8080
  • Objet : scellés Pokémon génériques : ETB, display, booster bundle, collection box, blister, booster pack
  • Pré-traitement : image brute par défaut; crop scellé optionnel quand l'app a un indice de forme booster
  • Embedding : DINOv2 base, 768 dimensions, via le sidecar dédié sealed-embeddings
  • Index : PostgreSQL pgvector, table sealed_product_embeddings_vitb_lab
  • Sources de référence : images internes ptcg-assets par défaut ; les photos de référence scellées SKN-owned sont en pause pour les scans normaux et doivent être demandées explicitement
  • Signaux en plus : OCR optionnel, filtres type produit/langue, reranking des candidats
  • Détecteur optionnel : segmentation YOLO si models/yolo/booster_seg.pt existe; sinon fallback OpenCV foreground crop
  • Force : la couverture scellée large de ptcg-assets peut être interrogée dans le même backend que les cartes, tandis que les références SKN-owned restent disponibles pour le debug et les benchmarks contrôlés
  • Faiblesse : l'accuracy terrain dépend encore de la couverture des références, qualité photo, variantes produit, variantes de langue et qualité du détecteur

Les scans scellés génériques ne forcent volontairement pas booster_pack, parce qu'un booster visible dans une box peut sinon dominer le match et masquer le vrai produit.

tcg-app2 Booster ​

  • Mode mobile : tcgapp2-booster
  • Endpoint : POST /scan/booster sur le service FastAPI local tcg-app2, port 8003
  • Objet : booster packs
  • Pré-traitement : contrôle de flou, segmentation booster YOLOv11-Seg si un modèle est présent, fallback contour OpenCV sinon
  • Embedding : DINOv2 ViT-B/14, 768 dimensions, entrée 518 px
  • OCR : EasyOCR, concentré sur les métadonnées utiles de booster : langue, éditeur, édition, année et indice TCG
  • Vector store : Qdrant, en stockage local embarqué ou mode serveur
  • Source de référence : tcg-app2/data/boosters_metadata.json plus images boosters indexées par scripts/build_booster_index.py
  • Décision : recherche vectorielle avec filtres metadata issus de l'OCR
  • Force : plus proche de l'architecture booster spécifique de ton ami, utile pour les A-B tests booster-only
  • Faiblesse : stack séparée, index séparé, scope booster-only, qualité très dépendante du modèle de segmentation booster et du catalogue indexé

Ce path est isolé volontairement du scellé générique SKN. C'est un comparateur lab, pas un remplacement de tous les scellés.

Fallback on-device ​

  • Runtime : app React Native, sans backend
  • Entrées : src/scan/cardIndex.json local et stratégies scanner
  • Signaux : pHash, histogramme couleur, OCR/MLKit local quand disponible, ensemble de stratégies debug
  • Force : fonctionne quand les endpoints backend échouent
  • Faiblesse : moins précis et moins complet que la reconnaissance backend

C'est une couche fallback et diagnostic, pas le scanner de production principal.

Reconnaissance slab ​

  • État actuel : l'app a un type Slab, mais il utilise actuellement les cinq mêmes paths que Card
  • Ce qui manque : détection slab, crop du label, reconnaissance de l'organisme de grading, OCR de la note, OCR du numéro de certification, politique de vérification dédiée

Aujourd'hui une photo de slab peut donc identifier la carte visible si le crop est assez bon, mais elle ne reconnaît pas vraiment PSA 10, BGS, CGC ou le cert number.

Ce Qui Est Entraîné vs Indexé ​

ComposantEntraîné par nous aujourd'hui ?Ce qui change quand on l'améliore
Embeddings cartes DINOv2Non. Modèle pré-entraîné figé.Rebuild des embeddings cartes si le modèle, le crop ou la géométrie d'entrée change.
Embeddings scellés DINOv2Non. Modèle pré-entraîné figé.Rebuild des embeddings scellés si le modèle, le crop ou la géométrie d'entrée change.
FAISS / pgvector / QdrantNon. Ce sont des index vectoriels, pas des modèles de reconnaissance.Réindexer les vecteurs et les métadonnées.
Détecteur YOLO scellé/boosterOui, dès qu'on fournit des poids.Meilleur crop objet avant embedding, surtout sur vraies photos téléphone.
OCRNon. OCR off-the-shelf plus règles.Améliorer régions texte, dictionnaires, filtres et reranking.
ptcg-assets / images SKN-ownedPas des modèles. Ce sont des références. Les scans normaux utilisent ptcg-assets par défaut ; SKN-owned est en pause sauf demande explicite.Ajouter une couverture référence plus propre, licenciée et mieux labellisée.

Où Interviennent les Photos du POC ​

Il y a deux concepts différents à ne pas mélanger : les fixtures de test du POC et les références scellées backend.

Dans poc-tcg-collector ​

Le repo POC contient des images de fixture pour les tests et le fallback local :

PathNombre observéRôle
__fixtures__/cards/real/*.jpg5Fixtures cartes réelles pour les tests d'intégration autour de demoScanDb.
__fixtures__/tcgdex/images/*.jpg13Fixtures de reproductibilité pour les anciens tests d'ingest TCGdex.
__fixtures__/cards/card-a-stripes.jpg, card-b-checker.jpg, card-c-gradient.jpg3Fixtures synthétiques pour déterminisme pHash et histogramme.
src/scan/demoScanDb.tslignes généréesPetite DB démo legacy utilisée par les tests. Le scanner écran production ne la lit plus directement.
src/scan/cardIndex.jsoncatalogue JSONCatalogue fallback/debug bundlé par Metro, généré depuis les données backend.
fichiers racine Screenshot_*.jpgnon suivisScreenshots de debug visuel seulement. Ce ne sont pas des références.

Ces images du POC ne nourrissent pas /scan-lab, /scan-compat, /scan, /scan-frame, /scan-sealed-lab ou le matching production tcg-app2 au runtime. Elles servent surtout aux tests, à la reproductibilité et au fallback local de diagnostic.

Les "10 photos" du dernier travail scellé ​

Les 10 photos scellées possédées par SKN sont côté backend, pas dans le POC :

text
tcg-collector-backend/src/api/tests/fixtures/sealed-samples/images/labeled/

Elles sont listées dans :

text
tcg-collector-backend/src/api/tests/fixtures/sealed-samples/manifest.json

Elles interviennent à deux endroits :

  1. Échantillons benchmark : npm run benchmark:sealed les poste vers /scan-sealed-lab et mesure l'accuracy exact/top-K.
  2. Références privées SKN-owned : l'ingest Docker monte sealed-samples via SKN_SEALED_REFERENCES_SOURCE, mais depuis le 2026-05-23 le défaut compose est SEALED_INCLUDE_SKN_REFERENCES=false. Si elles sont activées manuellement, elles peuvent être embed dans sealed_product_embeddings_vitb_lab comme références skn-owned:*.

Ce deuxième point est utile, mais il faut l'interpréter correctement : matcher ces mêmes 10 photos après les avoir indexées valide le câblage et le rappel de doublons. Ça ne prouve pas que le scanner généralise à de nouvelles photos téléphone, angles, lumières, langues ou variantes jamais vues.

Les requêtes /scan-sealed-lab normales utilisent maintenant source=ptcg-assets par défaut, même si d'anciennes lignes skn-owned existent encore dans Postgres. Utiliser source=skn-owned uniquement pour debugger les références bootstrap possédées, ou source=all pour des comparaisons A/B contrôlées.

Pour valider le terrain avec des images jamais ingérées, il faut utiliser le dossier séparé :

text
tcg-collector-backend/src/api/tests/fixtures/sealed-eval/

Ces images ne doivent pas être ingérées comme références. Elles servent à mesurer la généralisation.

Guide de Lecture Pratique ​

  • Si Lab est bon et Combined refuse : le voisin visuel est probablement bon, mais OCR/pHash ne confirment pas.
  • Si Frame est pire que Lab : le crop client est probablement faux ou trop lent.
  • Si Compat ou Tormknd est meilleur que Lab : comparer pré-traitement et couverture d'index avant de changer les seuils.
  • Si tcg-app2 Booster est meilleur que Sealed sur boosters : sa segmentation booster/Qdrant/OCR aide vraiment.
  • Si Sealed retourne de mauvais produits proches : inspecter top-K, filtres OCR, type produit, langue, présence de la référence attendue, et vérifier si une requête debug a explicitement activé source=skn-owned ou source=all.
  • Si une photo a été prise depuis un écran PC : attendre une accuracy plus faible, les reflets et le moiré peuvent dominer l'embedding.

Pages Liées ​