Commit graph

4 commits

Author SHA1 Message Date
kiyo9w
5eb4bdf6c8 chore(eval): reconcile the distractor sets and refresh the sweep numbers
The Wikimedia collector truncated the whole basename at 60 characters, so 13
files lost their extension and cv2 could not read them by name - the distractor
sets were quietly scoring 13 images fewer than they held. It now truncates the
stem and keeps the extension, and the files on disk are renamed to match.

The search terms also pull in .djvu volumes whose page 1 Commons serves as a
JPEG thumbnail. Twelve book scans were in the sets; they contributed 0 false
accepts, and they are not shelves, so the collector filters them and the
manifests no longer list them.

With all 2650 crops readable the sweep is re-measured end to end: 3.09% at the
old lines, 0.30% at the shipped 4.0/4, image6 44 shown / 42 correct / 95.5%.
The accept sweep table and the verdict's far-unknown sentence now carry those
numbers instead of the pre-calibration ones.

Also: the fetched images are gitignored (manifests and results are not), the
l10/l11 shelf-tag crops that back the catalog corrections are committed, and a
stale pre-gate eval.json and a duplicate of eval/labels/image6.json are gone.
2026-09-29 04:17:54 +09:00
kiyo9w
601d72296c fix(catalog): correct sku_l10 to 400g and enroll its packshot
Ajinomoto ピュアセレクト マヨネーズ has no 450g size: the official lineup is
250g/400g/600g/1kg, the shelf tag in add/image6.jpg reads 400g, and DECISION.md
already recorded the mismatch. Both CSVs carried 450g, so every l10 answer
shipped a wrong size.

The packshot is the exact 400g front (JAN 4901001114030, 1000x1000) with its
source URL and the 450g rejection recorded in
data/packshots/research/sku_l10/manifest.json.

Enrolling it moves the catalog ceiling from 69% to 87% of in-catalog facings
answerable by image (l10 was 11 unenrolled facings). Measured on the corrected
image6 labels: local lane 92% identity at 84% precision full, 85% at 91% live.

Also points external-eval defaults at the repository-local data path; the
licensed Wikimedia corpus remains uncommitted pending manifest review.
2026-09-29 02:45:21 +09:00
kiyo9w
0e23425ef0 feat: a live path that uses the enrolled store, and a demo server a phone can reach
The live session scored crops with the matcher regardless of the configured identity
backend, so a live scan used the old mechanism while the still path used the enrolled
gallery - measured, the matcher accepts look-alikes and cannot say "unknown", which is
exactly what a real shelf needs it to do. score_crop now routes to the gallery, and
the decision uses a similarity scale (accept at 0.60 with a 0.04 margin) rather than
inlier-count thresholds that mean nothing on a cosine.

The synthetic walk is gone: demo.py, demo_replay.py, the /v1/demo endpoints and the
walk benchmark are deleted, and the app's frame source is the camera on a device (the
single-image replay stays for the simulator, which has no camera).

stock-demo merges both demo shelves (27 products, 62 views, trained head) so one
server recognises either image, and run-demo-server.sh starts it bound to 0.0.0.0 and
prints the exact URL to put in Config.xcconfig.

Verified over the LAN with 1280x960 frames: 40 frames in 5.3s, 9 products recognised
on demo image 1.

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-25 10:51:57 +09:00
kiyo9w
f74366d6a4 test: evaluate on 54 real store photos the pipeline has never seen
Everything else here is measured on two photographs. This collects real store
shelves from Wikimedia Commons (scriptable API, explicit licences: CC0, CC BY,
CC BY-SA, public domain, each recorded in a manifest) and evaluates the pipeline on
them. 46 of 54 images carry a shelf; the rest are book scans and a shop front.

What it found, and it is not what I expected:

- **Detection transfers.** 2,258 detections across dairy cases, soy-sauce shelves,
  spice racks, a confectionery aisle, an Okinawan supermarket and a Hong Kong
  grocery - tight boxes on images the model has never seen, and correctly nothing on
  the book scans.
- **Identity transfers when the product is genuinely there.** On a 2011 milk-case
  photo it labelled six facings of 明治 おいしい牛乳 correctly, and 野菜生活100 and
  R-1 elsewhere. The matcher does reach new photographs of products it has templates
  for.
- **Precision is the failure, and rejection is missing.** In that same photograph it
  labelled 低脂肪殺菌牛乳, 有機豆乳, 特濃4.5, 無調整豆乳 and 北海道牛乳 as おいしい牛乳 -
  they are all white milk cartons. Across 24 shelves whose products are not in the
  catalog it accepted 451 identities, and the score cannot be thresholded to fix it:
  the real shelf's median is 18.2 with a p10 of 5.2, while the foreign shelves' median
  is 6.0 and the worst offenders score 50.5 (a bento), 80.6 (a shop interior) and
  189.9 (deer cookies). A threshold that catches the foreigners also throws away the
  real matches.

That confirms on real data what the literature and the review predicted: the
matcher's raw inlier score is not a confidence, and fine-grained look-alikes are the
failure mode. Step 4 of the plan - shortlist, local re-rank, calibrated rejection -
is the fix, not a refinement.

docs/EXTERNAL-EVAL.md records the numbers, the method and the attribution; the
images themselves are not redistributed. 175 tests pass.

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-25 02:21:00 +09:00