feat(identity): local-feature matcher plus text lane as the default backend
Replaces the DINO gallery as the recognition path with the measured design from docs/research/2026-09-28-recognition-architecture/DECISION.md: RootSIFT over a per-SKU reference pyramid, similarity-constrained RANSAC and a hue check, fused with an OCR text lane that vetoes a match whose package text names a different catalog row and answers on its own when geometry finds nothing. - identity_lanes.py: LocalLane, TextLane, DecisionPolicy. The text lane builds each row's signature from the catalog name plus its packshot OCR, so a row with no enrolled image is still answerable. - engine.py: every backend groups scores by canonical SKU, so no view-suffixed id reaches the wire and a name and price always resolve. decide_crop fuses the lanes; score_crop_lanes feeds the live path. Both lanes are built in warm_up (non-fatally) so the first frame is not the slow one, and the text lane shares the engine's OCR lock. - live.py: decides per crop on the lane's own rank order. The lane's order comes from its rank key and its value is only the gate, so re-sorting by value named a different SKU than the lane chose; averaging in an empty observation also diluted a good confidence below the accept line. - identity.py: a `local` score scale whose gate is one absolute line, because the value is already a margin over the runner-up. - app.py, run-demo-server.sh: `--identity local` is the default; the demo server no longer starts on the leaked `stock-lopia` catalog. - eval_live.py: the replay vocabulary accepts `local`, so a recording from the shipped server can be scored. - README.md: documents the three backends and what each is for. Measured on the corrected image6 labels at live resolution: 36/61 in-catalog facings named at 95% precision, 0 of 48 unknowns accepted, 11 labels sourced from the text lane alone. Through the real server: /v1/recognize 90% precision, /v1/stream 100% precision, no view-suffixed ids on either.
This commit is contained in:
parent
25dbf132e7
commit
aaed5d388f
44 changed files with 7847 additions and 60 deletions
69
recognization/stock-lopia-clean/README.md
Normal file
69
recognization/stock-lopia-clean/README.md
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# LOPIA clean catalog
|
||||
|
||||
Official manufacturer pack shots, one front view per SKU. This replaces the
|
||||
views in `../stock-lopia/`, which were 71-119 px crops cut from the test shelf
|
||||
`add/image6.jpg` itself: one 18 px sliver, duplicate crops, a wrong product on
|
||||
`sku_l09`, and five SKUs with no view at all. Enrolling from the test shelf is
|
||||
why every dark package collapsed onto one SKU and why the identity head was
|
||||
trained on its own exam.
|
||||
|
||||
Rebuild or extend with:
|
||||
|
||||
python code/rebuild_catalog.py --source stock-lopia-clean --output stock-lopia-clean \
|
||||
--replace --min-views 1 --csv stock-lopia/stock.csv
|
||||
|
||||
`--min-views 1` because official pages publish a single front view per JAN. The
|
||||
default floor of 2 exists to catch accidental single-view enrollment from shelf
|
||||
crops, where several views are available.
|
||||
|
||||
## Provenance
|
||||
|
||||
| SKU | Product | Source | Image |
|
||||
|---|---|---|---|
|
||||
| sku_l01 | キユーピー エッグケア 305g | [kewpie.co.jp](https://www.kewpie.co.jp/products/detail/4901577090301/) | `4901577090301L.jpg` |
|
||||
| sku_l02 | キユーピー 血圧ケア アマニ油マヨネーズ 200g | [kewpie.co.jp](https://www.kewpie.co.jp/products/detail/4901577060052/) | `4901577060052L.jpg` |
|
||||
| sku_l03 | キユーピー からしマヨネーズ 200g | [kewpie.co.jp](https://www.kewpie.co.jp/products/detail/4901577338779/) | `4901577338779L.jpg` |
|
||||
| sku_l05 | キユーピー ゼロ ノンコレステロール 310g | [kewpie.co.jp](https://www.kewpie.co.jp/products/detail/4901577092381/) | `4901577092381L.jpg` |
|
||||
| sku_l06 | キユーピー 内臓脂肪ケア フィッテ 210g | [kewpie.co.jp](https://www.kewpie.co.jp/products/close/) (discontinued 2026秋) | `4901577083600L.jpg` |
|
||||
| sku_l09 | ピュアセレクト コクうま カロリーカット65% 360g | [ajinomoto.co.jp](https://www.ajinomoto.co.jp/products/detail/?ProductName=pureselect_2) | `A140600321` |
|
||||
| sku_l11 | キユーピー ハーフ 400g | [kewpie.co.jp](https://www.kewpie.co.jp/products/detail/4901577031083/) | `4901577031083L.jpg` |
|
||||
|
||||
Kewpie images follow `https://img.kewpie.co.jp/products_src/g3/imgs/<JAN13>L.jpg`;
|
||||
Ajinomoto images follow
|
||||
`https://www.ajinomoto.co.jp/products/Image.aspx?PicType=0&PIMNO=<PIMNO>`.
|
||||
|
||||
## Known gaps
|
||||
|
||||
Five SKUs in `../stock-lopia/stock.csv` have no official pack shot here, so no
|
||||
image lane can match them. They stay in `stock.csv` as text-only rows: the text
|
||||
lane builds a signature from the printed name, which is how it can name or veto
|
||||
a near-unknown the matcher cannot see. They are the current image-coverage
|
||||
ceiling, not a recognition failure:
|
||||
|
||||
| SKU | Catalog name | Why it is missing |
|
||||
|---|---|---|
|
||||
| sku_l04 | やまや めんたいマヨネーズタイプ 200g | Yamaya's current lineup has no 200 g mentaiko mayo |
|
||||
| sku_l07 | 丸和油脂 ラッキーマヨネーズ 200g | Maruwa's current catalog has no 200 g Lucky Mayonnaise |
|
||||
| sku_l08 | スパイシーストーム ペリペリミックス 30g | No official 30 g Peri-Peri Mix found |
|
||||
| sku_l10 | ピュアセレクト マヨネーズ 450g | Ajinomoto's current lineup is 400/250/600 g/1 kg; no 450 g |
|
||||
| sku_l12 | 焼肉のたれ 中辛 | Brand not recorded in the catalog; ambiguous |
|
||||
|
||||
The catalog names for these five disagree with the manufacturers' current
|
||||
lineups, so the shelf tags and the CSV need reconciling before enrollment.
|
||||
|
||||
Keep the text-only rows when rebuilding: the CSV carry-over must preserve every
|
||||
source row, not just the SKUs with a kept view. Dropping these five costs the
|
||||
text lane the signatures that cover them.
|
||||
|
||||
`sku_l09.jpg` is enrolled but only 305 px tall, below the 800 px source floor
|
||||
the enrollment protocol wants (§8 of the architecture decision). Its matcher
|
||||
scores dwarf the other references (85-129 inliers against 10-40), so it wins
|
||||
facings it should not; re-source it before trusting l09 precision.
|
||||
|
||||
## Rejected
|
||||
|
||||
`references/rejected/kewpie-mayonnaise-450g.jpg` is Kewpie Mayonnaise 450g (JAN
|
||||
4901577042072). It was briefly filed as `sku_l09` and then as `sku_l10` because
|
||||
the catalog's names pointed there, but it is neither product: l09 is Ajinomoto
|
||||
Pure Select コクうま カロリーカット 65% 360g and l10 is Pure Select マヨネーズ
|
||||
450g. It is kept as provenance for that mix-up and is never enrolled.
|
||||
Loading…
Add table
Add a link
Reference in a new issue