scorevision: push artifact
Browse files
miner.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
-
"""ScoreVision crime detector — YOLOv11s
|
|
|
|
| 2 |
from pathlib import Path
|
| 3 |
import math
|
| 4 |
|
|
@@ -33,9 +34,9 @@ class Miner:
|
|
| 33 |
cross_iou_thresh = 0.50
|
| 34 |
max_aspect_ratio = 10.0
|
| 35 |
max_det = 150
|
| 36 |
-
# tuned on
|
| 37 |
_conf_thres_array = np.array(
|
| 38 |
-
[0.
|
| 39 |
)
|
| 40 |
|
| 41 |
def __init__(self, path_hf_repo: Path) -> None:
|
|
@@ -167,7 +168,6 @@ class Miner:
|
|
| 167 |
return np.array(keep_all, dtype=np.intp)
|
| 168 |
|
| 169 |
def _cross_class_dedup(self, boxes, scores, cls_ids, iou_thr):
|
| 170 |
-
"""If two boxes (any class) heavily overlap, keep only the higher-scoring one."""
|
| 171 |
n = len(boxes)
|
| 172 |
if n == 0:
|
| 173 |
return np.array([], dtype=np.intp)
|
|
@@ -211,7 +211,6 @@ class Miner:
|
|
| 211 |
|
| 212 |
def _decode(self, preds: ndarray, ratio: float, pad: tuple[float, float],
|
| 213 |
orig_size: tuple[int, int]) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
| 214 |
-
"""ONNX output is [1,300,6]: x1,y1,x2,y2,conf,cls in letterboxed coords."""
|
| 215 |
if preds.ndim == 3 and preds.shape[0] == 1:
|
| 216 |
preds = preds[0]
|
| 217 |
if preds.ndim != 2 or preds.shape[1] < 6:
|
|
@@ -223,18 +222,15 @@ class Miner:
|
|
| 223 |
boxes = preds[:, :4].astype(np.float32)
|
| 224 |
scores = preds[:, 4].astype(np.float32)
|
| 225 |
cls_ids = preds[:, 5].astype(np.int32)
|
| 226 |
-
# drop padded rows
|
| 227 |
keep = (scores > 0) & (cls_ids >= 0) & (cls_ids < len(self.class_names))
|
| 228 |
boxes, scores, cls_ids = boxes[keep], scores[keep], cls_ids[keep]
|
| 229 |
if len(boxes) == 0:
|
| 230 |
return boxes, scores, cls_ids
|
| 231 |
-
# per-class confidence
|
| 232 |
thr = self._conf_thres_array[cls_ids]
|
| 233 |
keep = scores >= thr
|
| 234 |
boxes, scores, cls_ids = boxes[keep], scores[keep], cls_ids[keep]
|
| 235 |
if len(boxes) == 0:
|
| 236 |
return boxes, scores, cls_ids
|
| 237 |
-
# untransform: subtract pad, divide ratio
|
| 238 |
pad_w, pad_h = pad
|
| 239 |
boxes[:, [0, 2]] -= pad_w
|
| 240 |
boxes[:, [1, 3]] -= pad_h
|
|
@@ -262,7 +258,6 @@ class Miner:
|
|
| 262 |
cls_ids = np.concatenate([c0, cf], axis=0) if len(b0) or len(bf) else c0
|
| 263 |
if len(boxes) == 0:
|
| 264 |
return []
|
| 265 |
-
# filter + per-class NMS + cross-class dedup
|
| 266 |
boxes, scores, cls_ids = self._filter_sane(
|
| 267 |
boxes, scores, cls_ids, (image.shape[1], image.shape[0])
|
| 268 |
)
|
|
|
|
| 1 |
+
"""ScoreVision crime detector v24 — YOLOv11s trained on rival-consensus labels.
|
| 2 |
+
Per-class conf thresholds tuned vs validator-PGT proxy; flip TTA; cross-class NMS."""
|
| 3 |
from pathlib import Path
|
| 4 |
import math
|
| 5 |
|
|
|
|
| 34 |
cross_iou_thresh = 0.50
|
| 35 |
max_aspect_ratio = 10.0
|
| 36 |
max_det = 150
|
| 37 |
+
# per-class thresholds — tuned on rival-consensus GT (proxy for validator PGT)
|
| 38 |
_conf_thres_array = np.array(
|
| 39 |
+
[0.30, 0.70, 0.60, 0.50, 0.40, 0.40], dtype=np.float32
|
| 40 |
)
|
| 41 |
|
| 42 |
def __init__(self, path_hf_repo: Path) -> None:
|
|
|
|
| 168 |
return np.array(keep_all, dtype=np.intp)
|
| 169 |
|
| 170 |
def _cross_class_dedup(self, boxes, scores, cls_ids, iou_thr):
|
|
|
|
| 171 |
n = len(boxes)
|
| 172 |
if n == 0:
|
| 173 |
return np.array([], dtype=np.intp)
|
|
|
|
| 211 |
|
| 212 |
def _decode(self, preds: ndarray, ratio: float, pad: tuple[float, float],
|
| 213 |
orig_size: tuple[int, int]) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
|
|
| 214 |
if preds.ndim == 3 and preds.shape[0] == 1:
|
| 215 |
preds = preds[0]
|
| 216 |
if preds.ndim != 2 or preds.shape[1] < 6:
|
|
|
|
| 222 |
boxes = preds[:, :4].astype(np.float32)
|
| 223 |
scores = preds[:, 4].astype(np.float32)
|
| 224 |
cls_ids = preds[:, 5].astype(np.int32)
|
|
|
|
| 225 |
keep = (scores > 0) & (cls_ids >= 0) & (cls_ids < len(self.class_names))
|
| 226 |
boxes, scores, cls_ids = boxes[keep], scores[keep], cls_ids[keep]
|
| 227 |
if len(boxes) == 0:
|
| 228 |
return boxes, scores, cls_ids
|
|
|
|
| 229 |
thr = self._conf_thres_array[cls_ids]
|
| 230 |
keep = scores >= thr
|
| 231 |
boxes, scores, cls_ids = boxes[keep], scores[keep], cls_ids[keep]
|
| 232 |
if len(boxes) == 0:
|
| 233 |
return boxes, scores, cls_ids
|
|
|
|
| 234 |
pad_w, pad_h = pad
|
| 235 |
boxes[:, [0, 2]] -= pad_w
|
| 236 |
boxes[:, [1, 3]] -= pad_h
|
|
|
|
| 258 |
cls_ids = np.concatenate([c0, cf], axis=0) if len(b0) or len(bf) else c0
|
| 259 |
if len(boxes) == 0:
|
| 260 |
return []
|
|
|
|
| 261 |
boxes, scores, cls_ids = self._filter_sane(
|
| 262 |
boxes, scores, cls_ids, (image.shape[1], image.shape[0])
|
| 263 |
)
|