Order bbox corners, and find the ground truth is for another manga
`_bbox_to_pixels` sorts each coordinate pair after clamping. Run B returned `p007 person_1` as `[226, 417, 130, 551]`, x1 > x2, which cropped to nothing and lost that detection silently. The third GPU cycle came back with 0 degenerate boxes over 119 detections. The plan's first item cannot run as written. All 145 rows of `identity_labels` belong to chapter 8ca8249b, a different manga. Chapter 7c944dd4 has none, so `/review/identity` reports `accuracy: null`. Scoring 8ca8249b gives 7/138 on an identity run that predates every fix. The cycle also settled the coverage question. All 68 assignments landed on face-bearing detections and none on a gated one, so recall among face-bearing detections is 96%, up from 82%. Coverage is the `has_face` gate and nothing else. What is now open is precision: the lead holds 36 of 68 assignments. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+11
-5
@@ -323,10 +323,13 @@ def _bbox_to_pixels(chars: list, w: int, h: int) -> list:
|
||||
b = c.get("bbox")
|
||||
if not (isinstance(b, list) and len(b) == 4 and all(isinstance(v, (int, float)) for v in b)):
|
||||
continue
|
||||
c["bbox"] = [min(w, max(0, round(b[0] * w / BBOX_GRID))),
|
||||
min(h, max(0, round(b[1] * h / BBOX_GRID))),
|
||||
min(w, max(0, round(b[2] * w / BBOX_GRID))),
|
||||
min(h, max(0, round(b[3] * h / BBOX_GRID)))]
|
||||
xs = sorted((min(w, max(0, round(b[0] * w / BBOX_GRID))),
|
||||
min(w, max(0, round(b[2] * w / BBOX_GRID)))))
|
||||
ys = sorted((min(h, max(0, round(b[1] * h / BBOX_GRID))),
|
||||
min(h, max(0, round(b[3] * h / BBOX_GRID)))))
|
||||
# ponytail: the model swapped corners on 1 of 117 boxes (p007 person_1, x1 > x2).
|
||||
# Ordering here is enough because a zero-area box still crops to nothing downstream.
|
||||
c["bbox"] = [xs[0], ys[0], xs[1], ys[1]]
|
||||
return chars
|
||||
|
||||
|
||||
@@ -1216,8 +1219,11 @@ if __name__ == "__main__":
|
||||
# the top sixth of the panel, inside a speech balloon, which is what identity embedded.
|
||||
_ch = [{"local_id": "person_5", "bbox": [222, 405, 654, 1000]},
|
||||
{"local_id": "edge", "bbox": [0, 0, 1000, 1000]},
|
||||
{"local_id": "junk", "bbox": "nope"}]
|
||||
{"local_id": "junk", "bbox": "nope"},
|
||||
# p007 person_1 of run B: x1 > x2, so the crop came out empty and the detection was lost
|
||||
{"local_id": "swapped", "bbox": [226, 417, 130, 551]}]
|
||||
_bbox_to_pixels(_ch, 900, 1650)
|
||||
assert _ch[3]["bbox"] == [117, 688, 203, 909], _ch[3]["bbox"] # corners ordered, non-empty crop
|
||||
assert _ch[0]["bbox"] == [200, 668, 589, 1650], _ch[0]["bbox"]
|
||||
assert _ch[1]["bbox"] == [0, 0, 900, 1650], _ch[1]["bbox"] # a clamped box spans the whole panel
|
||||
assert _ch[2]["bbox"] == "nope", _ch[2]["bbox"] # unparseable is left alone, not crashed
|
||||
|
||||
Reference in New Issue
Block a user