88 lines
3.0 KiB
Python
88 lines
3.0 KiB
Python
"""Single-page boundary test: datelines + rules -> article boxes, overlaid.
|
|
Usage: venv/bin/python3 _test_boundaries.py <run_dir> <page_num>
|
|
"""
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import cv2
|
|
from PIL import Image
|
|
|
|
from _lines import detect_separator_lines
|
|
from _boundaries import construct_boundaries
|
|
from smart_extractor import find_article_starts_by_dateline
|
|
|
|
|
|
def paper_of_height(h):
|
|
if 7040 <= h <= 7060:
|
|
return "sakshi"
|
|
if h in (6833, 6549):
|
|
return "andhra_jyothi"
|
|
if h == 6422:
|
|
return "namaste_telangana"
|
|
return "unknown"
|
|
|
|
|
|
def iou(a, b):
|
|
ix = max(0, min(a[2], b[2]) - max(a[0], b[0]))
|
|
iy = max(0, min(a[3], b[3]) - max(a[1], b[1]))
|
|
inter = ix * iy
|
|
if inter == 0:
|
|
return 0.0
|
|
ua = (a[2] - a[0]) * (a[3] - a[1]) + (b[2] - b[0]) * (b[3] - b[1]) - inter
|
|
return inter / ua if ua else 0.0
|
|
|
|
|
|
def main(run_dir, page_num):
|
|
run = Path(run_dir)
|
|
png = run / "pages" / f"page_{page_num:03d}.png"
|
|
regs = json.loads((run / "pages" / f"page_{page_num:03d}.regions.json").read_text())["regions"]
|
|
rmap = {r["id"]: r for r in regs}
|
|
paper = paper_of_height(Image.open(png).height)
|
|
|
|
lines = detect_separator_lines(png)
|
|
dls = find_article_starts_by_dateline(regs, str(png), paper)
|
|
boxes = construct_boundaries(regs, dls, lines, lines["size"])
|
|
|
|
print(f"\npaper={paper} datelines={len(dls)} boxes={len(boxes)} "
|
|
f"rules H={len(lines['h'])} V={len(lines['v'])}")
|
|
|
|
# validation
|
|
fails = []
|
|
for bx in boxes:
|
|
db = rmap[bx["region_id"]]["bbox"]
|
|
bb = bx["bbox"]
|
|
contains = bb[0] <= db[0] and bb[1] <= db[1] and bb[2] >= db[2] and bb[3] >= db[3]
|
|
if not contains:
|
|
fails.append(f"R{bx['region_id']} box does NOT contain its dateline body")
|
|
if bb[2] - bb[0] < 50 or bb[3] - bb[1] < 50:
|
|
fails.append(f"R{bx['region_id']} degenerate box {bb}")
|
|
for i in range(len(boxes)):
|
|
for j in range(i + 1, len(boxes)):
|
|
ov = iou(boxes[i]["bbox"], boxes[j]["bbox"])
|
|
if ov > 0.25:
|
|
fails.append(f"R{boxes[i]['region_id']} & R{boxes[j]['region_id']} overlap iou={ov:.2f}")
|
|
|
|
for bx in sorted(boxes, key=lambda z: z["bbox"][1]):
|
|
print(f" R{bx['region_id']:>3} hl=R{bx['headline_region']} {bx['dateline'][:22]!r:24} "
|
|
f"bbox={bx['bbox']} walls={bx['walls']['ceil_rule']}/{bx['walls']['floor_rule']}")
|
|
print(f"\nVALIDATION: {'PASS' if not fails else f'{len(fails)} ISSUE(S)'}")
|
|
for f in fails:
|
|
print(" ⚠", f)
|
|
|
|
img = cv2.imread(str(png))
|
|
for L in lines["h"]:
|
|
cv2.line(img, (L["x1"], L["y1"]), (L["x2"], L["y2"]), (0, 0, 255), 4)
|
|
for L in lines["v"]:
|
|
cv2.line(img, (L["x1"], L["y1"]), (L["x2"], L["y2"]), (255, 0, 0), 4)
|
|
for bx in boxes:
|
|
b = bx["bbox"]
|
|
cv2.rectangle(img, (b[0], b[1]), (b[2], b[3]), (0, 180, 0), 8)
|
|
out = Path(f"/tmp/boundaries_{run.name}_p{page_num:03d}.png")
|
|
cv2.imwrite(str(out), img)
|
|
print("overlay:", out)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main(sys.argv[1], int(sys.argv[2]))
|