πŸƒ Saudi Baloot Dense Fanned Hand Card Detector (baloot-fan-v2)

baloot-fan-v2 is a specialized object detection model based on YOLO11n, trained to recognize 32 Saudi Baloot playing cards (ranks A, K, Q, J, 10, 9, 8, 7 across all 4 suits) plus 1 other class (ranks 2–6) in dense, overlapping fanned hands held by players under realistic occlusion, finger shadows, and camera tilt.

Part of the open-source Hakim Vision (AIBaloot) project.


πŸ“Š Model Summary & Performance

  • Model Architecture: YOLO11n (Ultralytics)
  • Input Resolution: 704 Γ— 704 px (Stretch resized)
  • Target Environments: WebGPU (FP16) via onnxruntime-web, WASM INT8 CPU fallback, native PyTorch / ONNX Runtime.

Evaluation Metrics (Holdout Validation Set at 704Γ—704)

Metric Value
Precision 98.26%
Recall 94.04%
mAP@50 98.72%
mAP@50-95 95.81%

Latency Benchmarks

Format File Size Runtime Target Latency
FP16 ONNX 5.1 MB WebGPU (iOS Safari 26+, Chrome 113+) ~20–40 ms
INT8 ONNX 3.16 MB WebAssembly (CPU fallback) ~110–220 ms
PyTorch (best.pt) 5.3 MB Native GPU (RTX 2080 Ti / CUDA) ~3–5 ms

🏷️ 33 Detection Classes (Baloot Ontology)

The model detects corner-index bounding boxes for the 32 cards used in Saudi Baloot, mapping all irrelevant ranks (2–6) into class 32 (other):

 0: Ah   1: Kh   2: Qh   3: Jh   4: 10h  5: 9h   6: 8h   7: 7h  (Hearts β™₯)
 8: Ad   9: Kd  10: Qd  11: Jd  12: 10d 13: 9d  14: 8d  15: 7d  (Diamonds ♦)
16: Ac  17: Kc  18: Qc  19: Jc  20: 10c 21: 9c  22: 8c  23: 7c  (Clubs ♣)
24: As  25: Ks  26: Qs  27: Js  28: 10s 29: 9s  30: 8s  31: 7s  (Spades β™ )
32: other (Ranks 2–6, non-Baloot cards)

πŸš€ How to Use

1. PyTorch (ultralytics)

from ultralytics import YOLO

# Load PyTorch weights
model = YOLO("best.pt")

# Predict on an image
results = model.predict("player_hand.jpg", imgsz=704, conf=0.35)

# Render results
for result in results:
    result.show()

2. ONNX Runtime (Python)

import cv2
import numpy as np
import onnxruntime as ort

# Load ONNX model
session = ort.InferenceSession("baloot-fan-v2.fp16.onnx", providers=["CUDAExecutionProvider", "CPUExecutionProvider"])

# Preprocess image (Stretch resize to 704x704)
img = cv2.imread("player_hand.jpg")
img_resized = cv2.resize(img, (704, 704))
input_tensor = (img_resized.astype(np.float32) / 255.0).transpose((2, 0, 1))[np.newaxis, ...]

# Run inference
outputs = session.run(None, {session.get_inputs()[0].name: input_tensor})

3. In-Browser WebGPU (onnxruntime-web)

import * as ort from 'onnxruntime-web/webgpu';

// Load FP16 ONNX model with WebGPU EP
const session = await ort.InferenceSession.create('./baloot-fan-v2.fp16.onnx', {
  executionProviders: ['webgpu']
});

// Run inference on WebGPU
const feeds = { images: inputTensor };
const results = await session.run(feeds);

πŸ› οΈ Quantization & WebGPU Constraints

  • Static INT8 PTQ: Quantized using MinMax calibration on representative hand composites. reduce_range=True was applied to prevent activation overflow on CPU SIMD targets.
  • Decode Tail Excluded: Detection head outputs combine [0, 704] coordinate spaces with [0, 1] probabilities, so the decoding tail is preserved in FP16/FP32 to maintain score precision.

πŸ“œ Citation & License

Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Dataset used to train osos3lom/baloot-fan-v2

Evaluation results

  • mAP@50 on Saudi Baloot Fanned Cards Holdout Set
    self-reported
    0.987
  • mAP@50-95 on Saudi Baloot Fanned Cards Holdout Set
    self-reported
    0.958
  • precision on Saudi Baloot Fanned Cards Holdout Set
    self-reported
    0.983
  • recall on Saudi Baloot Fanned Cards Holdout Set
    self-reported
    0.940