meaculpitt commited on
Commit
6c8fdd5
·
verified ·
1 Parent(s): 37a6d98

scorevision: push artifact

Browse files
Files changed (6) hide show
  1. README.md +20 -25
  2. __pycache__/miner.cpython-312.pyc +0 -0
  3. class_names.txt +0 -79
  4. miner.py +62 -76
  5. model_type.json +1 -1
  6. weights.onnx +2 -2
README.md CHANGED
@@ -1,13 +1,14 @@
1
  ---
2
  tags:
3
  - element_type:detect
4
- - model:yolov11-small
5
- - object:vehicle
6
  manako:
7
  description: >
8
- YOLO11s vehicle detector fine-tuned on COCO vehicles + BDD100K + VisDrone.
9
- FP16 ONNX, 1280x1280 input. Trained R6: 59,870 images, 50 epochs.
10
- source: meaculpitt/Detect-Vehicle
 
11
  prompt_hints: null
12
  input_payload:
13
  - name: frame
@@ -16,32 +17,26 @@ manako:
16
  output_payload:
17
  - name: detections
18
  type: detections
19
- description: Bounding boxes for detected vehicles
20
- evaluation_score: 0.7701
21
  last_benchmark:
22
- type: visdrone_val
23
- ran_at: 2026-03-25T17:34:00+00:00
24
  result_path: null
25
  ---
26
 
27
- # Detect-Vehicle — SN44
28
 
29
- YOLO11s fine-tuned for vehicle detection (car, bus, truck, motorcycle).
30
 
31
  | Metric | Value |
32
  |--------|-------|
33
- | mAP@50 | 77.01% |
34
- | Model | YOLO11s (FP16 ONNX) |
35
- | Input size | 1280x1280 |
36
- | Model size | 19.2 MB |
37
- | Training data | COCO vehicles + BDD100K + VisDrone (59,870 images) |
38
- | Baseline to beat | 40.72% |
39
 
40
- ## Classes
41
-
42
- | Output ID | Class |
43
- |-----------|-------|
44
- | 0 | car |
45
- | 1 | bus |
46
- | 2 | truck |
47
- | 3 | motorcycle |
 
1
  ---
2
  tags:
3
  - element_type:detect
4
+ - model:yolov11-nano
5
+ - object:person
6
  manako:
7
  description: >
8
+ YOLOv11-nano fine-tuned for ground-level CCTV person detection on SN44.
9
+ Trained on CrowdHuman (15k, dense crowds) + BDD100K street pedestrians.
10
+ Conf threshold raised to 0.35 to minimise false positives.
11
+ source: meaculpitt/Detect-Person
12
  prompt_hints: null
13
  input_payload:
14
  - name: frame
 
17
  output_payload:
18
  - name: detections
19
  type: detections
20
+ description: Bounding boxes for detected persons
21
+ evaluation_score: 0.5563
22
  last_benchmark:
23
+ type: coco_val2017
24
+ ran_at: '2026-03-25T02:58:57+00:00'
25
  result_path: null
26
  ---
27
 
28
+ # Detect-Person — SN44
29
 
30
+ YOLOv11-nano fine-tuned for ground-level CCTV person detection.
31
 
32
  | Metric | Value |
33
  |--------|-------|
34
+ | mAP@50 (COCO val2017) | 55.63% |
35
+ | Precision (conf=0.35) | 56.86% |
36
+ | Recall | 50.67% |
37
+ | Baseline to beat | 37.55% |
38
+ | Model size | 5.6 MB |
39
+ | Input size | 1280×1280 |
40
 
41
+ **Training data**: CrowdHuman (15k) + BDD100K (3.2k pedestrians)
42
+ **Validation**: COCO val2017 persons (2,693 images)
 
 
 
 
 
 
__pycache__/miner.cpython-312.pyc CHANGED
Binary files a/__pycache__/miner.cpython-312.pyc and b/__pycache__/miner.cpython-312.pyc differ
 
class_names.txt CHANGED
@@ -1,80 +1 @@
1
  person
