iotaminer commited on
Commit
2cbead3
·
verified ·
1 Parent(s): dbdf48b

scorevision: push artifact

Browse files
Files changed (1) hide show
  1. miner.py +69 -10
miner.py CHANGED
@@ -149,9 +149,18 @@ class Miner:
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
@@ -306,16 +315,25 @@ class Miner:
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
 
@@ -325,7 +343,9 @@ class Miner:
325
  boxes /= ratio
326
  boxes = _clip_boxes(boxes, orig_size)
327
 
328
- boxes, scores = self._filter_sane(boxes, scores, orig_size)
 
 
329
  if len(boxes) == 0:
330
  return []
331
 
@@ -333,9 +353,10 @@ class Miner:
333
  keep = keep[: self.max_det]
334
  boxes = boxes[keep]
335
  scores = scores[keep]
 
336
 
337
  out: list[BoundingBox] = []
338
- for box, conf in zip(boxes, scores):
339
  if box[2] <= box[0] or box[3] <= box[1]:
340
  continue
341
  out.append(
@@ -344,12 +365,50 @@ class Miner:
344
  y1=int(math.floor(box[1])),
345
  x2=int(math.ceil(box[2])),
346
  y2=int(math.ceil(box[3])),
347
- cls_id=0,
348
  conf=float(conf),
349
  )
350
  )
351
  return out
352
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
  @staticmethod
354
  def _coco_classes() -> list[str]:
355
  return [
 
149
  """
150
 
151
  def __init__(self, path_hf_repo: Path) -> None:
152
+ # IMPORTANT: element `manak0/Detect-detect-vehicle` declares:
153
+ # objects = ["bus", "car", "truck", "motorcycle"] (in this order)
154
+ # So the validator maps cls_id 0->"bus", 1->"car", 2->"truck", 3->"motorcycle".
155
+ # We must emit cls_id matching this order.
156
+ self.class_names = ["bus", "car", "truck", "motorcycle"]
157
+ # COCO -> element cls_id:
158
+ # bus (5) -> 0
159
+ # car (2) -> 1
160
+ # truck (7) -> 2
161
+ # motorcycle (3) -> 3
162
+ self.coco_to_element = {5: 0, 2: 1, 7: 2, 3: 3}
163
+ self.vehicle_coco_ids = tuple(self.coco_to_element.keys())
164
 
165
  weights_name = os.environ.get("SN44_ONNX_WEIGHTS", _DEFAULT_WEIGHTS)
166
  weights_path = path_hf_repo / weights_name
 
315
  boxes_xywh = preds[:, :4].astype(np.float32)
316
  class_scores = preds[:, 4:].astype(np.float32)
317
 
318
+ # For each detection, determine which COCO vehicle class has the MAX score
319
+ # and retain that as the class id + score.
320
+ vehicle_coco_idx = np.array(self.vehicle_coco_ids, dtype=np.intp)
321
+ vehicle_class_scores = class_scores[:, vehicle_coco_idx] # (N, 4)
322
+ best_in_vehicle = vehicle_class_scores.argmax(axis=1) # (N,) index into vehicle_coco_idx
323
+ vehicle_scores = vehicle_class_scores.max(axis=1) # (N,)
324
+ best_coco_ids = vehicle_coco_idx[best_in_vehicle] # COCO ids per row
325
+
326
  mask = vehicle_scores >= self.conf_thres
327
  if not np.any(mask):
328
  return []
329
 
330
  boxes_xywh = boxes_xywh[mask]
331
  scores = vehicle_scores[mask]
332
+ # Map COCO id -> element cls_id (for emission)
333
+ element_cls_ids = np.array(
334
+ [self.coco_to_element[int(c)] for c in best_coco_ids[mask]],
335
+ dtype=np.int32,
336
+ )
337
 
338
  boxes = _xywh_to_xyxy(boxes_xywh)
339
 
 
343
  boxes /= ratio
344
  boxes = _clip_boxes(boxes, orig_size)
345
 
346
+ boxes, scores, element_cls_ids = self._filter_sane_with_cls(
347
+ boxes, scores, element_cls_ids, orig_size,
348
+ )
349
  if len(boxes) == 0:
350
  return []
351
 
 
353
  keep = keep[: self.max_det]
354
  boxes = boxes[keep]
355
  scores = scores[keep]
356
+ element_cls_ids = element_cls_ids[keep]
357
 
358
  out: list[BoundingBox] = []
359
+ for box, conf, cls_id in zip(boxes, scores, element_cls_ids):
360
  if box[2] <= box[0] or box[3] <= box[1]:
361
  continue
362
  out.append(
 
365
  y1=int(math.floor(box[1])),
366
  x2=int(math.ceil(box[2])),
367
  y2=int(math.ceil(box[3])),
368
+ cls_id=int(cls_id),
369
  conf=float(conf),
370
  )
371
  )
372
  return out
373
 
374
+ def _filter_sane_with_cls(
375
+ self,
376
+ boxes: np.ndarray,
377
+ scores: np.ndarray,
378
+ cls_ids: np.ndarray,
379
+ orig_size: tuple[int, int],
380
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
381
+ if len(boxes) == 0:
382
+ return boxes, scores, cls_ids
383
+ orig_w, orig_h = orig_size
384
+ image_area = float(orig_w * orig_h)
385
+ keep: list[int] = []
386
+ for i, box in enumerate(boxes):
387
+ x1, y1, x2, y2 = box.tolist()
388
+ bw = x2 - x1
389
+ bh = y2 - y1
390
+ if bw <= 0 or bh <= 0:
391
+ continue
392
+ if bw < self.min_w or bh < self.min_h:
393
+ continue
394
+ area = bw * bh
395
+ if area < self.min_box_area:
396
+ continue
397
+ if area > self.max_box_area_ratio * image_area:
398
+ continue
399
+ ar = max(bw / max(bh, 1e-6), bh / max(bw, 1e-6))
400
+ if ar > self.max_aspect_ratio:
401
+ continue
402
+ keep.append(i)
403
+ if not keep:
404
+ return (
405
+ np.empty((0, 4), dtype=np.float32),
406
+ np.empty((0,), dtype=np.float32),
407
+ np.empty((0,), dtype=np.int32),
408
+ )
409
+ idx = np.array(keep, dtype=np.intp)
410
+ return boxes[idx], scores[idx], cls_ids[idx]
411
+
412
  @staticmethod
413
  def _coco_classes() -> list[str]:
414
  return [