scorevision: push artifact
Browse files
miner.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
"""
|
| 2 |
-
Detect-
|
| 3 |
|
| 4 |
Loaded by the TurboVision chute_template from the root of the HF repo.
|
| 5 |
Thresholds (imgsz, conf, iou, max_det) are overridable via SN44_* env vars
|
|
@@ -8,6 +8,10 @@ so operators can hot-patch without redeploying.
|
|
| 8 |
Contract expected by the chute template:
|
| 9 |
* class `Miner(path_hf_repo: Path)`
|
| 10 |
* method `predict_batch(batch_images, offset, n_keypoints) -> list[TVFrameResult]`
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
"""
|
| 12 |
|
| 13 |
from __future__ import annotations
|
|
@@ -136,10 +140,18 @@ def _clip_boxes(boxes: np.ndarray, image_size: tuple[int, int]) -> np.ndarray:
|
|
| 136 |
|
| 137 |
|
| 138 |
class Miner:
|
| 139 |
-
"""Detect-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
|
| 141 |
def __init__(self, path_hf_repo: Path) -> None:
|
| 142 |
-
self.class_names = ["
|
|
|
|
|
|
|
| 143 |
|
| 144 |
weights_name = os.environ.get("SN44_ONNX_WEIGHTS", _DEFAULT_WEIGHTS)
|
| 145 |
weights_path = path_hf_repo / weights_name
|
|
@@ -199,21 +211,21 @@ class Miner:
|
|
| 199 |
self.max_aspect_ratio = 8.0
|
| 200 |
self.max_box_area_ratio = 0.9
|
| 201 |
|
| 202 |
-
self.person_cls_idx = 0
|
| 203 |
-
|
| 204 |
print(
|
| 205 |
-
"Miner ready: "
|
| 206 |
f"imgsz={self.input_height}x{self.input_width}, "
|
| 207 |
f"conf={self.conf_thres:.3f}, iou={self.iou_thres:.3f}, "
|
| 208 |
-
f"max_det={self.max_det}, providers={self.session.get_providers()}"
|
|
|
|
| 209 |
)
|
| 210 |
|
| 211 |
def __repr__(self) -> str:
|
| 212 |
return (
|
| 213 |
-
"
|
| 214 |
f"providers={self.session.get_providers()}, "
|
| 215 |
f"imgsz={self.input_height}x{self.input_width}, "
|
| 216 |
-
f"conf={self.conf_thres}, iou={self.iou_thres}
|
|
|
|
| 217 |
)
|
| 218 |
|
| 219 |
def _preprocess(
|
|
@@ -294,13 +306,16 @@ class Miner:
|
|
| 294 |
boxes_xywh = preds[:, :4].astype(np.float32)
|
| 295 |
class_scores = preds[:, 4:].astype(np.float32)
|
| 296 |
|
| 297 |
-
|
| 298 |
-
|
|
|
|
|
|
|
|
|
|
| 299 |
if not np.any(mask):
|
| 300 |
return []
|
| 301 |
|
| 302 |
boxes_xywh = boxes_xywh[mask]
|
| 303 |
-
scores =
|
| 304 |
|
| 305 |
boxes = _xywh_to_xyxy(boxes_xywh)
|
| 306 |
|
|
|
|
| 1 |
"""
|
| 2 |
+
Detect-vehicle miner for ScoreVision.
|
| 3 |
|
| 4 |
Loaded by the TurboVision chute_template from the root of the HF repo.
|
| 5 |
Thresholds (imgsz, conf, iou, max_det) are overridable via SN44_* env vars
|
|
|
|
| 8 |
Contract expected by the chute template:
|
| 9 |
* class `Miner(path_hf_repo: Path)`
|
| 10 |
* method `predict_batch(batch_images, offset, n_keypoints) -> list[TVFrameResult]`
|
| 11 |
+
|
| 12 |
+
Vehicle classes filtered from COCO 80-class: car(2), motorcycle(3), bus(5), truck(7).
|
| 13 |
+
cls_id is REMAPPED to 0 in the output because the ScoreVision validator
|
| 14 |
+
treats class-0 as the single target class per element.
|
| 15 |
"""
|
| 16 |
|
| 17 |
from __future__ import annotations
|
|
|
|
| 140 |
|
| 141 |
|
| 142 |
class Miner:
|
| 143 |
+
"""Detect-vehicle miner: ONNX Runtime + raw YOLO decode + numpy NMS.
|
| 144 |
+
|
| 145 |
+
Same yolo11s_fp16 backbone as the Detect-Person miner; inference path is
|
| 146 |
+
unchanged. The ONLY difference is class filtering: we keep COCO classes
|
| 147 |
+
{car=2, motorcycle=3, bus=5, truck=7} and merge them into a single
|
| 148 |
+
emitted class_id=0 per the validator's single-target convention.
|
| 149 |
+
"""
|
| 150 |
|
| 151 |
def __init__(self, path_hf_repo: Path) -> None:
|
| 152 |
+
self.class_names = ["vehicle"]
|
| 153 |
+
# COCO class indices we keep:
|
| 154 |
+
self.vehicle_coco_ids = (2, 3, 5, 7) # car, motorcycle, bus, truck
|
| 155 |
|
| 156 |
weights_name = os.environ.get("SN44_ONNX_WEIGHTS", _DEFAULT_WEIGHTS)
|
| 157 |
weights_path = path_hf_repo / weights_name
|
|
|
|
| 211 |
self.max_aspect_ratio = 8.0
|
| 212 |
self.max_box_area_ratio = 0.9
|
| 213 |
|
|
|
|
|
|
|
| 214 |
print(
|
| 215 |
+
"Vehicle Miner ready: "
|
| 216 |
f"imgsz={self.input_height}x{self.input_width}, "
|
| 217 |
f"conf={self.conf_thres:.3f}, iou={self.iou_thres:.3f}, "
|
| 218 |
+
f"max_det={self.max_det}, providers={self.session.get_providers()}, "
|
| 219 |
+
f"coco_ids={self.vehicle_coco_ids}"
|
| 220 |
)
|
| 221 |
|
| 222 |
def __repr__(self) -> str:
|
| 223 |
return (
|
| 224 |
+
"DetectVehicleMiner("
|
| 225 |
f"providers={self.session.get_providers()}, "
|
| 226 |
f"imgsz={self.input_height}x{self.input_width}, "
|
| 227 |
+
f"conf={self.conf_thres}, iou={self.iou_thres}, "
|
| 228 |
+
f"coco_ids={self.vehicle_coco_ids})"
|
| 229 |
)
|
| 230 |
|
| 231 |
def _preprocess(
|
|
|
|
| 306 |
boxes_xywh = preds[:, :4].astype(np.float32)
|
| 307 |
class_scores = preds[:, 4:].astype(np.float32)
|
| 308 |
|
| 309 |
+
# For each detection keep MAX confidence across the vehicle classes.
|
| 310 |
+
vehicle_idx = np.array(self.vehicle_coco_ids, dtype=np.intp)
|
| 311 |
+
vehicle_scores_all = class_scores[:, vehicle_idx]
|
| 312 |
+
vehicle_scores = vehicle_scores_all.max(axis=1)
|
| 313 |
+
mask = vehicle_scores >= self.conf_thres
|
| 314 |
if not np.any(mask):
|
| 315 |
return []
|
| 316 |
|
| 317 |
boxes_xywh = boxes_xywh[mask]
|
| 318 |
+
scores = vehicle_scores[mask]
|
| 319 |
|
| 320 |
boxes = _xywh_to_xyxy(boxes_xywh)
|
| 321 |
|