2
- bicycle
3
- car
4
- motorcycle
5
- airplane
6
- bus
7
- train
8
- truck
9
- boat
10
- traffic light
11
- fire hydrant
12
- stop sign
13
- parking meter
14
- bench
15
- bird
16
- cat
17
- dog
18
- horse
19
- sheep
20
- cow
21
- elephant
22
- bear
23
- zebra
24
- giraffe
25
- backpack
26
- umbrella
27
- handbag
28
- tie
29
- suitcase
30
- frisbee
31
- skis
32
- snowboard
33
- sports ball
34
- kite
35
- baseball bat
36
- baseball glove
37
- skateboard
38
- surfboard
39
- tennis racket
40
- bottle
41
- wine glass
42
- cup
43
- fork
44
- knife
45
- spoon
46
- bowl
47
- banana
48
- apple
49
- sandwich
50
- orange
51
- broccoli
52
- carrot
53
- hot dog
54
- pizza
55
- donut
56
- cake
57
- chair
58
- couch
59
- potted plant
60
- bed
61
- dining table
62
- toilet
63
- tv
64
- laptop
65
- mouse
66
- remote
67
- keyboard
68
- cell phone
69
- microwave
70
- oven
71
- toaster
72
- sink
73
- refrigerator
74
- book
75
- clock
76
- vase
77
- scissors
78
- teddy bear
79
- hair drier
80
- toothbrush
 
1
  person
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
miner.py CHANGED
@@ -1,12 +1,7 @@
1
  """
2
- Score Vision SN44 — VehicleDetect miner. v3 (2026-03-26).
3
- Single-pass + NMS. Letterbox preprocessing.
4
-
5
- Model: YOLO11s ONNX, 4 classes trained as:
6
- 0 = car, 1 = bus, 2 = truck, 3 = motorcycle
7
-
8
- Official submission order (remapped in MODEL_TO_OUT):
9
- 0 = bus, 1 = car, 2 = truck, 3 = motorcycle
10
  """
11
 
12
  from pathlib import Path
@@ -17,14 +12,6 @@ import numpy as np
17
  import onnxruntime as ort
18
  from numpy import ndarray
19
  from pydantic import BaseModel
20
- # ── Model class index → submission class index ───────────────────────────────
21
- MODEL_TO_OUT: dict[int, int] = {0: 1, 1: 0, 2: 2, 3: 3}
22
- OUT_TO_MODEL: dict[int, int] = {v: k for k, v in MODEL_TO_OUT.items()}
23
- OUT_NAMES = ["bus", "car", "truck", "motorcycle"]
24
-
25
- IMG_SIZE = 1280
26
- CONF_THRESH = 0.55
27
- IOU_THRESH = 0.45
28
 
29
 
30
  class BoundingBox(BaseModel):
@@ -45,83 +32,79 @@ class TVFrameResult(BaseModel):
45
  class Miner:
46
  def __init__(self, path_hf_repo: Path) -> None:
47
  self.path_hf_repo = path_hf_repo
 
48
  self.session = ort.InferenceSession(
49
  str(path_hf_repo / "weights.onnx"),
50
  providers=["CUDAExecutionProvider", "CPUExecutionProvider"],
51
  )
52
  self.input_name = self.session.get_inputs()[0].name
53
- self.conf_threshold = CONF_THRESH
54
- self.iou_threshold = IOU_THRESH
 
 
 
55
 
56
  def __repr__(self) -> str:
