scorevision: push artifact
Browse files
miner.py
CHANGED
|
@@ -185,6 +185,12 @@ PER_CONSENSUS_IOU = 0.50 # Cross-view IoU to confirm low-conf box
|
|
| 185 |
PER_WBF_IOU = 0.40 # Final WBF dedup (unchanged)
|
| 186 |
PER_RTF_BUDGET = 8.0 # Conservative RTF budget (gate is 10s)
|
| 187 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
# ββ Shared ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 189 |
WBF_SKIP_THR = 0.0001
|
| 190 |
|
|
@@ -527,41 +533,35 @@ class Miner:
|
|
| 527 |
else:
|
| 528 |
logger.warning(f"[person TTA] skipping flip β pass1 took {elapsed*1000:.0f}ms")
|
| 529 |
|
| 530 |
-
# ββ Consensus filtering ββ
|
| 531 |
kept_b, kept_s = [], []
|
| 532 |
|
| 533 |
-
|
| 534 |
-
|
| 535 |
-
|
| 536 |
-
|
| 537 |
-
def _has_match(box, others):
|
| 538 |
-
if len(others) == 0:
|
| 539 |
-
return False
|
| 540 |
-
xx1 = np.maximum(box[0], others[:, 0])
|
| 541 |
-
yy1 = np.maximum(box[1], others[:, 1])
|
| 542 |
-
xx2 = np.minimum(box[2], others[:, 2])
|
| 543 |
-
yy2 = np.minimum(box[3], others[:, 3])
|
| 544 |
-
inter = np.maximum(0, xx2 - xx1) * np.maximum(0, yy2 - yy1)
|
| 545 |
-
a1 = (box[2] - box[0]) * (box[3] - box[1])
|
| 546 |
-
a2 = (others[:, 2] - others[:, 0]) * (others[:, 3] - others[:, 1])
|
| 547 |
-
iou = inter / (a1 + a2 - inter + 1e-9)
|
| 548 |
-
return bool(np.any(iou > PER_CONSENSUS_IOU))
|
| 549 |
-
|
| 550 |
-
for i in range(len(boxes_orig)):
|
| 551 |
-
if confs_orig[i] >= PER_CONF_HIGH or _has_match(boxes_orig[i], boxes_flip):
|
| 552 |
-
kept_b.append(boxes_orig[i])
|
| 553 |
-
kept_s.append(confs_orig[i])
|
| 554 |
|
|
|
|
|
|
|
|
|
|
| 555 |
for i in range(len(boxes_flip)):
|
| 556 |
-
if confs_flip[i]
|
| 557 |
-
|
| 558 |
-
|
| 559 |
-
|
| 560 |
-
|
| 561 |
-
|
| 562 |
-
|
| 563 |
-
|
| 564 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 565 |
|
| 566 |
if not kept_b:
|
| 567 |
return []
|
|
@@ -582,6 +582,28 @@ class Miner:
|
|
| 582 |
fb[:, [0, 2]] *= ow
|
| 583 |
fb[:, [1, 3]] *= oh
|
| 584 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 585 |
out = []
|
| 586 |
for i in range(len(fb)):
|
| 587 |
b = fb[i]
|
|
|
|
| 185 |
PER_WBF_IOU = 0.40 # Final WBF dedup (unchanged)
|
| 186 |
PER_RTF_BUDGET = 8.0 # Conservative RTF budget (gate is 10s)
|
| 187 |
|
| 188 |
+
# ββ Person box sanity filters (matching top scorers) ββββββββββββββββββββββββ
|
| 189 |
+
PER_MIN_WH = 8 # Minimum box width or height (pixels)
|
| 190 |
+
PER_MIN_AREA = 14 * 14 # Minimum box area (pixels^2)
|
| 191 |
+
PER_MAX_ASPECT = 8.0 # Maximum aspect ratio
|
| 192 |
+
PER_MAX_AREA_RATIO = 0.80 # Maximum box area / image area
|
| 193 |
+
|
| 194 |
# ββ Shared ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 195 |
WBF_SKIP_THR = 0.0001
|
| 196 |
|
|
|
|
| 533 |
else:
|
| 534 |
logger.warning(f"[person TTA] skipping flip β pass1 took {elapsed*1000:.0f}ms")
|
| 535 |
|
| 536 |
+
# ββ Consensus filtering (v2 β original-primary, flip supplements) ββ
|
| 537 |
kept_b, kept_s = [], []
|
| 538 |
|
| 539 |
+
# Always keep ALL original boxes at conf >= PER_CONF_LOW
|
| 540 |
+
for i in range(len(boxes_orig)):
|
| 541 |
+
kept_b.append(boxes_orig[i])
|
| 542 |
+
kept_s.append(confs_orig[i])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 543 |
|
| 544 |
+
if has_flip:
|
| 545 |
+
# From flip view: only add HIGH-conf boxes that original MISSED
|
| 546 |
+
# (IoU < 0.3 with all original boxes = truly new detection)
|
| 547 |
for i in range(len(boxes_flip)):
|
| 548 |
+
if confs_flip[i] < PER_CONF_HIGH:
|
| 549 |
+
continue
|
| 550 |
+
# Check if this flip box overlaps any original box
|
| 551 |
+
if len(boxes_orig) > 0:
|
| 552 |
+
xx1 = np.maximum(boxes_flip[i, 0], boxes_orig[:, 0])
|
| 553 |
+
yy1 = np.maximum(boxes_flip[i, 1], boxes_orig[:, 1])
|
| 554 |
+
xx2 = np.minimum(boxes_flip[i, 2], boxes_orig[:, 2])
|
| 555 |
+
yy2 = np.minimum(boxes_flip[i, 3], boxes_orig[:, 3])
|
| 556 |
+
inter = np.maximum(0, xx2 - xx1) * np.maximum(0, yy2 - yy1)
|
| 557 |
+
a1 = (boxes_flip[i, 2] - boxes_flip[i, 0]) * (boxes_flip[i, 3] - boxes_flip[i, 1])
|
| 558 |
+
a2 = (boxes_orig[:, 2] - boxes_orig[:, 0]) * (boxes_orig[:, 3] - boxes_orig[:, 1])
|
| 559 |
+
iou = inter / (a1 + a2 - inter + 1e-9)
|
| 560 |
+
if np.max(iou) >= 0.3:
|
| 561 |
+
continue # Already detected by original β skip
|
| 562 |
+
# Truly new high-conf detection from flip
|
| 563 |
+
kept_b.append(boxes_flip[i])
|
| 564 |
+
kept_s.append(confs_flip[i])
|
| 565 |
|
| 566 |
if not kept_b:
|
| 567 |
return []
|
|
|
|
| 582 |
fb[:, [0, 2]] *= ow
|
| 583 |
fb[:, [1, 3]] *= oh
|
| 584 |
|
| 585 |
+
# ββ Sanity filter (remove degenerate boxes) βββββββββββββββββββββ
|
| 586 |
+
img_area = float(oh * ow)
|
| 587 |
+
sane = []
|
| 588 |
+
for i in range(len(fb)):
|
| 589 |
+
bw = fb[i, 2] - fb[i, 0]
|
| 590 |
+
bh = fb[i, 3] - fb[i, 1]
|
| 591 |
+
if bw < PER_MIN_WH or bh < PER_MIN_WH:
|
| 592 |
+
continue
|
| 593 |
+
area = bw * bh
|
| 594 |
+
if area < PER_MIN_AREA:
|
| 595 |
+
continue
|
| 596 |
+
if max(bw, bh) / max(min(bw, bh), 1e-6) > PER_MAX_ASPECT:
|
| 597 |
+
continue
|
| 598 |
+
if area / img_area > PER_MAX_AREA_RATIO:
|
| 599 |
+
continue
|
| 600 |
+
sane.append(i)
|
| 601 |
+
|
| 602 |
+
if not sane:
|
| 603 |
+
return []
|
| 604 |
+
fb = fb[sane]
|
| 605 |
+
fs = fs[sane]
|
| 606 |
+
|
| 607 |
out = []
|
| 608 |
for i in range(len(fb)):
|
| 609 |
b = fb[i]
|