diff --git a/recognization/code/engine.py b/recognization/code/engine.py index 959c7b8..27507bd 100644 --- a/recognization/code/engine.py +++ b/recognization/code/engine.py @@ -566,7 +566,12 @@ class RecognitionEngine: return self._lane def score_crop(self, crop: Any, method: Optional[str] = None) -> Dict[str, float]: - """Score one crop, keyed by canonical SKU. + """Score one crop, keyed by canonical SKU, in the lane's rank order. + + The insertion order is the ranking and callers rely on it: the local + lane's order comes from its rank key while its value is the margin over + the runner-up, so re-sorting by value names a different SKU than the + lane chose. `list(scores.items())` is therefore the ranked sequence. Every backend groups by SKU before returning. Scoring each reference view separately is what made the demo's default catalog report 22-29 of diff --git a/recognization/code/eval_identity.py b/recognization/code/eval_identity.py index f664a1f..1e12e51 100644 --- a/recognization/code/eval_identity.py +++ b/recognization/code/eval_identity.py @@ -22,7 +22,7 @@ detector). The hybrid lane also reports shortlist recall, because a true SKU outside the shortlist is a hard ceiling no verifier can lift. python code/eval_identity.py \ - --labels docs/research/2026-09-28-recognition-architecture/evidence/image6_v2.json \ + --labels eval/labels/image6.json \ --image add/image6.jpg --stock-dir stock-lopia-clean --lanes matcher --live Labels are {"image", "facings": [{"box", "label"}]} with "unknown" for facings @@ -70,7 +70,7 @@ LIVE_LONG_SIDE = 1280 # Pixel equality is not a leak test: a template re-cut from the same photo with # a different box passes a same-shape comparison. A 64x64 grayscale signature # catches most of those, but it is a heuristic, not a proof — measured on -# image6_v2 against stock-lopia, re-cuts in the realistic 0.94..1.06 box band +# the corrected labels against stock-lopia, re-cuts in the realistic 0.94..1.06 box band # land 7..37 MAD from their facing's signature while the closest pair of # genuinely distinct same-SKU facings is 23.1, so the distributions overlap and # no threshold is clean. 20.0 catches 81% of that band with zero false @@ -116,12 +116,13 @@ def file_hash(path: str) -> Optional[str]: def catalog_hash(stock_dir: str) -> Optional[str]: - """SHA-256 over the catalog's CSV bytes and its image names. + """SHA-256 over the catalog's CSV bytes and each view's bytes. - Image bytes are not hashed: a re-encoded view of the same product is the - same catalog, and hashing every packshot would make the number move for - reasons that do not change a single decision. A changed row or a different - set of views does change it. + The view bytes are hashed, not just their names. Names alone were not + enough: replacing `sku_l09.jpg` with a different product's packshot left + the hash unchanged, so a report could claim the same catalog while every + l09 decision in it had moved. Re-encoding the same image does move the + hash, which is the price of not being able to lie about what was scored. """ digest = hashlib.sha256() csv_path = os.path.join(stock_dir, "stock.csv") @@ -137,8 +138,14 @@ def catalog_hash(stock_dir: str) -> Optional[str]: ) except OSError: names = [] - digest.update(b"\n") - digest.update("\n".join(names).encode("utf-8")) + for name in names: + digest.update(b"\n") + digest.update(name.encode("utf-8")) + try: + with open(os.path.join(stock_dir, name), "rb") as handle: + digest.update(handle.read()) + except OSError: + digest.update(b"unreadable") return digest.hexdigest() @@ -557,7 +564,7 @@ def shortlist_recall( shortlist already dropped. The denominator is enrolled facings only — a facing whose SKU has no reference cannot be retrieved by any shortlist, so counting it here reports a retrieval failure that is really a catalog gap. - Measured on image6_v2, that distinction is 67% vs 98% at top-5. + Measured on the corrected labels, that distinction is 67% vs 98% at top-5. """ hits = total = 0 misses: List[Dict[str, Any]] = [] diff --git a/recognization/code/identity_lanes.py b/recognization/code/identity_lanes.py index b6af8b3..b730d9f 100644 --- a/recognization/code/identity_lanes.py +++ b/recognization/code/identity_lanes.py @@ -27,7 +27,6 @@ import math import os import re import sys -import unicodedata from dataclasses import dataclass from typing import Any, Dict, List, Optional, Sequence, Tuple @@ -38,7 +37,7 @@ if current_dir not in sys.path: import cv2 # noqa: E402 import numpy as np # noqa: E402 -from rebuild_catalog import sku_of # noqa: E402 +from rebuild_catalog import bigrams, normalize_text, sku_of # noqa: E402 # The local lane's accept line, in the units of `confidence()` below. Measured # on the corrected image6 labels: 2.0 keeps 95% of shown labels correct at 59% @@ -258,23 +257,10 @@ class LocalLane: return {sku: value for sku, value in self.rank(crop)} -# Katakana folding: OCR reads small kana and the long-vowel mark inconsistently, -# so キユーピー and キユピー have to land on the same bigrams. -_KANA_FOLD = str.maketrans( - "ッャュョァィゥェォヮヵヶユ", "ツヤユヨアイウエオワカケユ" -) - - -def normalize_text(text: str) -> str: - """NFKC, uppercase, kana-folded, alphanumeric and `%` only.""" - text = unicodedata.normalize("NFKC", text).upper() - text = text.translate(_KANA_FOLD) - text = text.replace("キユーピー", "キユピ").replace("キューピー", "キユピ") - return "".join(ch for ch in text if ch.isalnum() or ch == "%") - - -def bigrams(text: str) -> set: - return {text[i:i + 2] for i in range(len(text) - 1)} +# Text normalization and bigrams come from `rebuild_catalog`, which uses them +# to match a catalog name against a packshot's OCR. Two copies of the same +# folding rules drift: the lane's copy folded ユ to itself while the catalog's +# did not, so the same read scored differently depending on which one ran. def identity_bigrams(read: str) -> set: diff --git a/recognization/code/test_engine.py b/recognization/code/test_engine.py index 7bafafa..90a2aab 100644 --- a/recognization/code/test_engine.py +++ b/recognization/code/test_engine.py @@ -564,6 +564,51 @@ class DecisionPolicyTests(unittest.TestCase): self.assertEqual(decision["identity_level"], "rejected") +class LocalLaneConcurrencyTests(unittest.TestCase): + """The lane is shared by the classify pool, so `rank` must be thread-safe. + + One `cv2.BFMatcher` is reused across calls. The classify pool runs up to + eight workers, so a lane that mutated matcher state per call would return + another crop's answer under load - the failure would look like a + recognition error, not a crash. + """ + + def test_concurrent_ranking_matches_solo_ranking(self): + import threading + + import cv2 + + from identity_lanes import LocalLane + + stock_dir = os.path.join(os.path.dirname(current_dir), "stock-lopia-clean") + if not os.path.isdir(stock_dir): + self.skipTest("no catalog checked out") + image_path = os.path.join(os.path.dirname(current_dir), "add", "image6.jpg") + if not os.path.isfile(image_path): + self.skipTest("no evaluation photo checked out") + lane = LocalLane(stock_dir) + image = cv2.imread(image_path) + crops = [image[700:1000, 600 + 40 * i:800 + 40 * i] for i in range(8)] + solo = lane.rank(crops[0]) + results = {} + errors = [] + + def work(index: int) -> None: + try: + for _ in range(6): + results[index] = lane.rank(crops[index]) + except Exception as error: # noqa: BLE001 - reported below + errors.append(repr(error)) + + threads = [threading.Thread(target=work, args=(i,)) for i in range(8)] + for thread in threads: + thread.start() + for thread in threads: + thread.join() + self.assertEqual(errors, []) + self.assertEqual(results[0], solo, "a shared matcher must not cross crops") + + class CatalogImageTests(unittest.TestCase): def test_catalog_image_path_is_resolved_through_inventory(self): engine, _, _, _ = make_engine() diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/DECISION.md b/recognization/docs/research/2026-09-28-recognition-architecture/DECISION.md index f555928..ab0ba66 100644 --- a/recognization/docs/research/2026-09-28-recognition-architecture/DECISION.md +++ b/recognization/docs/research/2026-09-28-recognition-architecture/DECISION.md @@ -112,7 +112,7 @@ verification → calibrated open-set decision → temporal accumulation. ### The four ceilings, separated -On corrected labels (`evidence/image6_v2.json`): 109 scored facings, 61 +On corrected labels (`eval/labels/image6.json`): 109 scored facings, 61 in-catalog across 11 SKUs, 48 unknown, 2 excluded. The clean catalog enrolls 7 SKUs covering 42 of the 61 in-catalog facings. @@ -288,7 +288,7 @@ rank, decision, lane latencies), and report the four ceilings separately. ### Benchmark tiers (build these first; they block every other decision) -- **Tier 1, diagnostic:** `evidence/image6_v2.json` (109 facings). Dev only. +- **Tier 1, diagnostic:** `eval/labels/image6.json` (109 facings). Dev only. Free to tune on. Its numbers never ship. - **Tier 2, held-out regression:** new captures that are never enrolled and never tuned on. At least 3 visits across ≥ 2 LOPIA locations or days, same @@ -335,7 +335,7 @@ reverted. | `test_live.py` change | encodes the reverted budget | Revert with it. | | `code/rebuild_catalog.py` (untracked) | catalog tooling | Keep. Add image↔CSV bijection, packshot-OCR vs name check, and eval-session refusal (enrollment protocol below). | | `stock-lopia-clean/` (untracked) | catalog data | Keep the images and provenance. Fix `stock.csv` (F-04) and the README's "Six SKUs" (it lists five). Replace the l06 packshot with the current package. | -| `eval/labels/image6.json` (untracked) | ground truth | **Replace** with `evidence/image6_v2.json`, schema: `label`, `source`, `note`, `v1_label`. | +| `eval/labels/image6.json` | ground truth | Adopted; schema: `label`, `source`, `note`, `v1_label`. | | `identity.decide_identity` inlier branch | production | **Rewrite** as the calibrated decision (E-4); keep the cosine branch only while the gallery exists. | | Production score path (`engine.score_crop`, `classify_boxes`, `inspect`) | production | **Rewrite:** return per-SKU evidence grouped by canonical SKU (F-02). | | `feature_matcher.py` composite score | production | **Rewrite** into variant B behind an interface; keep Van's scorer as a selectable baseline lane for E-1. | @@ -431,7 +431,7 @@ covers a recognition backend. The product-level floor is Van's system (G1–G4). - **Evidence:** `evidence/image6-v1-labels-overlay.jpg`; the per-index list in §3. Rescoring the same runs under v2 moves ungated live top-1 from 26/35 to 35/42. - **Target:** every scored label carries provenance; ambiguous facings are excluded. -- **Change:** adopt `evidence/image6_v2.json`; schema-check `label/source/note`. +- **Change:** adopt `eval/labels/image6.json`; schema-check `label/source/note`. - **Validation:** E-0 double-labelling on Tier 2. - **Acceptance:** no architecture claim cites v1. @@ -602,7 +602,7 @@ and overstates its precision, so the evaluator now has a `van` lane: the same scores, always answered. Every "vs Van" claim in this record uses that row. .venv/bin/python code/eval_identity.py --stock stock-lopia-clean \ - --labels docs/research/2026-09-28-recognition-architecture/evidence/image6_v2.json \ + --labels eval/labels/image6.json \ --image add/image6.jpg --lanes van,matcher,local --live full resolution — 109 scored facings (61 in-catalog, 48 unknown) @@ -673,7 +673,7 @@ Two further review findings, both fixed and both measured: The headline number is reproducible from the repo, not from a scratch script: .venv/bin/python code/eval_identity.py --stock stock-lopia-clean \ - --labels docs/research/2026-09-28-recognition-architecture/evidence/image6_v2.json \ + --labels eval/labels/image6.json \ --image add/image6.jpg --lanes local --live live resolution: catalog 69% · identity 86% · decision 86% · diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/README.md b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/README.md index 1779ce0..1fb166d 100644 --- a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/README.md +++ b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/README.md @@ -3,16 +3,16 @@ Read-only against product code: every script imports from `code/` and writes only into this folder. Run from `recognization/` with `.venv/bin/python`. -`image6_v2.json` is the corrected image6 label set (26 of 111 v1 labels +`eval/labels/image6.json` is the corrected image6 label set (26 of 111 v1 labels changed; every row carries `v1_label`, `source`, and a `note` where changed). `image6-v1-labels-overlay.jpg` shows the v1 labels on the shelf; green = catalog label, red = unknown. `sheet.py` regenerates per-SKU contact sheets. | Step | Command (prefix `E=docs/research/2026-09-28-recognition-architecture/evidence`) | Produces | |---|---|---| -| Original matcher, both catalogs, full/live/live-with-unscaled-boxes | `.venv/bin/python $E/diag.py --stock stock-lopia-clean --labels $E/image6_v2.json [--live] [--bug] --out $E/run_stock-lopia-clean_.pkl` (repeat with `--stock stock-lopia`) | `run_*.pkl` | +| Original matcher, both catalogs, full/live/live-with-unscaled-boxes | `.venv/bin/python $E/diag.py --stock stock-lopia-clean --labels $E/../../../eval/labels/image6.json [--live] [--bug] --out $E/run_stock-lopia-clean_.pkl` (repeat with `--stock stock-lopia`) | `run_*.pkl` | | Score them under v1 or v2 labels | `.venv/bin/python $E/analyze.py $E/run_*.pkl` | identity top-1, argmax, current gate | -| Matcher variants | `.venv/bin/python $E/variants.py --stock stock-lopia-clean --labels $E/image6_v2.json [--live] --scales 200,400 --root --geom affine --out $E/v_ms_root_aff_.pkl` (also `--tmpl-h 250/400`, no flags = raw) | `v_*.pkl` | +| Matcher variants | `.venv/bin/python $E/variants.py --stock stock-lopia-clean --labels $E/../../../eval/labels/image6.json [--live] --scales 200,400 --root --geom affine --out $E/v_ms_root_aff_.pkl` (also `--tmpl-h 250/400`, no flags = raw) | `v_*.pkl` | | Variant ranking + open-set frontier | `.venv/bin/python $E/an2.py $E $(basename -a $E/v_*.pkl)` (`LABELS=image6_v2_lfo.json` for the leave-facing-out runs) | correct at 100/95/90 % precision | | Leave-facing-out catalog | `.venv/bin/python $E/lfo_setup.py`, then `variants.py --stock $E/cat_ --labels $E/image6_v2_lfo.json --scales 200,400 --root --geom affine [--live] --out $E/lfo_cat__.pkl` | `lfo_*.pkl` | | Unrelated-shelf distractors | `YOLO_OFFLINE=1 .venv/bin/python $E/distract.py stock-lopia-clean $E/cat_full` | `distract.pkl` | @@ -44,7 +44,7 @@ with no arguments raise `IndexError`; neither validates its own usage. v1 labels are no longer a file on disk — `eval/labels/image6.json` is the v2 set. To score a run under v1, rebuild it from the `v1_label` field: - .venv/bin/python -c "import json;d=json.load(open('$E/image6_v2.json'));\ + .venv/bin/python -c "import json;d=json.load(open('$E/../../../eval/labels/image6.json'));\ [f.update(label=f.pop('v1_label')) for f in d['facings']];\ json.dump(d,open('/tmp/image6_v1.json','w'),ensure_ascii=False)" diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/an2.py b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/an2.py index 5174adb..598fb29 100644 --- a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/an2.py +++ b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/an2.py @@ -1,5 +1,5 @@ import pickle, json, sys, numpy as np, collections -import os; S = sys.argv[1]; L = {f['index']: f['label'] for f in json.load(open(f'{S}/' + os.environ.get('LABELS','image6_v2.json')))['facings']} +import os; S = sys.argv[1]; L = {f['index']: f['label'] for f in json.load(open(f'{S}/' + os.environ.get('LABELS','../../../../eval/labels/image6.json')))['facings']} RANK = { 'inl': lambda e: e['inliers'], 'inl*col': lambda e: e['inliers'] * (0.25 + e['color']), diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l01.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l01.jpg new file mode 100644 index 0000000..e35eb97 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l01.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l01_shelf.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l01_shelf.jpg new file mode 100644 index 0000000..5a079a9 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l01_shelf.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l02.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l02.jpg new file mode 100644 index 0000000..086c12d Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l02.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l02_shelf.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l02_shelf.jpg new file mode 100644 index 0000000..e2e95d5 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l02_shelf.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l03.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l03.jpg new file mode 100644 index 0000000..597f2c2 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l03.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l03_shelf.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l03_shelf.jpg new file mode 100644 index 0000000..8b4b0fa Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l03_shelf.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l05.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l05.jpg new file mode 100644 index 0000000..009e5aa Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l05.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l05_shelf.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l05_shelf.jpg new file mode 100644 index 0000000..25df422 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l05_shelf.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l06.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l06.jpg new file mode 100644 index 0000000..0fb6c11 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l06.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l06_shelf.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l06_shelf.jpg new file mode 100644 index 0000000..255842f Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l06_shelf.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l07_shelf.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l07_shelf.jpg new file mode 100644 index 0000000..cf85f61 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l07_shelf.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l09.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l09.jpg new file mode 100644 index 0000000..661e797 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l09.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l09_shelf.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l09_shelf.jpg new file mode 100644 index 0000000..4353a95 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l09_shelf.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l10_shelf.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l10_shelf.jpg new file mode 100644 index 0000000..9d3dcf8 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l10_shelf.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l11.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l11.jpg new file mode 100644 index 0000000..a54c358 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l11.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l11_shelf.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l11_shelf.jpg new file mode 100644 index 0000000..b8da93e Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_full/sku_l11_shelf.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l01.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l01.jpg new file mode 100644 index 0000000..e35eb97 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l01.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l02.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l02.jpg new file mode 100644 index 0000000..086c12d Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l02.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l03.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l03.jpg new file mode 100644 index 0000000..597f2c2 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l03.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l05.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l05.jpg new file mode 100644 index 0000000..009e5aa Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l05.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l06.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l06.jpg new file mode 100644 index 0000000..0fb6c11 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l06.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l09.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l09.jpg new file mode 100644 index 0000000..661e797 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l09.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l11.jpg b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l11.jpg new file mode 100644 index 0000000..a54c358 Binary files /dev/null and b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/cat_pack/sku_l11.jpg differ diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/dino_scale.py b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/dino_scale.py index 2d963d7..64d7ae4 100644 --- a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/dino_scale.py +++ b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/dino_scale.py @@ -16,7 +16,7 @@ for p in sorted(glob.glob('add/*')): if min(c.shape[:2])>=40: dis.append((f'd{j}_{os.path.basename(p)}',c)) random.shuffle(dis) D=[(k,g.embed(c)) for k,c in dis] -L=json.load(open(f'{S}/image6_v2.json')); E={k for k,_ in refs} +L=json.load(open(f'{S}/../../../../eval/labels/image6.json')); E={k for k,_ in refs} Q=[(fc['label'],g.embed(c)) for fc,c in crops('add/image6.jpg',L,True) if fc['label'] in E] t=time.perf_counter(); _=g.embed(Q and dis[0][1]); print('embed ms',round((time.perf_counter()-t)*1000,1)) for N in [0,50,200,len(D)]: diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/fuse_eval.py b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/fuse_eval.py index fe2a092..360989a 100644 --- a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/fuse_eval.py +++ b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/fuse_eval.py @@ -2,7 +2,7 @@ import sys,os,json,pickle,csv,numpy as np S=os.path.dirname(os.path.abspath(__file__)); sys.path.insert(0,S) from ocr_fuse import norm,sim # noqa (module runs OCR of packshots on import; cheap) sig=pickle.load(open(f'{S}/sig.pkl','rb')); O=pickle.load(open(f'{S}/ocr.pkl','rb')) -L={f['index']:f['label'] for f in json.load(open(f'{S}/image6_v2.json'))['facings']} +L={f['index']:f['label'] for f in json.load(open(f'{S}/../../../../eval/labels/image6.json'))['facings']} def conf(ev): r=sorted(ev.items(),key=lambda kv:-kv[1]['inliers']*(0.25+kv[1]['color'])) (k1,e1),(k2,e2)=r[0],r[1]; i1,i2=e1['inliers'],e2['inliers'] diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/image6_v2.json b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/image6_v2.json deleted file mode 100644 index 70210e3..0000000 --- a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/image6_v2.json +++ /dev/null @@ -1,1478 +0,0 @@ -{ - "image": "add/image6.jpg", - "facings": [ - { - "box": [ - 39, - 56, - 143, - 313 - ], - "label": "sku_l01", - "match": 1.0, - "index": 0, - "source": "v1-confirmed-visual", - "v1_label": "sku_l01" - }, - { - "box": [ - 147, - 53, - 264, - 318 - ], - "label": "sku_l01", - "match": 1.0, - "index": 1, - "source": "v1-confirmed-visual", - "v1_label": "sku_l01" - }, - { - "box": [ - 1419, - 0, - 1500, - 107 - ], - "label": "exclude", - "match": 1.0, - "index": 2, - "note": "blurred corner of upper shelf; not identifiable", - "source": "visual-audit-2026-09-28", - "v1_label": "sku_l04" - }, - { - "box": [ - 270, - 64, - 377, - 322 - ], - "label": "sku_l01", - "match": 1.0, - "index": 3, - "source": "v1-confirmed-visual", - "v1_label": "sku_l01" - }, - { - "box": [ - 382, - 72, - 467, - 324 - ], - "label": "sku_l01", - "match": 0.0, - "index": 4, - "note": "Egg Care front, same tag run as #0-3", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 472, - 64, - 570, - 328 - ], - "label": "sku_l01", - "match": 0.0, - "index": 5, - "note": "Egg Care front", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 575, - 137, - 639, - 330 - ], - "label": "sku_l02", - "match": 1.0, - "index": 6, - "source": "v1-confirmed-visual", - "v1_label": "sku_l02" - }, - { - "box": [ - 641, - 126, - 732, - 337 - ], - "label": "sku_l02", - "match": 1.0, - "index": 7, - "source": "v1-confirmed-visual", - "v1_label": "sku_l02" - }, - { - "box": [ - 736, - 123, - 817, - 339 - ], - "label": "sku_l02", - "match": 1.0, - "index": 8, - "source": "v1-confirmed-visual", - "v1_label": "sku_l02" - }, - { - "box": [ - 822, - 135, - 909, - 345 - ], - "label": "sku_l02", - "match": 1.0, - "index": 9, - "source": "v1-confirmed-visual", - "v1_label": "sku_l02" - }, - { - "box": [ - 959, - 160, - 1044, - 349 - ], - "label": "sku_l03", - "match": 1.0, - "index": 10, - "source": "v1-confirmed-visual", - "v1_label": "sku_l03" - }, - { - "box": [ - 1049, - 158, - 1138, - 348 - ], - "label": "sku_l03", - "match": 1.0, - "index": 11, - "source": "v1-confirmed-visual", - "v1_label": "sku_l03" - }, - { - "box": [ - 1143, - 144, - 1228, - 353 - ], - "label": "sku_l03", - "match": 1.0, - "index": 12, - "source": "v1-confirmed-visual", - "v1_label": "sku_l03" - }, - { - "box": [ - 1233, - 147, - 1352, - 356 - ], - "label": "sku_l03", - "match": 1.0, - "index": 13, - "source": "v1-confirmed-visual", - "v1_label": "sku_l03" - }, - { - "box": [ - 1375, - 152, - 1475, - 365 - ], - "label": "sku_l04", - "match": 1.0, - "index": 14, - "source": "v1-confirmed-visual", - "v1_label": "sku_l04" - }, - { - "box": [ - 1482, - 155, - 1500, - 363 - ], - "label": "exclude", - "match": 0.0, - "index": 15, - "note": "18 px sliver", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 0, - 472, - 76, - 662 - ], - "label": "unknown", - "match": 1.0, - "index": 16, - "note": "garlic jar, not mayo", - "source": "visual-audit-2026-09-28", - "v1_label": "sku_l05" - }, - { - "box": [ - 86, - 420, - 163, - 664 - ], - "label": "sku_l05", - "match": 1.0, - "index": 17, - "source": "v1-confirmed-visual", - "v1_label": "sku_l05" - }, - { - "box": [ - 167, - 420, - 265, - 662 - ], - "label": "sku_l05", - "match": 1.0, - "index": 18, - "source": "v1-confirmed-visual", - "v1_label": "sku_l05" - }, - { - "box": [ - 270, - 426, - 366, - 664 - ], - "label": "sku_l05", - "match": 1.0, - "index": 19, - "source": "v1-confirmed-visual", - "v1_label": "sku_l05" - }, - { - "box": [ - 476, - 446, - 571, - 669 - ], - "label": "sku_l06", - "match": 1.0, - "index": 20, - "source": "v1-confirmed-visual", - "v1_label": "sku_l06" - }, - { - "box": [ - 583, - 458, - 678, - 672 - ], - "label": "sku_l06", - "match": 1.0, - "index": 21, - "source": "v1-confirmed-visual", - "v1_label": "sku_l06" - }, - { - "box": [ - 683, - 454, - 774, - 672 - ], - "label": "sku_l06", - "match": 0.0, - "index": 22, - "note": "Fitte front", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 778, - 459, - 865, - 675 - ], - "label": "sku_l06", - "match": 0.0, - "index": 23, - "note": "Fitte front", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 871, - 466, - 945, - 674 - ], - "label": "sku_l07", - "match": 1.0, - "index": 24, - "source": "v1-confirmed-visual", - "v1_label": "sku_l07" - }, - { - "box": [ - 949, - 471, - 1020, - 674 - ], - "label": "sku_l07", - "match": 1.0, - "index": 25, - "source": "v1-confirmed-visual", - "v1_label": "sku_l07" - }, - { - "box": [ - 1024, - 493, - 1098, - 676 - ], - "label": "sku_l07", - "match": 1.0, - "index": 26, - "source": "v1-confirmed-visual", - "v1_label": "sku_l07" - }, - { - "box": [ - 1103, - 494, - 1176, - 676 - ], - "label": "sku_l07", - "match": 0.0, - "index": 27, - "note": "Lucky Mayonnaise front", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 1181, - 499, - 1245, - 676 - ], - "label": "sku_l07", - "match": 0.0, - "index": 28, - "note": "Lucky Mayonnaise front", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 1249, - 480, - 1331, - 676 - ], - "label": "sku_l07", - "match": 1.0, - "index": 29, - "note": "Lucky Mayonnaise front; was l08", - "source": "visual-audit-2026-09-28", - "v1_label": "sku_l08" - }, - { - "box": [ - 1336, - 502, - 1421, - 682 - ], - "label": "sku_l08", - "match": 1.0, - "index": 30, - "source": "v1-confirmed-visual", - "v1_label": "sku_l08" - }, - { - "box": [ - 0, - 751, - 108, - 977 - ], - "label": "unknown", - "match": 1.0, - "index": 31, - "note": "demi-glace sauce pouch; was l09", - "source": "visual-audit-2026-09-28", - "v1_label": "sku_l09" - }, - { - "box": [ - 115, - 758, - 193, - 973 - ], - "label": "unknown", - "match": 1.0, - "index": 32, - "note": "demi-glace sauce pouch; was l09", - "source": "visual-audit-2026-09-28", - "v1_label": "sku_l09" - }, - { - "box": [ - 199, - 758, - 255, - 971 - ], - "label": "sku_l09", - "match": 1.0, - "index": 33, - "source": "v1-confirmed-visual", - "v1_label": "sku_l09" - }, - { - "box": [ - 258, - 758, - 352, - 976 - ], - "label": "sku_l09", - "match": 1.0, - "index": 34, - "source": "v1-confirmed-visual", - "v1_label": "sku_l09" - }, - { - "box": [ - 357, - 761, - 449, - 973 - ], - "label": "sku_l09", - "match": 1.0, - "index": 35, - "source": "v1-confirmed-visual", - "v1_label": "sku_l09" - }, - { - "box": [ - 452, - 755, - 514, - 972 - ], - "label": "sku_l09", - "match": 1.0, - "index": 36, - "source": "v1-confirmed-visual", - "v1_label": "sku_l09" - }, - { - "box": [ - 519, - 759, - 608, - 974 - ], - "label": "sku_l09", - "match": 1.0, - "index": 37, - "source": "v1-confirmed-visual", - "v1_label": "sku_l09" - }, - { - "box": [ - 614, - 759, - 700, - 973 - ], - "label": "sku_l09", - "match": 1.0, - "index": 38, - "source": "v1-confirmed-visual", - "v1_label": "sku_l09" - }, - { - "box": [ - 704, - 763, - 791, - 973 - ], - "label": "sku_l09", - "match": 1.0, - "index": 39, - "source": "v1-confirmed-visual", - "v1_label": "sku_l09" - }, - { - "box": [ - 798, - 765, - 916, - 974 - ], - "label": "sku_l09", - "match": 0.0, - "index": 40, - "note": "Kokuuma 65% front", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 919, - 763, - 973, - 974 - ], - "label": "sku_l09", - "match": 0.0, - "index": 41, - "note": "Kokuuma 65% partly occluded", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 977, - 765, - 1067, - 974 - ], - "label": "sku_l09", - "match": 0.0, - "index": 42, - "note": "Kokuuma 65% front", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 1070, - 762, - 1134, - 975 - ], - "label": "sku_l09", - "match": 0.0, - "index": 43, - "note": "Kokuuma 65% partly occluded", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 1138, - 767, - 1218, - 973 - ], - "label": "sku_l09", - "match": 0.0, - "index": 44, - "note": "Kokuuma 65% front", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 1221, - 768, - 1281, - 972 - ], - "label": "sku_l09", - "match": 0.0, - "index": 45, - "note": "Kokuuma 65% partly occluded", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 1285, - 794, - 1359, - 972 - ], - "label": "unknown", - "match": 0.0, - "index": 46, - "note": "ユーラス 野菜をおいしく食べる旨たれ 380g; possibly what stock.csv calls l12", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 1363, - 794, - 1440, - 973 - ], - "label": "unknown", - "match": 0.0, - "index": 47, - "note": "same tare bottle", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 1443, - 794, - 1500, - 973 - ], - "label": "unknown", - "match": 0.0, - "index": 48, - "note": "same tare bottle, partial", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 191, - 1060, - 297, - 1266 - ], - "label": "sku_l10", - "match": 1.0, - "index": 49, - "source": "v1-confirmed-visual", - "v1_label": "sku_l10" - }, - { - "box": [ - 306, - 1058, - 436, - 1260 - ], - "label": "sku_l10", - "match": 1.0, - "index": 50, - "source": "v1-confirmed-visual", - "v1_label": "sku_l10" - }, - { - "box": [ - 441, - 1060, - 538, - 1256 - ], - "label": "sku_l10", - "match": 1.0, - "index": 51, - "source": "v1-confirmed-visual", - "v1_label": "sku_l10" - }, - { - "box": [ - 542, - 1060, - 628, - 1251 - ], - "label": "sku_l10", - "match": 1.0, - "index": 52, - "source": "v1-confirmed-visual", - "v1_label": "sku_l10" - }, - { - "box": [ - 630, - 1055, - 680, - 1249 - ], - "label": "sku_l10", - "match": 1.0, - "index": 53, - "source": "v1-confirmed-visual", - "v1_label": "sku_l10" - }, - { - "box": [ - 685, - 1058, - 783, - 1251 - ], - "label": "sku_l10", - "match": 1.0, - "index": 54, - "source": "v1-confirmed-visual", - "v1_label": "sku_l10" - }, - { - "box": [ - 789, - 1056, - 876, - 1246 - ], - "label": "sku_l10", - "match": 1.0, - "index": 55, - "source": "v1-confirmed-visual", - "v1_label": "sku_l10" - }, - { - "box": [ - 878, - 1055, - 968, - 1246 - ], - "label": "sku_l10", - "match": 1.0, - "index": 56, - "source": "v1-confirmed-visual", - "v1_label": "sku_l10" - }, - { - "box": [ - 1044, - 1054, - 1113, - 1248 - ], - "label": "sku_l10", - "match": 1.0, - "index": 57, - "source": "v1-confirmed-visual", - "v1_label": "sku_l10" - }, - { - "box": [ - 1114, - 1051, - 1196, - 1247 - ], - "label": "sku_l10", - "match": 1.0, - "index": 58, - "source": "v1-confirmed-visual", - "v1_label": "sku_l10" - }, - { - "box": [ - 1199, - 1050, - 1280, - 1247 - ], - "label": "sku_l10", - "match": 0.0, - "index": 59, - "note": "Pure Select mayonnaise front", - "source": "visual-audit-2026-09-28", - "v1_label": "unknown" - }, - { - "box": [ - 1280, - 1061, - 1317, - 1244 - ], - "label": "unknown", - "match": 0.0, - "index": 60, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 1319, - 1068, - 1389, - 1240 - ], - "label": "unknown", - "match": 0.0, - "index": 61, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 1393, - 1067, - 1467, - 1241 - ], - "label": "unknown", - "match": 0.0, - "index": 62, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 1478, - 1068, - 1500, - 1242 - ], - "label": "unknown", - "match": 0.0, - "index": 63, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 64, - 1142, - 150, - 1264 - ], - "label": "unknown", - "match": 1.0, - "index": 64, - "note": "Heinz can; was l10", - "source": "visual-audit-2026-09-28", - "v1_label": "sku_l10" - }, - { - "box": [ - 0, - 1379, - 51, - 1561 - ], - "label": "unknown", - "match": 0.0, - "index": 65, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 60, - 1374, - 163, - 1560 - ], - "label": "unknown", - "match": 0.0, - "index": 66, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 190, - 1339, - 296, - 1562 - ], - "label": "sku_l11", - "match": 1.0, - "index": 67, - "source": "v1-confirmed-visual", - "v1_label": "sku_l11" - }, - { - "box": [ - 298, - 1335, - 404, - 1558 - ], - "label": "sku_l11", - "match": 1.0, - "index": 68, - "source": "v1-confirmed-visual", - "v1_label": "sku_l11" - }, - { - "box": [ - 421, - 1333, - 524, - 1549 - ], - "label": "sku_l11", - "match": 1.0, - "index": 69, - "source": "v1-confirmed-visual", - "v1_label": "sku_l11" - }, - { - "box": [ - 529, - 1332, - 626, - 1546 - ], - "label": "sku_l11", - "match": 1.0, - "index": 70, - "source": "v1-confirmed-visual", - "v1_label": "sku_l11" - }, - { - "box": [ - 634, - 1328, - 729, - 1541 - ], - "label": "sku_l11", - "match": 1.0, - "index": 71, - "source": "v1-confirmed-visual", - "v1_label": "sku_l11" - }, - { - "box": [ - 734, - 1326, - 831, - 1538 - ], - "label": "sku_l11", - "match": 1.0, - "index": 72, - "source": "v1-confirmed-visual", - "v1_label": "sku_l11" - }, - { - "box": [ - 836, - 1326, - 924, - 1535 - ], - "label": "sku_l11", - "match": 1.0, - "index": 73, - "source": "v1-confirmed-visual", - "v1_label": "sku_l11" - }, - { - "box": [ - 930, - 1324, - 1018, - 1532 - ], - "label": "sku_l11", - "match": 1.0, - "index": 74, - "source": "v1-confirmed-visual", - "v1_label": "sku_l11" - }, - { - "box": [ - 1022, - 1320, - 1123, - 1530 - ], - "label": "sku_l11", - "match": 1.0, - "index": 75, - "note": "Kewpie Half front; was l12", - "source": "visual-audit-2026-09-28", - "v1_label": "sku_l12" - }, - { - "box": [ - 1190, - 1331, - 1262, - 1521 - ], - "label": "unknown", - "match": 1.0, - "index": 76, - "note": "Vegiglet dressing; was l12", - "source": "visual-audit-2026-09-28", - "v1_label": "sku_l12" - }, - { - "box": [ - 1266, - 1337, - 1334, - 1516 - ], - "label": "unknown", - "match": 1.0, - "index": 77, - "note": "Vegiglet dressing; was l12", - "source": "visual-audit-2026-09-28", - "v1_label": "sku_l12" - }, - { - "box": [ - 1337, - 1335, - 1403, - 1514 - ], - "label": "unknown", - "match": 1.0, - "index": 78, - "note": "Vegiglet dressing; was l12", - "source": "visual-audit-2026-09-28", - "v1_label": "sku_l12" - }, - { - "box": [ - 1409, - 1336, - 1475, - 1511 - ], - "label": "unknown", - "match": 1.0, - "index": 79, - "note": "Vegiglet dressing; was l12", - "source": "visual-audit-2026-09-28", - "v1_label": "sku_l12" - }, - { - "box": [ - 1480, - 1327, - 1500, - 1514 - ], - "label": "unknown", - "match": 0.0, - "index": 80, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 593, - 1619, - 679, - 1815 - ], - "label": "unknown", - "match": 0.0, - "index": 81, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 683, - 1617, - 762, - 1809 - ], - "label": "unknown", - "match": 0.0, - "index": 82, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 766, - 1612, - 839, - 1806 - ], - "label": "unknown", - "match": 0.0, - "index": 83, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 842, - 1609, - 909, - 1801 - ], - "label": "unknown", - "match": 0.0, - "index": 84, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 910, - 1607, - 995, - 1796 - ], - "label": "unknown", - "match": 0.911, - "index": 85, - "note": "Kewpie Mayonnaise 450g (not catalog); was l03", - "source": "visual-audit-2026-09-28", - "v1_label": "sku_l03" - }, - { - "box": [ - 999, - 1602, - 1078, - 1793 - ], - "label": "unknown", - "match": 0.0, - "index": 86, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 1083, - 1600, - 1169, - 1787 - ], - "label": "unknown", - "match": 0.0, - "index": 87, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 1173, - 1595, - 1269, - 1783 - ], - "label": "unknown", - "match": 0.0, - "index": 88, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 1306, - 1586, - 1388, - 1771 - ], - "label": "unknown", - "match": 0.0, - "index": 89, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 1390, - 1602, - 1457, - 1767 - ], - "label": "unknown", - "match": 0.0, - "index": 90, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 1461, - 1601, - 1499, - 1769 - ], - "label": "unknown", - "match": 0.0, - "index": 91, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 7, - 1632, - 103, - 1845 - ], - "label": "unknown", - "match": 0.0, - "index": 92, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 107, - 1630, - 199, - 1844 - ], - "label": "unknown", - "match": 0.0, - "index": 93, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 213, - 1631, - 313, - 1834 - ], - "label": "unknown", - "match": 0.0, - "index": 94, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 318, - 1628, - 405, - 1829 - ], - "label": "unknown", - "match": 0.0, - "index": 95, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 409, - 1626, - 491, - 1825 - ], - "label": "unknown", - "match": 0.0, - "index": 96, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 494, - 1622, - 589, - 1821 - ], - "label": "unknown", - "match": 0.0, - "index": 97, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 1059, - 1855, - 1197, - 2000 - ], - "label": "unknown", - "match": 0.0, - "index": 98, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 1216, - 1839, - 1309, - 2000 - ], - "label": "unknown", - "match": 0.0, - "index": 99, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 1313, - 1835, - 1397, - 1999 - ], - "label": "unknown", - "match": 0.0, - "index": 100, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 1404, - 1837, - 1498, - 2000 - ], - "label": "unknown", - "match": 0.0, - "index": 101, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 0, - 1918, - 75, - 1998 - ], - "label": "unknown", - "match": 0.0, - "index": 102, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 82, - 1910, - 187, - 1999 - ], - "label": "unknown", - "match": 0.0, - "index": 103, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 214, - 1897, - 506, - 1998 - ], - "label": "unknown", - "match": 0.0, - "index": 104, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 219, - 1906, - 362, - 2000 - ], - "label": "unknown", - "match": 0.0, - "index": 105, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 363, - 1911, - 500, - 1999 - ], - "label": "unknown", - "match": 0.0, - "index": 106, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 516, - 1882, - 591, - 2000 - ], - "label": "unknown", - "match": 0.0, - "index": 107, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 646, - 1886, - 786, - 2000 - ], - "label": "unknown", - "match": 0.0, - "index": 108, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 790, - 1882, - 887, - 2000 - ], - "label": "unknown", - "match": 0.0, - "index": 109, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - }, - { - "box": [ - 895, - 1862, - 1044, - 2000 - ], - "label": "unknown", - "match": 0.0, - "index": 110, - "source": "v1-confirmed-visual", - "v1_label": "unknown" - } - ], - "version": 2 -} \ No newline at end of file diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/lfo_setup.py b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/lfo_setup.py index 2eba5fc..78c4bd5 100644 --- a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/lfo_setup.py +++ b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/lfo_setup.py @@ -4,7 +4,7 @@ image6_v2_lfo.json with those reference facings excluded from scoring. Same-photo references make this an optimistic proxy, not a held-out result.""" import json, cv2, os, shutil, collections E = os.path.dirname(os.path.abspath(__file__)) -L = json.load(open(f'{E}/image6_v2.json')); im = cv2.imread('add/image6.jpg') +L = json.load(open(f'{E}/../../../../eval/labels/image6.json')); im = cv2.imread('add/image6.jpg') by = collections.defaultdict(list) for f in L['facings']: if f['label'] not in ('unknown', 'exclude'): by[f['label']].append(f) diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/ocr_exp.py b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/ocr_exp.py index 7b1375a..4469929 100644 --- a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/ocr_exp.py +++ b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/ocr_exp.py @@ -3,7 +3,7 @@ sys.path.insert(0,'code'); sys.path.insert(0,os.path.dirname(__file__)) from ocr import VisionOcr from diag import crops S=os.path.dirname(__file__) -L=json.load(open(f'{S}/image6_v2.json')) +L=json.load(open(f'{S}/../../../../eval/labels/image6.json')) # distinguishing tokens per SKU (any hit counts); includes siblings for near-unknowns KEY={'sku_l01':['エッグケア','卵を使って'],'sku_l02':['アマニ'],'sku_l03':['からし','Spicy'],'sku_l04':['めんたい'], 'sku_l05':['ゼロ','ノンコレ'],'sku_l06':['フィッテ','内臓脂肪'],'sku_l07':['ラッキー'],'sku_l08':['PERI','ペリ'], diff --git a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/scale.py b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/scale.py index b591da9..9eaefc0 100644 --- a/recognization/docs/research/2026-09-28-recognition-architecture/evidence/scale.py +++ b/recognization/docs/research/2026-09-28-recognition-architecture/evidence/scale.py @@ -27,7 +27,7 @@ for p in sorted(glob.glob('add/*')): x1,y1,x2,y2=[int(v) for v in b['box']]; c=im[max(0,y1):y2,max(0,x1):x2] if min(c.shape[:2])>=40: dis.append((f'd_{os.path.basename(p)}_{j}',c)) random.shuffle(dis); print('distractor refs available',len(dis)) -L=json.load(open(f'{S}/image6_v2.json')); Q=[(fc,c) for fc,c in crops('add/image6.jpg',L,True) if fc['label']!='exclude' and min(c.shape[:2])>=8] +L=json.load(open(f'{S}/../../../../eval/labels/image6.json')); Q=[(fc,c) for fc,c in crops('add/image6.jpg',L,True) if fc['label']!='exclude' and min(c.shape[:2])>=8] Qf=[(fc['label'],)+feat(c,None) for fc,c in Q] bf=cv2.BFMatcher(cv2.NORM_L2) def verify(kq,dq,r):