Skip to content

Latest commit

Β 

History

History
244 lines (188 loc) Β· 7.08 KB

File metadata and controls

244 lines (188 loc) Β· 7.08 KB

πŸͺž SixByFive TCG β€” Finish Detector Trainer

A lightweight TensorFlow-based training environment for teaching a model to recognise card finishes (e.g., Normal vs Reverse Holo vs Holo vs Full Art) from photos of PokΓ©mon TCG cards.

The output is a small .tflite model ready to run on-device in your SixByFive TCG mobile app (Expo / React Native).


🧱 Overview

This repository provides:

  • Scripts to verify and preprocess your dataset
  • Automatic card-aware train/val/test splits
  • A patch builder that crops useful regions (corners, bottom band)
  • A model trainer that exports a quantized .tflite for mobile
  • Evaluation utilities for quick testing

πŸ“‚ Folder Structure

sbf-scan-model/ β”œβ”€ README.md β”œβ”€ requirements.txt β”œβ”€ config/ β”‚ β”œβ”€ train.yaml # (optional) custom training hyperparams β”‚ └─ classes.yaml # (optional) canonical class list β”œβ”€ datasets/ β”‚ β”œβ”€ finish_raw/ # << you place your full-card photos here >> β”‚ β”‚ β”œβ”€ normal/ β”‚ β”‚ β”œβ”€ reverse_holo/ β”‚ β”‚ β”œβ”€ holo/ # (optional) β”‚ β”‚ └─ full_art/ # (optional) β”‚ β”œβ”€ finish_split/ # created by tools/make_split.py β”‚ └─ finish_patches/ # created by tools/build_patches.py β”œβ”€ artifacts/ β”‚ └─ finish_v1/ β”‚ β”œβ”€ model.h5 β”‚ β”œβ”€ model.int8.tflite # << ship this + labels.txt in the app >> β”‚ β”œβ”€ labels.txt β”‚ └─ report.json β”œβ”€ tools/ β”‚ β”œβ”€ check_dataset.py β”‚ β”œβ”€ make_split.py β”‚ β”œβ”€ build_patches.py β”‚ β”œβ”€ train_finish_classifier_explicit.py β”‚ β”œβ”€ eval_tflite.py β”‚ └─ utils/io.py └─ scripts/ └─ export_onnx.py


πŸ“Έ Dataset Preparation

1️⃣ Where to put your images

Place your photos under:

datasets/finish_raw/<class_name>/

Examples:

datasets/finish_raw/normal/ datasets/finish_raw/reverse_holo/ datasets/finish_raw/holo/ datasets/finish_raw/full_art/

Only normal/ and reverse_holo/ are required for v1 β€” you can add the others later.


2️⃣ File naming convention

Use the following pattern for every file:

<card_key><shot_id>.jpg

Part Example Meaning
card_key sv1_123_pikachu stable ID for that card
finish normal or reverse_holo finish label
shot_id 1718283999012 timestamp or unique number

βœ… Example valid names: sv1_123_pikachu__normal__1718283982001.jpg sv1_123_pikachu__reverse_holo__1718283999012.jpg trainer_ultraball__reverse_holo__0003.jpg energy_grass__normal__johns_pixel_0007.jpg

⚠️ Avoid spaces, parentheses, or additional underscores outside this format.


3️⃣ Optional metadata

If you want to record extra details, add a matching .json file for each image:

sv1_123_pikachu__reverse_holo__1718283999012.json

Content example:

{
  "device": "iPhone 13 Pro",
  "sleeve": "matte",
  "lighting": "indoor"
}
The checker reads these to report device/sleeve diversity.

4️⃣ Minimum dataset targets
Metric	Recommended
Distinct cards per class	20–30
Photos per card	5–8 (angles, sleeves, lighting)
Total photos per class	β‰₯ 150
Classes (for v1)	normal, reverse_holo

βš™οΈ Setup Instructions (Windows / PowerShell)
# 1) Create & activate virtualenv
py -3 -m venv .venv
.\.venv\Scripts\Activate.ps1
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass

# 2) Install dependencies
pip install -r requirements.txt

