hitit-cuneiform-ocr / code /src /preprocessing /view_canonicalization.py
savastakan's picture
Initial upload: code + 5 record checkpoints + fuse
f211247 verified
Raw
History Blame Contribute Delete
3.69 kB
#!/usr/bin/env python3
"""View-aware rotation canonicalization (heuristic).
view_ile_hint tablet_view alanı zaten var. Şimdi: aspect ratio + view hint ile
doğru orientation'a rotate et (offline pass).
"""
import json, os
from pathlib import Path
from concurrent.futures import ProcessPoolExecutor
import numpy as np
from PIL import Image
ROOT = Path("/arf/scratch/stakan/hitit-proje")
SOURCES = ROOT / "datasets" / "sources"
def infer_canonical_rotation(img_path, view_hint):
"""
View hint + aspect ratio ile kanonik rotation tespit et.
Return: rotation_degrees (0, 90, 180, 270) ve landscape_score
"""
try:
with Image.open(img_path) as img:
w, h = img.size
aspect = w / max(h, 1)
# Tablet'ler genelde landscape veya kare. Çok aspect lehinde olan bir view'a göre:
# - obverse/reverse: landscape (aspect>1) tipik
# - edges: portrait (aspect<1) veya ince
# Bu basit heuristic; asıl model-based classifier ayrı.
if view_hint in ('obverse', 'reverse'):
return 0 if aspect >= 0.7 else 90 # portrait'i landscape'e çevir
elif view_hint in ('left_edge', 'right_edge'):
return 90 if aspect > 1 else 0
return 0
except Exception:
return 0
def worker(item):
rid, path, view = item
return (rid, infer_canonical_rotation(path, view))
def main():
items = []
for d in sorted(SOURCES.iterdir()):
if not d.is_dir(): continue
mp = d / "manifest.jsonl"
if not mp.exists(): continue
with open(mp) as f:
for line in f:
r = json.loads(line)
p = r.get('path')
if p and r.get('storage') == 'fs' and r.get('integrity_ok') is True:
items.append((r['id'], p, r.get('view', 'unknown')))
# Unique by path (daha hızlı)
seen_paths = set()
uniq = []
for rid, path, view in items:
if path in seen_paths: continue
seen_paths.add(path)
uniq.append((rid, path, view))
print(f"Tarama: {len(uniq):,} unique image")
results = {}
with ProcessPoolExecutor(max_workers=200) as ex:
for rid, rot in ex.map(worker, uniq, chunksize=500):
results[rid] = rot
# Manifest güncelle
from collections import Counter
rot_counts = Counter()
for d in sorted(SOURCES.iterdir()):
if not d.is_dir(): continue
for mf in ['manifest.jsonl', 'manifest_classification.jsonl', 'manifest_detection.jsonl']:
mp = d / mf
if not mp.exists(): continue
records = []
with open(mp) as f:
for line in f:
r = json.loads(line)
rot = results.get(r.get('id'))
if rot is not None:
r['canonical_rotation_deg'] = int(rot)
if mf == 'manifest.jsonl':
rot_counts[rot] += 1
records.append(r)
with open(mp, 'w') as f:
for r in records:
f.write(json.dumps(r, ensure_ascii=False) + '\n')
print(f"Rotation counts: {dict(rot_counts)}")
with open(ROOT / "datasets" / "processed" / "view_canonicalization_report.json", 'w') as f:
json.dump({
"method": "heuristic (aspect + view_hint)",
"n_images_processed": len(results),
"rotation_distribution": dict(rot_counts),
"note": "Heuristic v1. Model-based classifier (MobileNetV3) için ayrı training gerekir."
}, f, indent=2, ensure_ascii=False)
if __name__ == '__main__':
main()