57
- return f"VehicleDetect Miner v4 NMS session={type(self.session).__name__}"
58
-
59
- def _letterbox(self, img: ndarray) -> tuple[np.ndarray, float, int, int]:
60
- h, w = img.shape[:2]
61
- r = min(IMG_SIZE / h, IMG_SIZE / w)
62
- new_w, new_h = int(round(w * r)), int(round(h * r))
63
- img_r = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_LINEAR)
64
- dw, dh = IMG_SIZE - new_w, IMG_SIZE - new_h
65
- pad_l, pad_t = dw // 2, dh // 2
66
- img_p = cv2.copyMakeBorder(
67
- img_r, pad_t, dh - pad_t, pad_l, dw - pad_l,
68
- cv2.BORDER_CONSTANT, value=(114, 114, 114),
69
- )
70
- return img_p, r, pad_l, pad_t
71
-
72
- def _preprocess(self, image_bgr: ndarray) -> tuple[np.ndarray, float, int, int]:
73
- img_p, ratio, pad_l, pad_t = self._letterbox(image_bgr)
74
- img_rgb = cv2.cvtColor(img_p, cv2.COLOR_BGR2RGB)
75
- inp = img_rgb.astype(np.float32) / 255.0
76
- inp = np.ascontiguousarray(inp.transpose(2, 0, 1)[np.newaxis])
77
- return inp, ratio, pad_l, pad_t
78
-
79
- def _decode_raw(self, raw: np.ndarray, ratio: float, pad_l: int, pad_t: int,
80
- orig_w: int, orig_h: int) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
81
  """Decode ONNX output to (boxes_xyxy, confs, cls_ids) in original image coords."""
82
  pred = raw[0]
 
 
83
  if pred.shape[0] < pred.shape[1]:
84
- pred = pred.T
85
 
86
- bboxes_cx = pred[:, :4]
 
 
 
87
  cls_scores = pred[:, 4:]
 
 
88
 
89
  cls_ids = np.argmax(cls_scores, axis=1)
90
  confs = np.max(cls_scores, axis=1)
91
- mask = confs >= self.conf_threshold
92
 
93
- if not mask.any():
94
- return np.empty((0, 4)), np.empty(0), np.empty(0, dtype=int)
 
95
 
96
- bboxes_cx = bboxes_cx[mask]
97
- confs = confs[mask]
98
- cls_ids = cls_ids[mask]
99
 
100
- cx, cy, bw, bh = bboxes_cx[:, 0], bboxes_cx[:, 1], bboxes_cx[:, 2], bboxes_cx[:, 3]
101
- lx1 = cx - bw / 2
102
- ly1 = cy - bh / 2
103
- lx2 = cx + bw / 2
104
- ly2 = cy + bh / 2
105
 
106
- x1 = np.clip((lx1 - pad_l) / ratio, 0, orig_w)
107
- y1 = np.clip((ly1 - pad_t) / ratio, 0, orig_h)
108
- x2 = np.clip((lx2 - pad_l) / ratio, 0, orig_w)
109
- y2 = np.clip((ly2 - pad_t) / ratio, 0, orig_h)
110
- boxes = np.stack([x1, y1, x2, y2], axis=1)
 
111
 
112
- return boxes, confs, cls_ids
113
 
114
  def _run_single_pass(self, image_bgr: ndarray) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
115
- """Run one inference pass, return (boxes_xyxy, confs, cls_ids) in original coords."""
116
  orig_h, orig_w = image_bgr.shape[:2]
117
- inp, ratio, pad_l, pad_t = self._preprocess(image_bgr)
118
  raw = self.session.run(None, {self.input_name: inp})[0]
119
- return self._decode_raw(raw, ratio, pad_l, pad_t, orig_w, orig_h)
120
 
121
- def _nms(self, boxes: np.ndarray, confs: np.ndarray, cls_ids: np.ndarray
122
- ) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
123
  if len(boxes) == 0:
124
- return boxes, confs, cls_ids
125
  x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
126
  areas = (x2 - x1) * (y2 - y1)
127
  order = confs.argsort()[::-1]
@@ -136,7 +119,7 @@ class Miner:
136
  inter = np.maximum(0, xx2 - xx1) * np.maximum(0, yy2 - yy1)
137
  iou = inter / (areas[i] + areas[order[1:]] - inter + 1e-7)
138
  order = order[1:][iou <= self.iou_threshold]
139
- return boxes[keep], confs[keep], cls_ids[keep]
140
 
141
  def _infer_single(self, image_bgr: ndarray) -> list[BoundingBox]:
142
  orig_h, orig_w = image_bgr.shape[:2]
@@ -144,8 +127,9 @@ class Miner:
144
  if len(boxes) == 0:
