""" Run the pipeline over store photos it has never seen. python code/eval_external_images.py [data/external-shelves/wikimedia-commons] Reports detection and identity per image, and writes a JSON summary. See docs/EXTERNAL-EVAL.md for what the numbers mean. The images live in the repository (`data/external-shelves/`), not in a home directory: they are evaluation evidence, and evidence that only exists on one machine cannot be re-checked. """ import json, os, sys, time sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import cv2, numpy as np from engine import build_default_engine, EngineSettings from tags import TagService, TagSettings from reconcile import attach_tags_to_boxes DEFAULT_ROOT = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "data", "external-shelves", "wikimedia-commons") ROOT = os.path.expanduser(sys.argv[1] if len(sys.argv) > 1 else DEFAULT_ROOT) engine = build_default_engine(EngineSettings(stock_dir="stock-lopia")) catalog_by_sku = {p["sku_id"]: p for p in engine.catalog()} service = TagService(engine.ocr_engine, settings=TagSettings()) rows = [] for entry in manifest["images"]: path = os.path.join(ROOT, entry["file"]) image = cv2.imread(path) if image is None: continue # keep the long side at 1600 so detection cost is comparable across images height, width = image.shape[:2] if max(height, width) > 1600: scale = 1600.0 / max(height, width) image = cv2.resize(image, (int(width*scale), int(height*scale)), interpolation=cv2.INTER_AREA) started = time.perf_counter() result = engine.recognize(image, classify=True, method="hybrid", with_empty_slots=True) detections = result["detections"] recognized = sum(1 for d in detections if (d.get("identity") or {}).get("state") == "recognized") rejected = sum(1 for d in detections if (d.get("identity") or {}).get("state") == "rejected") rows.append({ "file": entry["file"], "title": entry["title"], "license": entry["license"], "size": f"{image.shape[1]}x{image.shape[0]}", "detections": len(detections), "recognized": recognized, "rejected": rejected, "ms": round((time.perf_counter()-started)*1000), }) print(f" {entry['file'][:34]:<34} {image.shape[1]}x{image.shape[0]:<5} " f"det={len(detections):>4} rec={recognized:>3} rej={rejected:>3} {rows[-1]['ms']:>5} ms") total_det = sum(r["detections"] for r in rows) total_rec = sum(r["recognized"] for r in rows) with_det = sum(1 for r in rows if r["detections"] > 0) print(f"\n{len(rows)} images, {total_det} detections, {total_rec} recognized " f"({100*total_rec//max(1,total_det)}%), images with any detection: {with_det}") json.dump(rows, open(os.path.join(ROOT, "eval.json"), "w"), ensure_ascii=False, indent=1) print(f"summary: {os.path.join(ROOT, 'eval.json')}")