product-recognition-demo/recognization/code
kiyo9w 23fd087611 feat: read a price tag as a card, with the JAN and a tax check
The tag pass read a whole shelf rail and then guessed where one tag ended and
the next began. Measured on the demo shelf, that meant the four tags of the
readable row were not reported at all, and the tags that were reported carried
another tag's text (a 649/754.9 tag came back as price 2630, name
"コプサラダトレッシング"). The box it published was the band, so a tag box lined up
with nothing on the shelf.

Tags are now cards. The OCR engine's own line boxes define them: lines are
clustered into rows (a band's crop also catches the packaging text above and
below), the tag row is chosen by how much it looks like tags, and the cards are
split on the horizontal gap between them. A card's box is the union of its lines,
so it wraps the printed tag. Each card is then re-read at several scales and in
the red channel, and the reads are pooled for voting.

Two things make the fields trustworthy rather than merely plausible:

- Layout separates the price from the JAN. The price is the largest text on the
  tag, so it comes from the tallest line; the JAN's last three digits come from a
  small line. Getting this backwards made a 269 price look like a JAN and vanish.
- The tag checks itself. The small clean number is the tax-included price and the
  big stylised one is the pre-tax price: measured, 269 x 1.08 = 290.52, 379 x 1.08
  = 409.32, 199 x 1.08 = 214.92. When the two agree the price is "measured"; when
  the big digits cannot be read the price is "derived" from the small ones and
  flagged, because a tag that is 3.2x too small to read is still arithmetic.

The JAN's last three digits are now read (they never were before) - on a real
LOPIA tag that is the staff-facing identity anchor printed next to the discount.

Measured on the readable row of add/image6.jpg, against values read by eye:
15 of 15 fields correct across three tags (JAN, price, tax-included price,
discount, name), up from 0 tags reported. 141 tests pass.

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-24 22:07:41 +09:00
..
web feat: price-tag UI, still-image tag passes, and honest tag evidence 2026-09-24 14:11:23 +09:00
__init__.py Initial commit for push folder 2026-09-18 09:13:53 +09:00
app.py perf: bound OCR so a walking scan stays real-time, and add walk pacing 2026-09-24 18:14:32 +09:00
bench_engine.py feat: recognition engine and session tracker for multi-client serving 2026-09-24 11:52:59 +09:00
benchmark.py Initial commit for push folder 2026-09-18 09:13:53 +09:00
demo.py perf: bound OCR so a walking scan stays real-time, and add walk pacing 2026-09-24 18:14:32 +09:00
detector.py refactor: make the matcher and detector safe for concurrent clients 2026-09-24 11:43:24 +09:00
download_stock.py Initial commit for push folder 2026-09-18 09:13:53 +09:00
empty_shelf_detector.py Initial commit for push folder 2026-09-18 09:13:53 +09:00
engine.py feat: price-tag UI, still-image tag passes, and honest tag evidence 2026-09-24 14:11:23 +09:00
fast_test.py Initial commit for push folder 2026-09-18 09:13:53 +09:00
feature_matcher.py feat: recognition server API, reference stream client, and live label memory 2026-09-24 12:31:17 +09:00
gui_app.py Initial commit for push folder 2026-09-18 09:13:53 +09:00
identity.py feat: identity decision contract and session-local observation model 2026-09-24 11:43:41 +09:00
inventory.py Initial commit for push folder 2026-09-18 09:13:53 +09:00
live.py feat: a synthetic store walk, and the live tuning it forced out 2026-09-24 18:09:23 +09:00
observe.py feat: identity decision contract and session-local observation model 2026-09-24 11:43:41 +09:00
ocr.py feat: OCR engine, price-tag geometry, and the cached tag pass 2026-09-24 13:52:15 +09:00
orb.py Initial commit for push folder 2026-09-18 09:13:53 +09:00
pipeline.py feat: identity decision contract and session-local observation model 2026-09-24 11:43:41 +09:00
reconcile.py feat: price-tag UI, still-image tag passes, and honest tag evidence 2026-09-24 14:11:23 +09:00
stream_client.py feat: recognition server API, reference stream client, and live label memory 2026-09-24 12:31:17 +09:00
suft.py Initial commit for push folder 2026-09-18 09:13:53 +09:00
tag_cards.py feat: read a price tag as a card, with the JAN and a tax check 2026-09-24 22:07:41 +09:00
tags.py feat: read a price tag as a card, with the JAN and a tax check 2026-09-24 22:07:41 +09:00
test.py Initial commit for push folder 2026-09-18 09:13:53 +09:00
test_api.py test: defend the live session and the server API 2026-09-24 12:44:54 +09:00
test_demo.py feat: a synthetic store walk, and the live tuning it forced out 2026-09-24 18:09:23 +09:00
test_empty.py Initial commit for push folder 2026-09-18 09:13:53 +09:00
test_engine.py test: defend engine and tracking contracts 2026-09-24 12:43:32 +09:00
test_image.py Initial commit for push folder 2026-09-18 09:13:53 +09:00
test_live.py feat: run the tag pass in parallel with recognition, in live and still modes 2026-09-24 13:58:18 +09:00
test_observe.py feat: identity decision contract and session-local observation model 2026-09-24 11:43:41 +09:00
test_ocr_tags.py feat: read a price tag as a card, with the JAN and a tax check 2026-09-24 22:07:41 +09:00
test_real_model.py docs: API contract, README for the server and live mode, real-model test 2026-09-24 12:46:54 +09:00
test_reconcile.py feat: price-tag UI, still-image tag passes, and honest tag evidence 2026-09-24 14:11:23 +09:00
test_suite.py Initial commit for push folder 2026-09-18 09:13:53 +09:00
test_tag_cards.py feat: read a price tag as a card, with the JAN and a tax check 2026-09-24 22:07:41 +09:00
test_tracking.py test: defend engine and tracking contracts 2026-09-24 12:43:32 +09:00
tracking.py fix: use the tracker imports that exist in ultralytics 8.4.153 2026-09-24 13:36:50 +09:00
train.py Initial commit for push folder 2026-09-18 09:13:53 +09:00
yolo_adapter.py feat: identity decision contract and session-local observation model 2026-09-24 11:43:41 +09:00