# 3) Verify your dataset layout
python tools\check_dataset.py --root datasets\finish_raw --min-cards-per-class 20 --min-images-per-card 5 --min-total-per-class 150

# 4) Split by card (avoids same-card leakage)
python tools\make_split.py --root datasets\finish_raw --out datasets\finish_split --train 0.8 --val 0.2 --test 0.0

# 5) Build patches for each split
python tools\build_patches.py --src datasets\finish_split\train --dst datasets\finish_patches\train
python tools\build_patches.py --src datasets\finish_split\val   --dst datasets\finish_patches\val

# 6) Train model (explicit dirs)
python tools\train_finish_classifier_explicit.py `
  --train_dir datasets\finish_patches\train `
  --val_dir   datasets\finish_patches\val `
  --out       artifacts\finish_v1 `
  --img 160 --epochs 25

# 7) Evaluate exported TFLite
python tools\eval_tflite.py `
  --data   datasets\finish_patches\val `
  --tflite artifacts\finish_v1\model.int8.tflite `
  --labels artifacts\finish_v1\labels.txt `
  --img 160
🧠 Outputs
After training, you’ll find results in:

artifacts/finish_v1/
β”‚
β”œβ”€ model.h5                 # full Keras model
β”œβ”€ model.int8.tflite        # quantized for mobile (ship this!)
β”œβ”€ labels.txt               # class order (one line per class)
└─ report.json              # training summary (accuracy, loss, params)
Copy these two files into your Expo app:

/assets/ml/finish/model.int8.tflite
/assets/ml/finish/labels.txt
Then load them with your TFLite bridge.

πŸš€ Using the model in your Expo app
Example snippet:

import Tflite from "tflite-react-native";
import * as ImageManipulator from "expo-image-manipulator";

const tflite = new Tflite();

async function classifyFinish(localPath) {
  await new Promise((resolve, reject) => {
    tflite.loadModel(
      {
        model: "model.int8.tflite",
        labels: "labels.txt",
      },
      (err, res) => (err ? reject(err) : resolve(res))
    );
  });

  // crop bottom-right patch and resize to 160Γ—160
  const patch = await ImageManipulator.manipulateAsync(
    localPath,
    [{ crop: { originX: 0.6, originY: 0.7, width: 0.4, height: 0.25, unit: "normalized" } },
     { resize: { width: 160, height: 160 } }],
    { compress: 1, format: ImageManipulator.SaveFormat.JPEG }
  );

  const result = await new Promise((resolve) => {
    tflite.runModelOnImage(
      {
        path: patch.uri.replace("file://", ""),
        imageMean: 0,
        imageStd: 255,
        numResults: 2,
        threshold: 0.01,
      },
      (err, res) => resolve(err ? [] : res)
    );
  });

  const best = result[0] || { label: "unknown", confidence: 0 };
  return best;
}
🧩 Quick Reference
Tool	Purpose
tools/check_dataset.py	Validate dataset balance, devices, and leakage
tools/make_split.py	Create train/val/test splits grouped by card
tools/build_patches.py	Crop standard regions for model input
tools/train_finish_classifier_explicit.py	Train model on explicit train/val dirs
tools/eval_tflite.py	Evaluate exported TFLite model
scripts/export_onnx.py	(Optional) Export .h5 to ONNX format

🧾 Versioning Your Models
Each new training run should go in a new folder:

artifacts/
β”œβ”€ finish_v1/
β”œβ”€ finish_v2/
└─ finish_v3/
Keep labels.txt in sync with your .tflite.

πŸ†˜ Troubleshooting
Issue	Solution
Python was not found	Disable Windows β€œApp Execution Aliases” for python/python3, or use py -3
Could not find TensorFlow	pip install tensorflow-cpu==2.17.1
Training crashes on small dataset	Add more distinct cards and rerun make_split.py
Model accuracy < 70%	Collect more diverse lighting/sleeves/sets; check patch crops
Validation accuracy >> test accuracy	Possible leakage β€” rerun make_split.py and retrain

πŸ“œ License
MIT Β© 2025 SixByFive β€” Use freely, modify, and contribute back improvements.