Download code/src/preprocessing/sam_polygon_run.py from savastakan/hitit-cuneiform-ocr: direct link, hf CLI and curl.
- Browser
- Download file 7.26 kB
-
https://huggingface.co/savastakan/hitit-cuneiform-ocr/resolve/main/code/src/preprocessing/sam_polygon_run.py
- Command line
-
hf download hf://savastakan/hitit-cuneiform-ocr/code/src/preprocessing/sam_polygon_run.py
-
curl -L -o sam_polygon_run.py https://huggingface.co/savastakan/hitit-cuneiform-ocr/resolve/main/code/src/preprocessing/sam_polygon_run.py
7.26 kB
| #!/usr/bin/env python3 | |
| """SAM 2.1 polygon annotation — GPU run. | |
| Detection bbox'larını prompt olarak kullanıp RLE mask üretir. | |
| Output: her kaynağın detection.coco.json dosyasına 'segmentation' alanı ekler. | |
| """ | |
| import json, os, argparse, time | |
| from pathlib import Path | |
| ROOT = Path("/arf/scratch/stakan/hitit-proje") | |
| SOURCES = ROOT / "datasets" / "sources" | |
| def main(): | |
| import torch | |
| from PIL import Image | |
| import numpy as np | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument('--source', default='all', help='all|hitit_local|compvis|yeni_veri|deepscribe') | |
| ap.add_argument('--limit', type=int, default=0) | |
| args = ap.parse_args() | |
| device = "cuda" if torch.cuda.is_available() else "cpu" | |
| print(f"Device: {device}", flush=True) | |
| # SAM 2.1 import (ultralytics YOLO'dan sam kullanabiliriz; veya segment_anything_2 paketi) | |
| try: | |
| from ultralytics import SAM | |
| sam = SAM("sam2.1_l.pt") # auto-download | |
| model_name = "sam2.1_l (ultralytics)" | |
| except Exception as e: | |
| print(f"Ultralytics SAM yüklenmedi: {e}; alternatif deneniyor", flush=True) | |
| try: | |
| from segment_anything import SamPredictor, sam_model_registry | |
| print("segment_anything varsa — manual checkpoint path gerekir") | |
| return | |
| except ImportError: | |
| print("SAM kurulu değil. Install: pip install ultralytics", flush=True) | |
| return | |
| source_dirs = ['hitit_local', 'compvis', 'yeni_veri', 'deepscribe'] if args.source == 'all' else [args.source] | |
| try: | |
| from pycocotools import mask as mask_utils | |
| except ImportError: | |
| os.system("pip install --user --quiet pycocotools") | |
| from pycocotools import mask as mask_utils | |
| t0 = time.time() | |
| total_done = 0 | |
| for src_name in source_dirs: | |
| src = SOURCES / src_name | |
| mp = src / "manifest_detection.jsonl" | |
| if not mp.exists(): continue | |
| records = [] | |
| with open(mp) as f: | |
| for line in f: | |
| records.append(json.loads(line)) | |
| if args.limit: | |
| records = records[:args.limit] | |
| print(f"\n{src_name}: {len(records)} record", flush=True) | |
| out_json = src / "detection.coco.json" | |
| coco = json.load(open(out_json)) if out_json.exists() else { | |
| "info": {"description": f"{src_name} detection with SAM 2.1 masks"}, | |
| "images": [], "annotations": [], "categories": [] | |
| } | |
| ann_id = 1 + (max([a['id'] for a in coco.get('annotations', [])], default=0)) | |
| cat_map = {c['name']: c['id'] for c in coco.get('categories', [])} | |
| img_id = 1 + (max([i['id'] for i in coco.get('images', [])], default=0)) | |
| existing_img_paths = {i.get('file_name') for i in coco.get('images', [])} | |
| for ri, r in enumerate(records): | |
| p = r.get('path') | |
| if not p or not os.path.exists(p): continue | |
| if p in existing_img_paths: continue | |
| # Bbox topla (YOLO label_path veya extra.bboxes) | |
| bboxes_xyxy = [] | |
| labels = [] | |
| w = r.get('width') or 0 | |
| h = r.get('height') or 0 | |
| if not (w and h): | |
| try: | |
| with Image.open(p) as img: | |
| w, h = img.size | |
| except: continue | |
| lp = r.get('label_path') | |
| if lp and os.path.exists(lp): | |
| try: | |
| with open(lp) as f: | |
| for ln in f: | |
| parts = ln.strip().split() | |
| if len(parts) == 5: | |
| cls, cx, cy, bw, bh = parts | |
| cx, cy, bw, bh = float(cx)*w, float(cy)*h, float(bw)*w, float(bh)*h | |
| x1, y1, x2, y2 = cx-bw/2, cy-bh/2, cx+bw/2, cy+bh/2 | |
| bboxes_xyxy.append([x1, y1, x2, y2]) | |
| labels.append(f"class_{cls}") | |
| except: pass | |
| extra = r.get('extra') or {} | |
| if isinstance(extra, dict): | |
| for b in extra.get('bboxes', []): | |
| if not isinstance(b, dict): continue | |
| lbl = b.get('class_name') or b.get('mzl_label') or b.get('train_label') or 'unknown' | |
| yolo = b.get('yolo_bbox') | |
| xyxy = b.get('bbox') | |
| if yolo and len(yolo) == 4: | |
| cx, cy, bw, bh = yolo | |
| cx, cy, bw, bh = cx*w, cy*h, bw*w, bh*h | |
| bboxes_xyxy.append([cx-bw/2, cy-bh/2, cx+bw/2, cy+bh/2]) | |
| labels.append(str(lbl)) | |
| elif xyxy and len(xyxy) == 4: | |
| bboxes_xyxy.append([float(x) for x in xyxy]) | |
| labels.append(str(lbl)) | |
| if not bboxes_xyxy: continue | |
| # SAM predict | |
| try: | |
| results = sam(p, bboxes=bboxes_xyxy, verbose=False) | |
| except Exception as e: | |
| print(f" skip {p}: {e}", flush=True) | |
| continue | |
| # Image entry | |
| coco['images'].append({ | |
| "id": img_id, | |
| "file_name": p, | |
| "width": w, "height": h, | |
| "fold": r.get('fold'), | |
| "tablet_id": r.get('tablet_id'), | |
| }) | |
| # Annotations | |
| if results and hasattr(results[0], 'masks') and results[0].masks is not None: | |
| masks = results[0].masks.data.cpu().numpy() # (N, H, W) bool | |
| for mi, (mask, lbl, bb) in enumerate(zip(masks, labels, bboxes_xyxy)): | |
| if lbl not in cat_map: | |
| cat_map[lbl] = len(cat_map) + 1 | |
| coco['categories'].append({"id": cat_map[lbl], "name": lbl, "supercategory": "sign"}) | |
| # RLE encode | |
| mask_u8 = (mask > 0).astype(np.uint8) | |
| rle = mask_utils.encode(np.asfortranarray(mask_u8)) | |
| rle['counts'] = rle['counts'].decode('utf-8') | |
| x1, y1, x2, y2 = bb | |
| coco['annotations'].append({ | |
| "id": ann_id, | |
| "image_id": img_id, | |
| "category_id": cat_map[lbl], | |
| "bbox": [x1, y1, x2-x1, y2-y1], | |
| "area": float(mask_u8.sum()), | |
| "iscrowd": 0, | |
| "segmentation": rle, | |
| }) | |
| ann_id += 1 | |
| img_id += 1 | |
| total_done += 1 | |
| if (ri+1) % 100 == 0: | |
| elapsed = time.time() - t0 | |
| rate = total_done / max(elapsed, 1) | |
| print(f" [{src_name}] {ri+1}/{len(records)} ({rate:.1f} img/s)", flush=True) | |
| with open(out_json, 'w') as f: | |
| json.dump(coco, f, ensure_ascii=False) | |
| print(f" {src_name}: yazıldı {out_json} — {len(coco['images'])} img, {len(coco['annotations'])} ann", flush=True) | |
| if __name__ == '__main__': | |
| main() | |