Download infer.py from BDRC/TiBLA-PP-DocLayout-L: direct link, hf CLI and curl.
- Browser
- Download file 3.21 kB
-
https://huggingface.co/BDRC/TiBLA-PP-DocLayout-L/resolve/main/infer.py
- Command line
-
hf download hf://BDRC/TiBLA-PP-DocLayout-L/infer.py
-
curl -L -o infer.py https://huggingface.co/BDRC/TiBLA-PP-DocLayout-L/resolve/main/infer.py
3.21 kB
| #!/usr/bin/env python3 | |
| """Run the TiBLA PP-DocLayout-L Tibetan book layout detector on one or more page | |
| images, writing YOLO-format labels. | |
| The model is a 4-class PP-DocLayout-L (header, text-area, footnote, footer) | |
| fine-tuned on the leak-free v4 `tam2col` split of TiBLAD. It is served from the | |
| exported PaddlePaddle inference model in `inference/`. The recommended global | |
| operating confidence is ~0.68 (the best-mean-F1 point on the v4 test). | |
| Usage: | |
| python infer.py --model-dir inference --source page.jpg | |
| python infer.py --model-dir inference --source pages/ --out preds --conf 0.68 | |
| Requires: paddlepaddle==3.0.0, paddlex. | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| from pathlib import Path | |
| IMG_EXTS = {".jpg", ".jpeg", ".png", ".webp", ".bmp", ".tif", ".tiff"} | |
| # native class order from inference.yml | |
| NAMES = {"header": 0, "text-area": 1, "footnote": 2, "footer": 3} | |
| def main() -> int: | |
| ap = argparse.ArgumentParser(description=__doc__, | |
| formatter_class=argparse.RawDescriptionHelpFormatter) | |
| ap.add_argument("--model-dir", default="inference", | |
| help="path to the exported inference model dir") | |
| ap.add_argument("--source", required=True, help="image file or folder") | |
| ap.add_argument("--out", default=None, | |
| help="optional folder to write YOLO-format .txt labels") | |
| ap.add_argument("--conf", type=float, default=0.68, | |
| help="global operating confidence (default 0.68)") | |
| args = ap.parse_args() | |
| from PIL import Image | |
| from paddlex import create_model | |
| model = create_model(model_name="PP-DocLayout-L", model_dir=args.model_dir) | |
| src = Path(args.source) | |
| imgs = sorted(p for p in src.iterdir() if p.suffix.lower() in IMG_EXTS) \ | |
| if src.is_dir() else [src] | |
| out_dir = Path(args.out) if args.out else None | |
| if out_dir: | |
| out_dir.mkdir(parents=True, exist_ok=True) | |
| n_img = n_kept = 0 | |
| for ip in imgs: | |
| n_img += 1 | |
| with Image.open(ip) as im: | |
| W, H = im.size | |
| lines = [] | |
| for res in model.predict(str(ip), threshold=args.conf): | |
| for box in res["boxes"]: | |
| label = box["label"] | |
| cls = NAMES.get(label) | |
| if cls is None: | |
| continue | |
| x1, y1, x2, y2 = box["coordinate"] | |
| cx, cy = ((x1 + x2) / 2) / W, ((y1 + y2) / 2) / H | |
| w, h = (x2 - x1) / W, (y2 - y1) / H | |
| lines.append((cls, float(box["score"]), cx, cy, w, h)) | |
| n_kept += len(lines) | |
| print(f"{ip.stem}: {len(lines)} boxes") | |
| for cls, score, cx, cy, w, h in lines: | |
| name = next(k for k, v in NAMES.items() if v == cls) | |
| print(f" {name:10} conf={score:.3f} cx={cx:.3f} cy={cy:.3f} " | |
| f"w={w:.3f} h={h:.3f}") | |
| if out_dir: | |
| (out_dir / f"{ip.stem}.txt").write_text( | |
| "".join(f"{c} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}\n" | |
| for c, _, cx, cy, w, h in lines)) | |
| print(f"\n{n_img} images, {n_kept} boxes kept (conf {args.conf})") | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |