--- library_name: onnx base_model: timm/mobilenetv3_small_100.lamb_in1k base_model_relation: finetune tags: - onnx - computer-vision - optical-character-recognition - racing-telemetry - cpu --- # Omatrack telemetry reader · 1.0.0 A small **image-derived gauge reader for one reviewed 1920×1080 orange AiM HUD layout**. It predicts four visible fields from local onboard-video frames: | Field | Meaning | Not a claim about | |---|---|---| | `gear` | Displayed numeric gear | ECU/native ground truth or non-digit gear glyphs | | `stint_lap` | Displayed stint/lap counter | Classified laps, crossings, race position or lap timing | | `brake_fill_pct` | Visible brake-bar fill, 0–100% | Physical brake pressure, force or calibrated pedal travel | | `throttle_fill_pct` | Visible throttle-bar fill, 0–100% | A calibrated/native throttle channel | **This is not an arbitrary HUD detector.** The ONNX graph accepts four prepared crops, not a full frame. Use the accompanying preprocessing, structural admission, count-constrained CTC decoder and unknown masks. Confident digits alone do not establish that a supported gauge is present. ## Download a pinned release The release tag is `v1.0.0`. Resolve it once to a commit, then download every file at that **same immutable commit**. No login is needed for this public repository: ```sh uv run --no-project --with huggingface-hub==1.30.0 python - <<'PY' from huggingface_hub import HfApi, hf_hub_download repo = "tobil/omatrack-telemetry-reader" commit = HfApi(token=False).model_info(repo, revision="v1.0.0").sha for name in ( "manifest.json", "gauge-reader.onnx", "read_frame.py", "test_read_frame.py", "requirements.txt", "README.md", "NOTICE", "LICENSE-APACHE-2.0-UPSTREAM.txt", "LICENSE-MIT-OMATRACK-CODE.txt", ): hf_hub_download(repo, name, revision=commit, local_dir="reader", token=False) print("Downloaded model repository commit:", commit) PY ``` Artifact identity: - Filename: `gauge-reader.onnx` - Size: **2,213,746 bytes** - SHA256: **`97029f70068f4ec276b3d6bc28810763275806f579d91ddd4701b544af392147`** - ONNX opset: **17**, float32, fixed batch of four crops - Reader contract: **`omatrack-crop-count-v1`** - Omatrack managed-model minimum version: **1.8.2** `manifest.json` carries version, size, hash, reader contract, minimum app version, and the graph's current custom metadata. It contains no download URLs. An updater should resolve the repository revision, fetch the manifest and model from that same commit, verify size/hash and graph compatibility, and preserve its previous known-good model if any check fails. ## Run locally on a frame ```sh cd reader uv venv .venv --python 3.12 uv pip install --python .venv/bin/python -r requirements.txt uv run --no-project --python .venv/bin/python read_frame.py \ --model gauge-reader.onnx --image /path/to/local-full-resolution-frame.png # Public synthetic tests; no images or training data are required. OMATRACK_EXAMPLE_MODEL=gauge-reader.onnx \ uv run --no-project --python .venv/bin/python test_read_frame.py ``` The script reads the image and model locally, verifies this release's model SHA256 and graph contract, and prints JSON. **It contains no network/upload code.** Model downloading is a separate step; private input images are never sent to Hugging Face. The example does not require PyTorch, timm, the training checkout or a `.pt` file. Output contains `observations`, per-field `known`, `unknown_reason`, `layout_supported`, `visited`, `status`, and `latency_ms`. Unknown observations are JSON `null`, **never an invented zero**. Errors leave `visited=false`; a successfully inspected unsupported image can be visited with all fields unknown. A zero numeric observation can still be known. Masks are runtime behavior, not additional neural-network outputs or calibrated probabilities. Supply the decoded source image, not a resized screenshot of a video player. Do not resize, mirror, crop, letterbox, or apply EXIF/display rotation to make a different frame fit the layout. The standalone example has no video clock and prints no fabricated frame timestamp. In a video pipeline, retain the actual decoded presentation PTS separately; do not substitute `time-pos`, an ordinal, or nominal-FPS arithmetic. Prefer native telemetry whenever it is available. ## Use with Omatrack [Omatrack](https://github.com/tobi/omatrack) is a native telemetry workstation. With Omatrack **1.8.2 or later**, use **Preferences → Image telemetry** to obtain or update the managed model, or choose the downloaded local `gauge-reader.onnx`. The managed downloader verifies the manifest/hash/compatibility before switching. Open a local onboard video. Native telemetry takes precedence; a metadata/data track conservatively withholds image fallback. For an eligible standalone video: - Opening is video-first; **Escape** returns to the docked telemetry workspace. - Watching collects observed cells. **Scan from cursor** scans ahead and fills earlier holes; seeking does not discard already collected coverage. - Traces are explicitly image-derived and recording-time based, not fabricated distance or authoritative lap classifications. - Partial and complete standard `.telemetry` caches live in the application cache, never beside or over the source video. They retain visited/layout/known masks, an actual-presentation-PTS channel and the exact source-origin transform. - A complete, validated cache can reopen without running the model or decoder. The 200 ms cache lattice is a recording policy, not extra source resolution. Unknown/gapped cells are not held or interpolated into observations. None of this turns a bar-fill prediction into physical brake pressure. ## Model and tensor contract The trained model has **551,783 parameters**. It retains the stem and early stride-8 layers of the timm MobileNetV3-small backbone, adds a spatial crop encoder, and predicts digit logits, visible fill and digit count. It is not the original ImageNet classifier. No new training was performed for this publication. | Name | Type / shape | Use | |---|---|---| | `crops` | float32 `[4,3,64,192]` | NCHW RGB / 255, ordered gear, counter, brake, throttle | | `digits` | float32 `[4,11,24]` | Use rows 0–1; token 0 blank, tokens 1–10 digits 0–9 | | `fills` | float32 `[4]` | Use rows 2–3, sigmoid fraction × 100 | | `counts` | float32 `[4,3]` | Use rows 0–1; argmax + 1 is predicted digit count | ImageNet mean/std normalization is **inside the graph**; do not apply it twice. The full-frame crop rectangles are half-open pixel coordinates: | Field | `[left, top, right, bottom]` | Transform | |---|---|---| | Gear | `[1399,1010,1475,1079]` | Keep aspect ratio, black center padding | | Counter | `[408,994,479,1044]` | Keep aspect ratio, black center padding | | Brake | `[956,628,999,894]` | Rotate clockwise 90°, then resize | | Throttle | `[1011,628,1055,894]` | Rotate clockwise 90°, then resize | Resize with Pillow RGB **BILINEAR**, including its antialiased reduction and uint8 rounding between passes. All crops finish at 192×64. This is not generally equivalent to arbitrary OpenCV/Qt resize defaults or a float-only resize pipeline. Decode digits with CTC prefix beam search, **beam width 10 separately per prefix length**, constrained to `argmax(counts)+1`. Preserve repeated-digit blank transitions and stable ties. Do not replace it with greedy argmax, force a gear vocabulary, infer counters from elapsed time, or smooth a missing observation into a value. One to three decoded digits become an integer; leading zeros follow ordinary integer conversion. Reject nonfinite outputs. ## Admission and limitations Admission is an independent image-structure heuristic in the example/native runtime. It requires all of the reviewed red/green vertical columns, their narrow edges, two separated orange/brown horizontal scale tracks and sparse bright scale marks at known source coordinates. It does not inspect filenames, driver/team logos, native telemetry, prior values, or model confidence. A digit crop also needs visible bright-glyph evidence; an erased digit can remain unknown even when the layout is supported. Limits are deliberate and important: - Other geometries, skins, moved/mirrored overlays, display captures, colour shifts, occlusion or unfamiliar compression may be rejected even when a HUD is visible. - An unrelated or synthetic image reproducing the anchor structure can pass. Broad independent no-HUD false-positive rates have **not** been established. - Glyph presence is only a blank-crop guard. Non-digit glyphs, partial occlusion, unfamiliar fonts and familiar-looking unsupported layouts can still be misread. - There is no general detector, calibrated confidence, speed/GPS/steering reader, physical-pressure calibration, driver identification or reliable lap classifier. - This is an analysis aid, not a safety-critical control input. Check the original pixels and native logger when decisions depend on correctness. ## Training provenance and validation The task-specific model was trained on **private, reviewed racing-HUD crops**, initialized from the Apache-2.0 timm [`mobilenetv3_small_100.lamb_in1k`](https://huggingface.co/timm/mobilenetv3_small_100.lamb_in1k) backbone, which was pretrained on ImageNet-1k. Training footage, screenshots, labels, recordings, source identifiers and `.pt` checkpoints are not included. This release does not provide a public training dataset or independent public accuracy benchmark. The export script is available in Omatrack for owners of the checkpoint; ordinary inference needs only this public ONNX file and example. Validation is **implementation/export parity**, not new gold pixel accuracy: - On 19 local real frames across three recordings, all 76 crop byte arrays matched the reviewed Pillow preprocessing. Native and example digit outputs matched the reference decoder; maximum visible-fill difference was about **0.0000179 percentage points**. - PyTorch/ONNX maximum absolute output differences were `5.913e-5` for digit logits, `1.788e-7` for fill fractions and `1.907e-5` for count logits. - Count-constrained decoding passed 36 synthetic/reference oracle cases, including repeated digits, ties and one/two/three-digit counts. - Blank/noise tests and 76 transformed real-scene negatives were rejected. Those transforms are **not** an independent broad no-HUD-video benchmark. - On a Neoverse-V2 CPU with one ONNX Runtime CPU thread, native C++ warm `read()` latency was approximately **2.61 ms median / 3.00 ms p95** over 38 timed samples. This excludes model load and video decoding. The Python example measured roughly **5.4 ms median / 7.1 ms p95** on the 19-frame local check. These are not end-to-end video FPS guarantees or measurements of other CPUs. The private validation inputs and actual reading examples are intentionally not published. `test_read_frame.py` contains only generated public arrays and tests. ## Licensing and notices **The license for the new task-specific model weights is not yet specified.** Public availability is not a blanket license grant for those new weights. No MIT or Apache-2.0 license is assigned to the task-specific weights by this model card. The upstream timm/MobileNetV3 component retains its **Apache-2.0** license and attribution; see `NOTICE` and `LICENSE-APACHE-2.0-UPSTREAM.txt`. Omatrack-derived example source code is separately **MIT**; see `LICENSE-MIT-OMATRACK-CODE.txt`. These scoped notices are not a license assignment to the new model as a whole. No rights to private training footage, screenshots or datasets are granted. AiM, MobileNetV3, timm and Hugging Face names identify compatibility/provenance; no endorsement or affiliation is implied.