145
  return []
146
 
147
- boxes, confs, cls_ids = self._nms(boxes, confs, cls_ids)
148
-
 
149
  out_boxes: list[BoundingBox] = []
150
  for i in range(len(boxes)):
151
  out_boxes.append(BoundingBox(
@@ -153,7 +137,7 @@ class Miner:
153
  y1=max(0, min(orig_h, math.floor(boxes[i, 1]))),
154
  x2=max(0, min(orig_w, math.ceil(boxes[i, 2]))),
155
  y2=max(0, min(orig_h, math.ceil(boxes[i, 3]))),
156
- cls_id=MODEL_TO_OUT[int(cls_ids[i])],
157
  conf=max(0.0, min(1.0, float(confs[i]))),
158
  ))
159
  return out_boxes
@@ -168,9 +152,11 @@ class Miner:
168
  for idx, image in enumerate(batch_images):
169
  boxes = self._infer_single(image)
170
  keypoints = [(0, 0) for _ in range(max(0, int(n_keypoints)))]
171
- results.append(TVFrameResult(
172
- frame_id=offset + idx,
173
- boxes=boxes,
174
- keypoints=keypoints,
175
- ))
 
 
176
  return results
 
1
  """
2
+ Score Vision SN44 — DetectPerson miner. v2 (2026-03-26).
3
+ Single-pass + NMS. Stretch resize preprocessing.
4
+ Single class: person (cls_id=0).
 
 
 
 
 
5
  """
6
 
7
  from pathlib import Path
 
12
  import onnxruntime as ort
13
  from numpy import ndarray
14
  from pydantic import BaseModel
 
 
 
 
 
 
 
 
15
 
16
 
17
  class BoundingBox(BaseModel):
 
32
  class Miner:
33
  def __init__(self, path_hf_repo: Path) -> None:
34
  self.path_hf_repo = path_hf_repo
35
+ self.class_names = ['person']
36
  self.session = ort.InferenceSession(
37
  str(path_hf_repo / "weights.onnx"),
38
  providers=["CUDAExecutionProvider", "CPUExecutionProvider"],
39
  )
40
  self.input_name = self.session.get_inputs()[0].name
41
+ input_shape = self.session.get_inputs()[0].shape
42
+ self.input_h = int(input_shape[2])
43
+ self.input_w = int(input_shape[3])
44
+ self.conf_threshold = 0.50
45
+ self.iou_threshold = 0.45
46
 
47
  def __repr__(self) -> str:
