meaculpitt commited on
Commit
87f5dd9
·
verified ·
1 Parent(s): f29cd5b

v3 weights (yolo11s, 204k merged plate dataset, val mAP50=0.944)

Browse files
Files changed (1) hide show
  1. miner.py +52 -0
miner.py CHANGED
@@ -359,6 +359,51 @@ class Miner:
359
  dets.append((xa, ya, xb, yb, float(confs[i]), int(cls_ids[i])))
360
  return dets
361
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
  def _quad4_raw_dets(
363
  self,
364
  image_bgr: ndarray,
@@ -415,6 +460,13 @@ class Miner:
415
  (orig_w - x2f, y1, orig_w - x1f, y2, conf, cls_id)
416
  )
417
 
 
 
 
 
 
 
 
418
  dets = self._soft_nms(all_dets)
419
 
420
  out_boxes: list[BoundingBox] = []
 
359
  dets.append((xa, ya, xb, yb, float(confs[i]), int(cls_ids[i])))
360
  return dets
361
 
362
+ def _cluster_dedup(
363
+ self,
364
+ dets: list[tuple[float, float, float, float, float, int]],
365
+ iou_thresh: float = 0.5,
366
+ ) -> list[tuple[float, float, float, float, float, int]]:
367
+ """Greedy near-duplicate suppression — for any pair with IoU >=
368
+ ``iou_thresh``, keep only the higher-conf detection.
369
+
370
+ Purpose: collapse TTA-induced duplicates of the same plate before
371
+ Soft-NMS, which would otherwise decay (but not kill) the lower-conf
372
+ copy, leaving multiple boxes per plate past our low score_threshold.
373
+ Mirrors the TTA-cluster-merge step in alfred8995/arabic000's miner.py.
374
+
375
+ Applied on *every* call (not just TTA) because the quad-4 overlap
376
+ band can also produce near-duplicate detections near tile seams.
377
+ IoU threshold 0.5 is loose enough that adjacent-but-distinct plates
378
+ (IoU < 0.5) stay separate; tight enough that same-plate variants
379
+ (IoU > 0.9 in practice) collapse.
380
+ """
381
+ if not dets:
382
+ return []
383
+ # Sort by conf desc (index 4)
384
+ srt = sorted(dets, key=lambda d: -d[4])
385
+ kept: list[tuple[float, float, float, float, float, int]] = []
386
+ suppressed = [False] * len(srt)
387
+ for i in range(len(srt)):
388
+ if suppressed[i]:
389
+ continue
390
+ x1i, y1i, x2i, y2i = srt[i][0], srt[i][1], srt[i][2], srt[i][3]
391
+ area_i = max(0.0, x2i - x1i) * max(0.0, y2i - y1i)
392
+ kept.append(srt[i])
393
+ for j in range(i + 1, len(srt)):
394
+ if suppressed[j]:
395
+ continue
396
+ x1j, y1j, x2j, y2j = srt[j][0], srt[j][1], srt[j][2], srt[j][3]
397
+ ix1 = max(x1i, x1j); iy1 = max(y1i, y1j)
398
+ ix2 = min(x2i, x2j); iy2 = min(y2i, y2j)
399
+ iw = max(0.0, ix2 - ix1); ih = max(0.0, iy2 - iy1)
400
+ inter = iw * ih
401
+ area_j = max(0.0, x2j - x1j) * max(0.0, y2j - y1j)
402
+ union = area_i + area_j - inter
403
+ if union > 0 and inter / union >= iou_thresh:
404
+ suppressed[j] = True
405
+ return kept
406
+
407
  def _quad4_raw_dets(
408
  self,
409
  image_bgr: ndarray,
 
460
  (orig_w - x2f, y1, orig_w - x1f, y2, conf, cls_id)
461
  )
462
 
463
+ # TTA-aware cluster-dedup: collapse near-duplicate detections of the
464
+ # same plate (e.g. original + unflipped TTA view) BEFORE Soft-NMS,
465
+ # which would otherwise decay but not kill the lower-conf copy at
466
+ # our low score_threshold=0.01. Without this step the deployed miner
467
+ # emitted 2-3 outputs per plate (verified on validator task 57820).
468
+ all_dets = self._cluster_dedup(all_dets, iou_thresh=0.5)
469
+
470
  dets = self._soft_nms(all_dets)
471
 
472
  out_boxes: list[BoundingBox] = []