""" Enroll a shelf: the products read off its crops become the store's catalog. This is the onboarding flow a real store would go through once - detect the facings, name the products, and keep their crops as the gallery that recognition matches against. The two demo shelves were built with it; the product lists live in this file because reading a contact sheet is a human step. python code/build_store_from_shelf.py """ import json, os, shutil, sys sys.path.insert(0, "code") import cv2 ROOT = os.path.expanduser("~/dorayaki-data/shelf-images") manifest = json.load(open(os.path.join(ROOT, "manifest.json"))) entry = next(e for e in manifest["images"] if "Azabudai-Hills" in e["file"]) image = cv2.imread(os.path.join(ROOT, entry["file"])) height, width = image.shape[:2] scale = min(1.0, 1600.0 / max(height, width)) image = cv2.resize(image, (int(width*scale), int(height*scale)), interpolation=cv2.INTER_AREA) boxes = json.load(open("/tmp/dorayaki-verify/mediya-boxes.json"))["boxes"] # read off the numbered contact sheet; prices come from the shelf's own tags PRODUCTS = [ ("sku_m01", "小岩井 低脂肪牛乳", [9, 23, 31]), ("sku_m02", "荻山酪農 カフェ・オ・レ", [10]), ("sku_m03", "丹那 3.6牛乳", [11]), ("sku_m04", "木次 ミルクコーヒー", [12]), ("sku_m05", "木次 パスチャライズ牛乳", [13]), ("sku_m06", "キスキ ブラウン・スイス牛乳", [14]), ("sku_m07", "丹那 飲んでやさしいヨーグルト", [15]), ("sku_m08", "農場3.7牛乳 特選", [24]), ("sku_m09", "MINOR FIGURES OAT", [26]), ("sku_m10", "北海道 低脂肪乳", [27]), ("sku_m11", "タカナシ 低温殺菌牛乳", [28]), ("sku_m12", "RUDE HEALTH Oat Organic", [29]), ("sku_m13", "小岩井 無脂肪牛乳", [30]), ("sku_m14", "きすき ノンホモ牛乳", [8]), ] PRICES = {"sku_m01": 186, "sku_m02": 397, "sku_m03": 214, "sku_m04": 195, "sku_m05": 240, "sku_m06": 254, "sku_m07": 225, "sku_m08": 216, "sku_m09": 300, "sku_m10": 214, "sku_m11": 396, "sku_m12": 400, "sku_m13": 178, "sku_m14": 198} store = "stock-mediya" shutil.rmtree(store, ignore_errors=True) os.makedirs(store, exist_ok=True) rows = ["SKU_ID,product_name,receipt_date,expiration_date,number_in,number_out,number_on,image_link,price"] written = [] for sku, name, indices in PRODUCTS: saved = 0 for position, index in enumerate(indices): box = boxes[index] x1, y1, x2, y2 = [int(v) for v in box] crop = image[max(0, y1):y2, max(0, x1):x2] if crop.size == 0: continue suffix = "" if saved == 0 else f"_{saved}" cv2.imwrite(os.path.join(store, f"{sku}{suffix}.jpeg"), crop) saved += 1 if saved == 0: raise SystemExit(f"{sku}: no readable crop; refusing a catalog row with no view") written.append(sku) rows.append(f"{sku},{name},2026-09-25,2026-10-20,24,8,16,'',{PRICES[sku]}") open(os.path.join(store, "stock.csv"), "w").write("\n".join(rows) + "\n") print(f"{store}: {len(written)} products, csv written")