48
+ return f"DetectPerson Miner v3 NMS session={type(self.session).__name__}"
49
+
50
+ def _preprocess(self, image_bgr: ndarray) -> tuple[np.ndarray, tuple[int, int]]:
51
+ h, w = image_bgr.shape[:2]
52
+ rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)
53
+ resized = cv2.resize(rgb, (self.input_w, self.input_h))
54
+ x = resized.astype(np.float32) / 255.0
55
+ x = np.transpose(x, (2, 0, 1))[None, ...]
56
+ return x, (h, w)
57
+
58
+ def _decode_raw(self, raw: np.ndarray, orig_h: int, orig_w: int
59
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
 
 
 
 
 
 
 
 
 
 
 
 
60
  """Decode ONNX output to (boxes_xyxy, confs, cls_ids) in original image coords."""
61
  pred = raw[0]
62
+ if pred.ndim != 2:
63
+ return np.empty((0, 4)), np.empty(0), np.empty(0, dtype=int)
64
  if pred.shape[0] < pred.shape[1]:
65
+ pred = pred.transpose(1, 0)
66
 
67
+ if pred.shape[1] < 5:
68
+ return np.empty((0, 4)), np.empty(0), np.empty(0, dtype=int)
69
+
70
+ boxes = pred[:, :4]
71
  cls_scores = pred[:, 4:]
72
+ if cls_scores.shape[1] == 0:
73
+ return np.empty((0, 4)), np.empty(0), np.empty(0, dtype=int)
74
 
75
  cls_ids = np.argmax(cls_scores, axis=1)
76
  confs = np.max(cls_scores, axis=1)
77
+ keep = confs >= self.conf_threshold
78
 
79
+ boxes = boxes[keep]
80
+ confs = confs[keep]
81
+ cls_ids = cls_ids[keep]
82
 
83
+ if boxes.shape[0] == 0:
84
+ return np.empty((0, 4)), np.empty(0), np.empty(0, dtype=int)
 
85
 
86
+ sx = orig_w / float(self.input_w)
87
+ sy = orig_h / float(self.input_h)
 
 
 
88
 
89
+ cx, cy, bw, bh = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
90
+ x1 = np.clip((cx - bw / 2) * sx, 0, orig_w)
91
+ y1 = np.clip((cy - bh / 2) * sy, 0, orig_h)
92
+ x2 = np.clip((cx + bw / 2) * sx, 0, orig_w)
93
+ y2 = np.clip((cy + bh / 2) * sy, 0, orig_h)
94
+ out_boxes = np.stack([x1, y1, x2, y2], axis=1)
95
 
96
+ return out_boxes, confs, cls_ids
97
 
98
  def _run_single_pass(self, image_bgr: ndarray) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
 
99
  orig_h, orig_w = image_bgr.shape[:2]
100
+ inp, _ = self._preprocess(image_bgr)
101
  raw = self.session.run(None, {self.input_name: inp})[0]
102
+ return self._decode_raw(raw, orig_h, orig_w)
103
 
104
+ def _nms_dets(self, boxes: np.ndarray, confs: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
105
+ """Simple NMS on boxes+confs."""
106
  if len(boxes) == 0:
107
+ return boxes, confs
108
  x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
109
  areas = (x2 - x1) * (y2 - y1)
110
  order = confs.argsort()[::-1]
 
119
  inter = np.maximum(0, xx2 - xx1) * np.maximum(0, yy2 - yy1)
120
  iou = inter / (areas[i] + areas[order[1:]] - inter + 1e-7)
121
  order = order[1:][iou <= self.iou_threshold]
122
+ return boxes[keep], confs[keep]
123
 
124
  def _infer_single(self, image_bgr: ndarray) -> list[BoundingBox]:
125
  orig_h, orig_w = image_bgr.shape[:2]
 
127
  if len(boxes) == 0:
128
  return []
129
 
130
+ boxes, confs = self._nms_dets(boxes, confs)
131
+ # cls_ids got filtered by _run_single_pass but not by _nms_dets, re-derive
132
+ # Actually _nms_dets only returns boxes/confs, cls_ids are all 0 for person
133
  out_boxes: list[BoundingBox] = []
134
  for i in range(len(boxes)):
135
  out_boxes.append(BoundingBox(
 
137
  y1=max(0, min(orig_h, math.floor(boxes[i, 1]))),
138
  x2=max(0, min(orig_w, math.ceil(boxes[i, 2]))),
139
  y2=max(0, min(orig_h, math.ceil(boxes[i, 3]))),
140
+ cls_id=0,
141
  conf=max(0.0, min(1.0, float(confs[i]))),
142
  ))
143
  return out_boxes
 
152
  for idx, image in enumerate(batch_images):
153
  boxes = self._infer_single(image)
154
  keypoints = [(0, 0) for _ in range(max(0, int(n_keypoints)))]
155
+ results.append(
156
+ TVFrameResult(
157
+ frame_id=offset + idx,
158
+ boxes=boxes,
159
+ keypoints=keypoints,
160
+ )
161
+ )
162
  return results
model_type.json CHANGED
@@ -1 +1 @@
1
- {"task_type": "object-detection", "model_type": "yolov11-small", "deploy": "2026-03-26T07:43Z"}
 
1
+ {"task_type": "object-detection", "model_type": "yolov11-nano", "deploy": "2026-03-26T07:46Z"}
weights.onnx CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:e3916408ec21f8c94358c18914f922814770b78557e52fe17ff7a9ee74339a5a
3
- size 19272252
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f32ed65b9024a69693f675d494c7fc813a964766c54b241464a463377342da60
3
+ size 5607862