| --- |
| license: agpl-3.0 |
| library_name: onnx |
| pipeline_tag: object-detection |
| tags: |
| - dice |
| - polyhedral-dice |
| - ttrpg |
| - tabletop |
| - yolox |
| - onnx |
| datasets: |
| - G-G-Games/diecamera-dice |
| --- |
| |
| # dieCamera dice readers |
|
|
| Four ONNX models that read physical polyhedral dice from a webcam frame: **which dice are |
| on the table, and what each one landed on.** They run offline on CPU or any DX12 GPU |
| (DirectML) in ~50β100 ms a frame, and are the local reader inside |
| [dieCamera](https://github.com/eschatus/diecamera). |
|
|
| Trained on [G-G-Games/diecamera-dice](https://huggingface.co/datasets/G-G-Games/diecamera-dice). |
|
|
| | file | job | size | |
| | ------------------------------------------------ | ------------------------------------------------------------ | ----: | |
| | `dice-shape.onnx` | YOLOv8 detector β finds each die, classifies its **type** | 43MB | |
| | `dice-value-glyph.onnx` | YOLOv8 detector β finds the **up-face numeral** on each die | 43MB | |
| | `dice-value.onnx` | ConvNeXt classifier β reads that numeral, 21-way `"0".."20"` | 106MB | |
| | `dice-value-cls.onnx` | YOLOv8-cls β reads a whole-die crop directly, 60-way | 20MB | |
|
|
| Each ships with a `.classes.json` giving its output order. **The class list is not |
| optional** β the indices mean nothing without it. |
|
|
| ## Two ways to read a face |
|
|
| `dice-shape` finds and types the dice in both pipelines. What differs is how the numeral |
| is read: |
|
|
| **Three-pass** (`dice-shape` β `dice-value-glyph` β `dice-value`) localises the numeral on |
| the full frame and classifies a tight crop of it. Argmax is gated to the die type's legal |
| range, so a "15" can never come back for a d8, and the returned confidence is a softmax |
| over the in-range classes only. |
|
|
| **Two-pass** (`dice-shape` β `dice-value-cls`) skips localisation and classifies the die |
| crop whole, as one of 60 (type, face) classes. A fifth the size and one less model call. |
|
|
| Both are shipped. Which is better is genuinely unsettled β see below. |
|
|
| ## Accuracy, honestly |
|
|
| Reported by their authors, on their own held-out splits: |
|
|
| - `dice-shape` β mAP50 **0.886** on a shared three-domain validation set (v2). Its |
| predecessor scored 0.995 on a single-domain split and 0.752 here; the higher number was |
| an easier test set, not a better model. |
| - `dice-value` (three-pass) β cross-validated per type: **d8 0.88 Β· d10 0.72 Β· d12 0.75 Β· |
| d20 0.55**. |
| - `dice-value-cls` (two-pass) β face top-1 **0.411** on held-out crops. Most of that came |
| from training at 224px instead of downscaling crops to 128, which was worth +0.12 by |
| itself. |
|
|
| Measured head-to-head on identical frames from the training corpus: |
|
|
| | frames | three-pass | two-pass | |
| | ------------------------------- | ---------: | --------: | |
| | whole corpus (563 dice) | 0.490 | 0.480 | |
| | 30 newest, sharp 5MP (113 dice) | 0.575 | **0.699** | |
|
|
| **Do not read that table as a verdict.** Both models were trained on this corpus with |
| splits that were not recorded, and the two-pass model was retrained after most of those |
| newest frames existed β so its 0.699 is partly recall. Only five frames in the corpus |
| postdate its training. There is no clean shared holdout yet, and the per-author numbers |
| above are better evidence than anything measured after the fact. |
|
|
| Die-type detection is identical either way (0.961 on the same frames) because both start |
| from `dice-shape`. |
|
|
| ## What they are not |
|
|
| These are **rig specialists, not a general dice reader.** They were trained on a handful |
| of webcams over a small tray, and accuracy falls off sharply on unfamiliar lighting, |
| backgrounds, or dice sets. The best single predictor of whether they will work for you is |
| how many pixels land on a die face: the reference rig reads well at ~270px across a die |
| and poorly at ~140px. |
|
|
| The known failure is **6 vs 9 on a d10**, which is ambiguous on plenty of real dice sets |
| and is not fully solvable from pixels alone. |
|
|
| Consuming application note: dieCamera never posts a face without showing it to a human |
| first. A fast, correctable guess is more useful there than a slow accurate one β these |
| models are tuned for that trade, not for autonomous use. |
|
|
| ## Usage |
|
|
| ```python |
| import json, onnxruntime as ort |
| sess = ort.InferenceSession("dice-shape.onnx") |
| classes = json.load(open("dice-shape.classes.json"))["classes"] |
| # 640x640 letterboxed RGB, NCHW, 0-1 -> standard YOLOv8 output; NMS, then classes[class_id] |
| ``` |
|
|
| The full pipeline β letterboxing, NMS, glyph-to-die matching, the range gate, and the |
| ImageNet normalisation the classifier expects β is implemented in TypeScript in |
| [`src/readers/local/`](https://github.com/eschatus/diecamera/tree/main/src/readers/local). |
| The crop recipe must match training exactly (detector box + 0.1 margin, stretch-resized to |
| 224Γ224, ImageNet-normalised); drifting from it reintroduced a domain-shift bug that once |
| took a value model from 97% on web images to 17.5% on the real rig. |
|
|
| ## Credits |
|
|
| - **`dice-value.onnx` and `dice-value-glyph.onnx`** β the three-pass value reader, and its |
| runtime, by **[Triveni Gandhi (@trivenigandhi)](https://github.com/trivenigandhi)**, |
| contributed in [dieCamera PR #6](https://github.com/eschatus/diecamera/pull/6). She also |
| contributed capture frames to the dataset. |
| - **`dice-shape.onnx` and `dice-value-cls.onnx`** β [@eschatus](https://github.com/eschatus). |
|
|
| ## License |
|
|
| **AGPL-3.0.** Use, modify, or redistribute these weights β including as part of a hosted |
| or network-accessible service β under AGPL-3.0, which requires releasing corresponding |
| source for your derivative under the same terms. A separate commercial license, without |
| the AGPL's copyleft/source-disclosure obligations, is available from G-G-Games for closed |
| commercial use; contact us for terms. The [dieCamera](https://github.com/eschatus/diecamera) |
| application itself is licensed separately (see its own repo). The training data is |
| CC BY-SA 4.0 and published separately. |
|
|
| *(Provisional β this replaces an earlier MIT license on this card. Not yet cleared by |
| counsel; do not rely on the enforceability of the commercial-license carve-out until a |
| lawyer has reviewed it.)* |
|
|