Download miner.py from liberoaphpollo/ScoreVision: direct link, hf CLI and curl.
- Browser
- Download file 6.07 kB
-
https://huggingface.co/liberoaphpollo/ScoreVision/resolve/main/miner.py
- Command line
-
hf download hf://liberoaphpollo/ScoreVision/miner.py
-
curl -L -o miner.py https://huggingface.co/liberoaphpollo/ScoreVision/resolve/main/miner.py
6.07 kB
| """SN44 TurboVision public-track miner for a raw YOLO head (the owner's element_trainer baselines: YOLO11n, detect or | |
| seg, output [1, 4 + NC (+ mask coefficients), N]), decoded exactly as the owner's own baseline miner decodes it. | |
| The validator hands predict_batch OpenCV BGR uint8 frames. Each frame is converted to RGB, resized (plain stretch, no | |
| letterbox) to the model's input size, scaled to 0..1, and run on the CPU with 2 threads. Per anchor: the arg-max of the | |
| NC class scores (mask coefficients ignored), kept when it reaches CONF; one class-agnostic greedy NMS at IOU over all | |
| kept boxes; boxes mapped back by the stretch factors, floored / ceiled to whole pixels and clipped to the frame. | |
| CLASS_MAP maps the model's classes to the element's `objects` indices (-1 drops a class; empty: the same order). | |
| """ | |
| import math | |
| from pathlib import Path | |
| import cv2 | |
| import numpy as np | |
| import onnxruntime as ort | |
| from numpy import ndarray | |
| from pydantic import BaseModel | |
| MODEL_FILE = "model.onnx" | |
| NC = 5 | |
| CONF = 0.25 | |
| IOU = 0.45 | |
| THREADS = 2 | |
| CLASS_MAP = () | |
| WARMUP_RUNS = 3 | |
| class BoundingBox(BaseModel): | |
| x1: int | |
| y1: int | |
| x2: int | |
| y2: int | |
| cls_id: int | |
| conf: float | |
| class Polygon(BaseModel): | |
| cls_id: int | |
| conf: float | |
| points: list[tuple[int, int]] | |
| class TVFrameResult(BaseModel): | |
| frame_id: int | |
| boxes: list[BoundingBox] | None = None | |
| polygons: list[Polygon] | None = None | |
| keypoints: list[tuple[int, int]] | None = None | |
| def _as_bgr(img) -> ndarray: | |
| if not isinstance(img, np.ndarray) or img.ndim not in (2, 3) or img.size == 0: | |
| raise ValueError(f"unsupported frame: {type(img).__name__} {getattr(img, 'shape', None)}") | |
| if img.dtype != np.uint8: | |
| img = np.clip(np.nan_to_num(img), 0, 255).astype(np.uint8) | |
| if img.ndim == 2 or img.shape[2] == 1: | |
| return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) | |
| if img.shape[2] == 4: | |
| return cv2.cvtColor(img, cv2.COLOR_BGRA2BGR) | |
| return img | |
| def _nms(boxes: ndarray, scores: ndarray, iou_thr: float) -> list[int]: | |
| order = scores.argsort()[::-1] | |
| keep = [] | |
| while order.size > 0: | |
| i = order[0] | |
| keep.append(int(i)) | |
| rest = order[1:] | |
| xx1 = np.maximum(boxes[i, 0], boxes[rest, 0]) | |
| yy1 = np.maximum(boxes[i, 1], boxes[rest, 1]) | |
| xx2 = np.minimum(boxes[i, 2], boxes[rest, 2]) | |
| yy2 = np.minimum(boxes[i, 3], boxes[rest, 3]) | |
| inter = np.maximum(0.0, xx2 - xx1) * np.maximum(0.0, yy2 - yy1) | |
| area_i = (boxes[i, 2] - boxes[i, 0]) * (boxes[i, 3] - boxes[i, 1]) | |
| area_r = (boxes[rest, 2] - boxes[rest, 0]) * (boxes[rest, 3] - boxes[rest, 1]) | |
| iou = inter / np.maximum(area_i + area_r - inter, 1e-6) | |
| order = rest[np.where(iou <= iou_thr)[0]] | |
| return keep | |
| class Miner: | |
| def __init__(self, path_hf_repo: Path) -> None: | |
| so = ort.SessionOptions() | |
| so.intra_op_num_threads = THREADS | |
| so.inter_op_num_threads = 1 | |
| so.execution_mode = ort.ExecutionMode.ORT_SEQUENTIAL | |
| so.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL | |
| so.add_session_config_entry("session.intra_op.allow_spinning", "0") | |
| cv2.setNumThreads(1) | |
| self.session = ort.InferenceSession(str(Path(path_hf_repo) / MODEL_FILE), sess_options=so, | |
| providers=["CPUExecutionProvider"]) | |
| inp = self.session.get_inputs()[0] | |
| self.input_name = inp.name | |
| self.in_h, self.in_w = int(inp.shape[2]), int(inp.shape[3]) | |
| dummy = np.zeros((1024, 1024, 3), np.uint8) | |
| for _ in range(WARMUP_RUNS): | |
| self._frame_boxes(dummy) | |
| def __repr__(self) -> str: | |
| return f"{MODEL_FILE} @ {self.in_w}x{self.in_h} stretch, CPU {THREADS} threads, conf {CONF}, agnostic NMS {IOU}" | |
| def _frame_boxes(self, img) -> list[BoundingBox]: | |
| img = _as_bgr(img) | |
| h, w = img.shape[:2] | |
| rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) | |
| x = cv2.resize(rgb, (self.in_w, self.in_h)).astype(np.float32) / 255.0 | |
| x = np.ascontiguousarray(np.transpose(x, (2, 0, 1))[None]) | |
| pred = self.session.run(None, {self.input_name: x})[0][0] | |
| if pred.shape[0] < pred.shape[1]: | |
| pred = pred.T | |
| scores = pred[:, 4:4 + NC] | |
| cls = scores.argmax(1) | |
| conf = scores.max(1) | |
| m = np.isfinite(pred[:, :4]).all(1) & (conf >= CONF) | |
| b, cls, conf = pred[m, :4], cls[m], conf[m] | |
| if b.shape[0] == 0: | |
| return [] | |
| sx, sy = w / float(self.in_w), h / float(self.in_h) | |
| xyxy = np.stack([(b[:, 0] - b[:, 2] / 2) * sx, (b[:, 1] - b[:, 3] / 2) * sy, | |
| (b[:, 0] + b[:, 2] / 2) * sx, (b[:, 1] + b[:, 3] / 2) * sy], 1) | |
| boxes = [] | |
| for i in _nms(xyxy, conf, IOU): | |
| c = int(cls[i]) | |
| if CLASS_MAP: | |
| if c >= len(CLASS_MAP) or CLASS_MAP[c] < 0: | |
| continue | |
| c = CLASS_MAP[c] | |
| x1, y1, x2, y2 = xyxy[i] | |
| ix1, iy1 = max(0, min(w, math.floor(x1))), max(0, min(h, math.floor(y1))) | |
| ix2, iy2 = max(0, min(w, math.ceil(x2))), max(0, min(h, math.ceil(y2))) | |
| if ix2 - ix1 < 1 or iy2 - iy1 < 1: | |
| continue | |
| boxes.append(BoundingBox(x1=ix1, y1=iy1, x2=ix2, y2=iy2, cls_id=c, conf=float(max(0.0, min(1.0, conf[i]))))) | |
| return boxes | |
| def predict_batch(self, batch_images: list[ndarray], offset: int, n_keypoints: int) -> list[TVFrameResult]: | |
| results: list[TVFrameResult] = [] | |
| for i, img in enumerate(batch_images): | |
| try: | |
| boxes = self._frame_boxes(img) | |
| except Exception as exc: # one bad frame must not fail the whole challenge | |
| print(f"inference_failure frame {offset + i}: {type(exc).__name__}: {exc}") | |
| boxes = [] | |
| results.append(TVFrameResult(frame_id=offset + i, boxes=boxes, polygons=[], | |
| keypoints=[(0, 0)] * int(n_keypoints) if n_keypoints else [])) | |
| return results | |