Instructions to use kesha-humonen/runic-reader-2 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use kesha-humonen/runic-reader-2 with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
File size: 2,934 Bytes
ed46c5d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | """Crop photographs to the zero-shot inscription box (data/ground_4b.jsonl) with a 20% margin and
rescale each crop to about 0.64 MP, so that runes occupy more of the recognizer's input.
Boxes are re-parsed from the raw model output (the "box" field of runs before the parse_box fix is wrong).
Images without a usable box are kept whole. Writes crops/ and splits/ocr_crop_{train,val,test}.jsonl.
Runs as the first step of the ocr4b_crop job (exp_v4.sh)."""
import json
import os
import re
from PIL import Image
R = "/home/jovyan/humonen/runic_access"
TARGET = 640_000
MARGIN = 0.2
def parse_box(text, w, h): # same as ground.parse_box, without importing torch
m = re.search(r"\[([^\[\]]*)\]", text)
nums = re.findall(r"-?\d+(?:\.\d+)?", m.group(1) if m else "")
if len(nums) < 4:
return None
x1, y1, x2, y2 = [float(v) for v in nums[:4]]
sx, sy = (w, h) if max(x1, y1, x2, y2) <= 1.0 else (w / 1000.0, h / 1000.0)
x1, x2 = sorted((x1 * sx, x2 * sx))
y1, y2 = sorted((y1 * sy, y2 * sy))
x1, y1, x2, y2 = max(0, x1), max(0, y1), min(w, x2), min(h, y2)
if x2 - x1 < 0.05 * w or y2 - y1 < 0.05 * h:
return None
return [x1, y1, x2, y2]
def crop_one(src, raw_text, dst):
"""Crop src to the parsed box with a margin, rescale to ~TARGET pixels, save to dst; return the crop box or None."""
im = Image.open(src).convert("RGB")
box = parse_box(raw_text, im.width, im.height)
if box:
x1, y1, x2, y2 = box
mx, my = MARGIN * (x2 - x1), MARGIN * (y2 - y1)
box = [max(0, x1 - mx), max(0, y1 - my), min(im.width, x2 + mx), min(im.height, y2 + my)]
im = im.crop(tuple(round(v) for v in box))
s = (TARGET / (im.width * im.height)) ** 0.5
im = im.resize((max(28, round(im.width * s)), max(28, round(im.height * s))), Image.BICUBIC)
im.save(dst + ".tmp.jpg", quality=92)
os.replace(dst + ".tmp.jpg", dst)
return box
if __name__ == "__main__":
raw = {}
for l in open(f"{R}/data/ground_4b.jsonl"):
r = json.loads(l)
raw[r["image"]] = r["raw"]
os.makedirs(f"{R}/crops", exist_ok=True)
stats = {"cropped": 0, "whole": 0}
boxes_out = open(f"{R}/data/crop_boxes.jsonl", "w")
for split in ("train", "val", "test"):
with open(f"{R}/splits/ocr_crop_{split}.jsonl", "w") as f:
for l in open(f"{R}/splits/ocr_real_{split}.jsonl"):
r = json.loads(l)
dst_rel = "crops/" + os.path.basename(r["image"])
box = crop_one(f"{R}/{r['image']}", raw.get(r["image"], ""), f"{R}/{dst_rel}")
stats["cropped" if box else "whole"] += 1
boxes_out.write(json.dumps({"image": r["image"], "crop_box": box}) + "\n")
f.write(json.dumps(dict(r, image=dst_rel, image_full=r["image"]), ensure_ascii=False) + "\n")
print(split, stats, flush=True)
boxes_out.close()
print("DONE", stats)
|