diff --git a/recognization/.gitignore b/recognization/.gitignore index 3baa5c9..2d86673 100644 --- a/recognization/.gitignore +++ b/recognization/.gitignore @@ -25,3 +25,14 @@ stock-*/identity_head.pt .gallery_cache_*.npz .demo-token config/local.env + +# Fetched images. Every set keeps its manifest.json (source URL, licence, +# artist) and its results in git; the pixels are re-fetchable from those URLs +# and are 59 MB for the Wikimedia shelves alone. +data/external-shelves/*/*.jpg +data/external-shelves/*/*.jpeg +data/external-shelves/*/*.JPG +data/external-shelves/*/*.png +data/packshots/research/*/images/ +data/packshots/research/*/pages/ +data/packshots/research/*/*.jpg diff --git a/recognization/code/collect_shelf_images.py b/recognization/code/collect_shelf_images.py index f7b3e45..9b9c3b9 100644 --- a/recognization/code/collect_shelf_images.py +++ b/recognization/code/collect_shelf_images.py @@ -141,7 +141,7 @@ def main() -> None: info = image_info(sorted(found)) print(f" metadata for {len(info)} files") - kept, skipped = [], {"license": 0, "size": 0, "missing": 0} + kept, skipped = [], {"license": 0, "size": 0, "missing": 0, "not_a_photo": 0} for title, entry in sorted(info.items()): if not entry.get("url"): skipped["missing"] += 1 @@ -150,6 +150,12 @@ def main() -> None: if not any(token in licence for token in PERMISSIVE): skipped["license"] += 1 continue + # A book scan is not a shelf. The search terms pull in .djvu volumes + # whose page 1 is a title page, and Commons serves those as JPEG + # thumbnails, so the extension check has to be on the source title. + if any(title.lower().endswith(ext) for ext in (".djvu", ".pdf", ".svg", ".tif", ".tiff")): + skipped["not_a_photo"] += 1 + continue if (entry.get("width") or 0) < 1000 or (entry.get("height") or 0) < 700: skipped["size"] += 1 continue @@ -158,9 +164,13 @@ def main() -> None: print(f" keeping {len(kept)} (skipped: {skipped})") manifest = [] for index, (title, entry) in enumerate(kept): - stem = os.path.basename(urllib.parse.urlparse(entry["url"]).path).replace(" ", "_") - stem = urllib.parse.unquote(stem)[:60] - name = f"{index:03d}_{stem}" + # Truncate the stem, never the extension: a 60-character cut on the + # whole basename drops it, and the file then has no type for cv2 or + # for anyone reading the directory. + stem, extension = os.path.splitext( + os.path.basename(urllib.parse.urlparse(entry["url"]).path).replace(" ", "_") + ) + name = f"{index:03d}_{urllib.parse.unquote(stem)[:60]}{extension.lower()}" path = os.path.join(root, name) if not os.path.exists(path): try: diff --git a/recognization/data/evaluations/2026-09-29-session/catalog-audit/enroll-2026-09-29.json b/recognization/data/evaluations/2026-09-29-session/catalog-audit/enroll-2026-09-29.json new file mode 100644 index 0000000..aec216f --- /dev/null +++ b/recognization/data/evaluations/2026-09-29-session/catalog-audit/enroll-2026-09-29.json @@ -0,0 +1,76 @@ +{ + "source": "data/packshots/source", + "output": "stock-lopia-clean", + "min_width": 120, + "min_height": 160, + "min_views": 1, + "duplicate_cosine": 0.98, + "min_name_ocr": 0.7, + "ocr": "vision", + "text_only_skus": [ + "sku_l04", + "sku_l07", + "sku_l08", + "sku_l12" + ], + "text_discriminated_siblings": [ + { + "sku": "sku_l09", + "view": "sku_l09.jpg", + "sibling_sku": "sku_l10", + "sibling_view": "sku_l10.jpg", + "cosine": 0.9817, + "name_similarity": 0.333 + } + ], + "below_pyramid_floor": [], + "completeness": { + "live_ready": null, + "reason": "no --shelf-tags given; the completeness rule needs the shelf's SKU list", + "enrolled": 8, + "text_only": [ + "sku_l04", + "sku_l07", + "sku_l08", + "sku_l12" + ] + }, + "skus": { + "sku_l01": [ + "sku_l01.jpg" + ], + "sku_l02": [ + "sku_l02.jpg" + ], + "sku_l03": [ + "sku_l03.jpg" + ], + "sku_l05": [ + "sku_l05.jpg" + ], + "sku_l06": [ + "sku_l06.jpg" + ], + "sku_l09": [ + "sku_l09.jpg" + ], + "sku_l10": [ + "sku_l10.jpg" + ], + "sku_l11": [ + "sku_l11.jpg" + ] + }, + "refused": [ + { + "sku": "sku_l04", + "view": "sku_l04.jpg", + "reason": "name/OCR 0.00 below 0.70: 明太手屋さんが つくつ た コ" + }, + { + "sku": "sku_l07", + "view": "sku_l07.jpg", + "reason": "name/OCR 0.57 below 0.70: ラッキー マヨネーズ 調味料(アミノ酸)不使用" + } + ] +} \ No newline at end of file diff --git a/recognization/data/evaluations/2026-09-29-session/catalog-audit/eval-after-l10.json b/recognization/data/evaluations/2026-09-29-session/catalog-audit/eval-after-l10.json new file mode 100644 index 0000000..01bdd94 --- /dev/null +++ b/recognization/data/evaluations/2026-09-29-session/catalog-audit/eval-after-l10.json @@ -0,0 +1,221 @@ +{ + "image": "add/image6.jpg", + "stock_dir": "stock-lopia-clean", + "labels": "eval/labels/image6.json", + "provenance": { + "catalog_hash": "3f1653d9d962073af96121250006b9b6d86113556797bbee65de68b60e87a64d", + "labels_hash": "5aabf029921ced767d4e14a18e8bccb55812dd974852c56e0931a98fa10366cf", + "image_hash": "a08b89ba37d27c9d5a81bcd56bcd042e6baf54d2f182bbaaf47e97f14c9cd525", + "code_revision": "68061635d9fef3097609945bfd9ac1935791b398" + }, + "facings": 111, + "leakage": { + "excluded": 0, + "labels": [] + }, + "hub_share_limit": 0.3, + "enrollment": { + "catalog_skus": [ + "sku_l01", + "sku_l02", + "sku_l03", + "sku_l04", + "sku_l05", + "sku_l06", + "sku_l07", + "sku_l08", + "sku_l09", + "sku_l10", + "sku_l11", + "sku_l12" + ], + "enrolled_skus": [ + "sku_l01", + "sku_l02", + "sku_l03", + "sku_l05", + "sku_l06", + "sku_l09", + "sku_l10", + "sku_l11" + ], + "unenrolled_skus": { + "sku_l07": 6, + "sku_l04": 1, + "sku_l08": 1 + }, + "facings_without_enrollment": 8, + "scored_facings": 109 + }, + "results": { + "full": [ + { + "lane": "local", + "accept": 2.0, + "margin": 0.15, + "in_catalog": 61, + "out_catalog": 48, + "enrolled": 53, + "correct": 48, + "wrong": 9, + "rejected": 52, + "catalog_ceiling": 0.8689, + "identity_ceiling": 0.9245, + "decision_ceiling": 0.8113, + "end_to_end_coverage": 0.7869, + "false_accepts": 9, + "unknown_false_accepts": 8, + "unenrolled_false_accepts": 0, + "false_accept_rate": 0.1667, + "near_unknown_false_accept_rate": 0.0, + "precision": 0.8421, + "max_sku_share": 0.2281, + "hub_sku": "sku_l09", + "hub_alarm": false, + "histogram": { + "sku_l09": 13, + "sku_l11": 10, + "sku_l10": 9, + "sku_l01": 5, + "sku_l03": 5, + "sku_l07": 5, + "sku_l06": 4, + "sku_l02": 3, + "sku_l05": 3 + }, + "per_sku": { + "sku_l01": { + "correct": 5, + "total": 5 + }, + "sku_l02": { + "correct": 2, + "total": 4 + }, + "sku_l03": { + "correct": 4, + "total": 4 + }, + "sku_l04": { + "correct": 0, + "total": 1 + }, + "sku_l05": { + "correct": 3, + "total": 3 + }, + "sku_l06": { + "correct": 4, + "total": 4 + }, + "sku_l07": { + "correct": 5, + "total": 6 + }, + "sku_l08": { + "correct": 0, + "total": 1 + }, + "sku_l09": { + "correct": 11, + "total": 13 + }, + "sku_l10": { + "correct": 9, + "total": 11 + }, + "sku_l11": { + "correct": 5, + "total": 9 + } + }, + "ms_per_crop": 26.7 + } + ], + "live": [ + { + "lane": "local", + "accept": 2.0, + "margin": 0.15, + "in_catalog": 61, + "out_catalog": 48, + "enrolled": 53, + "correct": 41, + "wrong": 4, + "rejected": 64, + "catalog_ceiling": 0.8689, + "identity_ceiling": 0.8491, + "decision_ceiling": 0.6604, + "end_to_end_coverage": 0.6721, + "false_accepts": 4, + "unknown_false_accepts": 3, + "unenrolled_false_accepts": 0, + "false_accept_rate": 0.0625, + "near_unknown_false_accept_rate": 0.0, + "precision": 0.9111, + "max_sku_share": 0.2, + "hub_sku": "sku_l09", + "hub_alarm": false, + "histogram": { + "sku_l09": 9, + "sku_l10": 9, + "sku_l11": 7, + "sku_l07": 6, + "sku_l01": 4, + "sku_l03": 3, + "sku_l05": 3, + "sku_l06": 2, + "sku_l02": 1, + "sku_l04": 1 + }, + "per_sku": { + "sku_l01": { + "correct": 4, + "total": 5 + }, + "sku_l02": { + "correct": 1, + "total": 4 + }, + "sku_l03": { + "correct": 3, + "total": 4 + }, + "sku_l04": { + "correct": 1, + "total": 1 + }, + "sku_l05": { + "correct": 3, + "total": 3 + }, + "sku_l06": { + "correct": 2, + "total": 4 + }, + "sku_l07": { + "correct": 5, + "total": 6 + }, + "sku_l08": { + "correct": 0, + "total": 1 + }, + "sku_l09": { + "correct": 9, + "total": 13 + }, + "sku_l10": { + "correct": 9, + "total": 11 + }, + "sku_l11": { + "correct": 4, + "total": 9 + } + }, + "ms_per_crop": 20.9 + } + ] + } +} \ No newline at end of file diff --git a/recognization/data/evaluations/2026-09-29-session/scratch/fa_detail.py b/recognization/data/evaluations/2026-09-29-session/scratch/fa_detail.py new file mode 100644 index 0000000..d7145fa --- /dev/null +++ b/recognization/data/evaluations/2026-09-29-session/scratch/fa_detail.py @@ -0,0 +1,27 @@ +"""Which facings are falsely accepted, and as what.""" +import sys, cv2 +sys.path.insert(0, "code") +from eval_identity import LocalLaneAdapter, load_labels, at_live_resolution, leaked, UNKNOWN, crop_of +from identity_lanes import DecisionPolicy + +payload = load_labels("eval/labels/image6.json") +image = cv2.imread("add/image6.jpg") +facings = [f for f in payload["facings"] if f["label"] != "exclude"] +facings = [f for f in facings if leaked(image, f["box"], "stock-lopia-clean") is None] +enrolled = {"sku_l01","sku_l02","sku_l03","sku_l05","sku_l06","sku_l09","sku_l10","sku_l11"} + +for live in (False, True): + picture = at_live_resolution(image) if live else image + scaled = facings if not live else [ + {**f, "box": [int(round(v * picture.shape[1] / image.shape[1])) for v in f["box"]]} + for f in facings] + lane = LocalLaneAdapter("stock-lopia-clean") + print(f"=== {'live' if live else 'full'} ===") + for f in scaled: + crop = crop_of(picture, f["box"]) + if crop.size == 0: continue + ranked = lane.rank(crop) + d = lane.decide(crop, ranked, accept=2.0, margin=0.0, scale="local") + ans = d.get("best_sku") if d.get("identity_level") == "accepted" else None + if ans and ans != f["label"]: + print(f" #{f['index']:>3} truth={f['label']:<9} answered={ans:<9} enrolled={f['label'] in enrolled}") diff --git a/recognization/data/evaluations/2026-09-29-session/scratch/fa_text.py b/recognization/data/evaluations/2026-09-29-session/scratch/fa_text.py new file mode 100644 index 0000000..d7e4ad7 --- /dev/null +++ b/recognization/data/evaluations/2026-09-29-session/scratch/fa_text.py @@ -0,0 +1,54 @@ +"""What the falsely-accepted crops actually read, and what the text lane scores. + +The advisory says crops 82-97 are Kewpie Mayonnaise 450g - a product the +catalog does not hold - and that no catalog row can therefore win the text +ranking, so the veto at DecisionPolicy.decide never fires. This prints the +reads and the scores that claim depends on. +""" +import csv +import sys + +import cv2 +import numpy as np + +sys.path.insert(0, "code") +from identity_lanes import TextLane, carries_identity # noqa: E402 +from ocr import build_ocr_engine # noqa: E402 + +INDICES = [73, 82, 83, 84, 86, 94, 95, 96, 97] + +rows = [] +with open("stock-lopia-clean/stock.csv", encoding="utf-8") as handle: + for record in csv.reader(handle): + if len(record) >= 2 and record[0].startswith("sku_"): + rows.append({"sku_id": record[0], "product_name": record[1]}) + +engine = build_ocr_engine("vision") +lane = TextLane.from_catalog(rows, "stock-lopia-clean", ocr_engine=engine) + +labels = {f["index"]: f for f in __import__("json").load(open("eval/labels/image6.json"))["facings"]} +image = cv2.imread("add/image6.jpg") + +tiles = [] +for index in INDICES: + facing = labels[index] + x1, y1, x2, y2 = facing["box"] + crop = image[y1:y2, x1:x2] + read = lane.read(crop) + scores = lane.scores_from_text(read) + top = sorted(scores.items(), key=lambda kv: -kv[1])[:3] + print(f"#{index:>3} truth={facing['label']:<9} carries={carries_identity(read)}") + print(f" read: {read[:110]}") + print(f" text top: {[(s, round(v, 3)) for s, v in top]}") + + height, width = crop.shape[:2] + scale = 260.0 / max(1, height) + resized = cv2.resize(crop, (max(1, int(width * scale)), 260), interpolation=cv2.INTER_CUBIC) + canvas = np.full((300, 220, 3), 255, np.uint8) + canvas[30:290, : min(resized.shape[1], 220)] = resized[:, :220] + cv2.putText(canvas, str(index), (6, 22), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) + tiles.append(canvas) + +grid = np.vstack([np.hstack(tiles[:5]), np.hstack(tiles[5:])]) +cv2.imwrite("data/evaluations/2026-09-29-session/scratch/fa_tiles.jpg", grid) +print("tile:", grid.shape) diff --git a/recognization/data/evaluations/2026-09-29-session/scratch/l10_facing59.jpg b/recognization/data/evaluations/2026-09-29-session/scratch/l10_facing59.jpg new file mode 100644 index 0000000..0806ed2 Binary files /dev/null and b/recognization/data/evaluations/2026-09-29-session/scratch/l10_facing59.jpg differ diff --git a/recognization/data/evaluations/2026-09-29-session/scratch/l10_shelf_tag.jpg b/recognization/data/evaluations/2026-09-29-session/scratch/l10_shelf_tag.jpg new file mode 100644 index 0000000..1ad63c4 Binary files /dev/null and b/recognization/data/evaluations/2026-09-29-session/scratch/l10_shelf_tag.jpg differ diff --git a/recognization/data/evaluations/2026-09-29-session/scratch/l11_shelf_tag.jpg b/recognization/data/evaluations/2026-09-29-session/scratch/l11_shelf_tag.jpg new file mode 100644 index 0000000..2268331 Binary files /dev/null and b/recognization/data/evaluations/2026-09-29-session/scratch/l11_shelf_tag.jpg differ diff --git a/recognization/data/evaluations/2026-09-29-session/scratch/l11_tag_half0.jpg b/recognization/data/evaluations/2026-09-29-session/scratch/l11_tag_half0.jpg new file mode 100644 index 0000000..6801bc9 Binary files /dev/null and b/recognization/data/evaluations/2026-09-29-session/scratch/l11_tag_half0.jpg differ diff --git a/recognization/data/evaluations/2026-09-29-session/scratch/l11_tag_half1.jpg b/recognization/data/evaluations/2026-09-29-session/scratch/l11_tag_half1.jpg new file mode 100644 index 0000000..372a5e0 Binary files /dev/null and b/recognization/data/evaluations/2026-09-29-session/scratch/l11_tag_half1.jpg differ diff --git a/recognization/data/evaluations/2026-09-29-session/scratch/l11_tag_zoom.jpg b/recognization/data/evaluations/2026-09-29-session/scratch/l11_tag_zoom.jpg new file mode 100644 index 0000000..36a2a23 Binary files /dev/null and b/recognization/data/evaluations/2026-09-29-session/scratch/l11_tag_zoom.jpg differ diff --git a/recognization/data/evaluations/2026-09-29-session/scratch/size_gate.py b/recognization/data/evaluations/2026-09-29-session/scratch/size_gate.py new file mode 100644 index 0000000..e5c3e18 --- /dev/null +++ b/recognization/data/evaluations/2026-09-29-session/scratch/size_gate.py @@ -0,0 +1,71 @@ +"""Mass-only size contradiction, with full reads. + +The first pass counted every quantity token, including percentages, so a crop +reading "カロリー 50% カット" looked like a 50 g package. Only mass units can +contradict a package size, so this restricts to g/kg and prints the whole read +for every accepted facing that carries one. +""" +import csv +import json +import re +import sys + +import cv2 + +sys.path.insert(0, "code") +from eval_identity import LocalLaneAdapter, at_live_resolution, crop_of, leaked # noqa: E402 +from identity_lanes import TextLane, normalize_text # noqa: E402 +from ocr import build_ocr_engine # noqa: E402 + +MASS = re.compile(r"(\d+(?:\.\d+)?)\s*(KG|G)", re.IGNORECASE) +# Package sizes this product class actually comes in. Below it are OCR fragments +# of a longer number ("20" from 200); above it are concatenations ("5210"). +PLAUSIBLE = (100.0, 2000.0) + + +def masses(text: str): + return {float(number) for number, _unit in MASS.findall(normalize_text(text))} + + +rows = [] +with open("stock-lopia-clean/stock.csv", encoding="utf-8") as handle: + for record in csv.reader(handle): + if len(record) >= 2 and record[0].startswith("sku_"): + rows.append({"sku_id": record[0], "product_name": record[1]}) +names = {row["sku_id"]: row["product_name"] for row in rows} + +engine = build_ocr_engine("vision") +text_lane = TextLane.from_catalog(rows, "stock-lopia-clean", ocr_engine=engine) +local_lane = LocalLaneAdapter("stock-lopia-clean") + +payload = json.load(open("eval/labels/image6.json")) +image = cv2.imread("add/image6.jpg") +facings = [f for f in payload["facings"] if f["label"] != "exclude"] +facings = [f for f in facings if leaked(image, f["box"], "stock-lopia-clean") is None] + +for live in (False, True): + picture = at_live_resolution(image) if live else image + scaled = facings if not live else [ + {**f, "box": [int(round(v * picture.shape[1] / image.shape[1])) for v in f["box"]]} + for f in facings] + print(f"=== {'live' if live else 'full'} ===") + for facing in scaled: + crop = crop_of(picture, facing["box"]) + if crop.size == 0: + continue + ranked = local_lane.rank(crop) + decision = local_lane.decide(crop, ranked, accept=2.0, margin=0.0, scale="local") + if decision.get("identity_level") != "accepted": + continue + answer = decision.get("best_sku") + read = text_lane.read(crop) + read_masses = masses(read) + name_masses = masses(names.get(answer, "")) + if not read_masses or not name_masses: + continue + plausible = {m for m in read_masses if PLAUSIBLE[0] <= m <= PLAUSIBLE[1]} + veto = bool(plausible) and not (read_masses & name_masses) + correct = "correct" if answer == facing["label"] else "WRONG" + print(f" #{facing['index']:>3} {'VETO' if veto else 'keep'} {correct:<7} " + f"answer={answer:<9} read_m={sorted(read_masses)} name_m={sorted(name_masses)}") + print(f" read: {read[:120]}") diff --git a/recognization/data/evaluations/2026-09-29-session/scratch/unknown_row.jpg b/recognization/data/evaluations/2026-09-29-session/scratch/unknown_row.jpg new file mode 100644 index 0000000..a9fca04 Binary files /dev/null and b/recognization/data/evaluations/2026-09-29-session/scratch/unknown_row.jpg differ diff --git a/recognization/data/external-shelves/wikimedia-commons-2/eval_result.json b/recognization/data/external-shelves/wikimedia-commons-2/eval_result.json index a197b24..e784242 100644 --- a/recognization/data/external-shelves/wikimedia-commons-2/eval_result.json +++ b/recognization/data/external-shelves/wikimedia-commons-2/eval_result.json @@ -2,115 +2,129 @@ "dataset": "wikimedia-commons-2", "catalog": "stock-lopia-clean", "note": "Unrelated shelves: every accept is a false accept by construction.", - "images": 15, - "detections": 421, + "images": 17, + "detections": 462, "false_accepts": 1, - "false_accept_rate": 0.0024, + "false_accept_rate": 0.0022, "rows": [ { "file": "000_1920px-2011年4月の牛乳_(5588310773).jpg", "title": "File:2011年4月の牛乳 (5588310773).jpg", "detections": 78, "false_accepts": 1, - "ms": 2983 + "ms": 3504 }, { "file": "001_Candy_in_Japan_2005_(5256472).jpg", "title": "File:Candy in Japan 2005 (5256472).jpg", "detections": 12, "false_accepts": 0, - "ms": 387 + "ms": 408 }, { - "file": "004_page1-960px-History_of_the_Toledo_Police_Department.djvu.jpg", - "title": "File:History of the Toledo Police Department.djvu", - "detections": 24, + "file": "002_1920px-Empty_shelves_in_Tokyo_area_as_people_get_ready_for_t.jpg", + "title": "File:Empty shelves in Tokyo area as people get ready for typhoon Hagibis - Oct 11 2019 330pm.jpeg", + "detections": 8, "false_accepts": 0, - "ms": 246 + "ms": 101 + }, + { + "file": "003_1920px-HK_SW_上環_Sheung_Wan_德輔道西_88_Des_Voeux_Road_West_shop_.jpg", + "title": "File:HK SW 上環 Sheung Wan 德輔道西 88 Des Voeux Road West shop 惠康超級市場 Wellcome Supermarket goods August 2020 SS2 27.jpg", + "detections": 10, + "false_accepts": 0, + "ms": 1560 + }, + { + "file": "005_1920px-Illuminated_wooden_shelf_with_many_glass_jars_contain.jpg", + "title": "File:Illuminated wooden shelf with many glass jars containing cookies for sale in Tokyo.jpg", + "detections": 41, + "false_accepts": 0, + "ms": 2946 }, { "file": "007_Japan_earthquake_store_shelves.jpg", "title": "File:Japan earthquake store shelves.jpg", "detections": 4, "false_accepts": 0, - "ms": 97 + "ms": 298 }, { "file": "009_Milk_(2655574568).jpg", "title": "File:Milk (2655574568).jpg", "detections": 58, "false_accepts": 0, - "ms": 1379 + "ms": 2802 }, { "file": "010_Natsuge-mikado_okashi.jpg", "title": "File:Natsuge-mikado okashi.jpg", "detections": 7, "false_accepts": 0, - "ms": 259 + "ms": 704 }, { "file": "012_1920px-Supermarket_in_2006_(646332846).jpg", "title": "File:Supermarket in 2006 (646332846).jpg", "detections": 129, "false_accepts": 0, - "ms": 2672 - }, - { - "file": "013_page1-1280px-Tangled_Hair.djvu.jpg", - "title": "File:Tangled Hair.djvu", - "detections": 0, - "false_accepts": 0, - "ms": 20 + "ms": 6707 }, { "file": "014_1920px-「ペヤング」予想通りの大売れ!_(18634213682).jpg", "title": "File:「ペヤング」予想通りの大売れ! (18634213682).jpg", "detections": 27, "false_accepts": 0, - "ms": 324 + "ms": 762 }, { "file": "015_1920px-お客様各位_2008_国内産バター_(2429997079).jpg", "title": "File:お客様各位 2008 国内産バター (2429997079).jpg", "detections": 14, "false_accepts": 0, - "ms": 529 + "ms": 1499 }, { "file": "016_1920px-パン売り場_手動ドア式_2016_(28574754416).jpg", "title": "File:パン売り場 手動ドア式 2016 (28574754416).jpg", "detections": 21, "false_accepts": 0, - "ms": 543 + "ms": 1842 }, { "file": "017_1920px-プラレール_2015_(22339689873).jpg", "title": "File:プラレール 2015 (22339689873).jpg", "detections": 12, "false_accepts": 0, - "ms": 254 + "ms": 864 }, { "file": "018_一家族様一本限り_(5588902836).jpg", "title": "File:一家族様一本限り (5588902836).jpg", "detections": 27, "false_accepts": 0, - "ms": 1385 + "ms": 3880 }, { "file": "019_1920px-洗濯洗剤_(10852819193).jpg", "title": "File:洗濯洗剤 (10852819193).jpg", "detections": 8, "false_accepts": 0, - "ms": 158 + "ms": 704 + }, + { + "file": "020_1920px-申し訳ございませんが_ごめんなさい_お魚本日の調理は終了いたしました。_どうぞよろしくお願いします_(11.jpg", + "title": "File:申し訳ございませんが ごめんなさい お魚本日の調理は終了いたしました。 どうぞよろしくお願いします (11331761984).jpg", + "detections": 6, + "false_accepts": 0, + "ms": 957 }, { "file": "021_1920px-要冷蔵_(4513315790).jpg", "title": "File:要冷蔵 (4513315790).jpg", "detections": 0, "false_accepts": 0, - "ms": 21 + "ms": 190 } ] } \ No newline at end of file diff --git a/recognization/data/external-shelves/wikimedia-commons-2/manifest.json b/recognization/data/external-shelves/wikimedia-commons-2/manifest.json index b4c6be1..52aad7a 100644 --- a/recognization/data/external-shelves/wikimedia-commons-2/manifest.json +++ b/recognization/data/external-shelves/wikimedia-commons-2/manifest.json @@ -22,7 +22,7 @@ "queries": 1 }, { - "file": "002_1920px-Empty_shelves_in_Tokyo_area_as_people_get_ready_for_t", + "file": "002_1920px-Empty_shelves_in_Tokyo_area_as_people_get_ready_for_t.jpg", "title": "File:Empty shelves in Tokyo area as people get ready for typhoon Hagibis - Oct 11 2019 330pm.jpeg", "width": 4027, "height": 3018, @@ -32,7 +32,7 @@ "queries": 1 }, { - "file": "003_1920px-HK_SW_上環_Sheung_Wan_德輔道西_88_Des_Voeux_Road_West_shop_", + "file": "003_1920px-HK_SW_上環_Sheung_Wan_德輔道西_88_Des_Voeux_Road_West_shop_.jpg", "title": "File:HK SW 上環 Sheung Wan 德輔道西 88 Des Voeux Road West shop 惠康超級市場 Wellcome Supermarket goods August 2020 SS2 27.jpg", "width": 4128, "height": 3096, @@ -42,17 +42,7 @@ "queries": 1 }, { - "file": "004_page1-960px-History_of_the_Toledo_Police_Department.djvu.jpg", - "title": "File:History of the Toledo Police Department.djvu", - "width": 1105, - "height": 1500, - "license": "Public domain", - "artist": "
\nToledo (Ohio). Division of Police
", - "source": "https://commons.wikimedia.org/wiki/File%3AHistory_of_the_Toledo_Police_Department.djvu", - "queries": 1 - }, - { - "file": "005_1920px-Illuminated_wooden_shelf_with_many_glass_jars_contain", + "file": "005_1920px-Illuminated_wooden_shelf_with_many_glass_jars_contain.jpg", "title": "File:Illuminated wooden shelf with many glass jars containing cookies for sale in Tokyo.jpg", "width": 4037, "height": 6055, @@ -62,7 +52,7 @@ "queries": 1 }, { - "file": "006_1920px-Interior_of_JUSCO_Shingu_Shopping_Center_20100213c.JP", + "file": "006_1920px-Interior_of_JUSCO_Shingu_Shopping_Center_20100213c.jpg", "title": "File:Interior of JUSCO Shingu Shopping Center 20100213c.JPG", "width": 3648, "height": 2736, @@ -81,16 +71,6 @@ "source": "https://commons.wikimedia.org/wiki/File%3AJapan_earthquake_store_shelves.jpg", "queries": 1 }, - { - "file": "008_page1-960px-Judge_v067_n1726_(1914-11-14.Leslie-Judge)_(Darw", - "title": "File:Judge v067 n1726 (1914-11-14.Leslie-Judge) (Darwin-IA).djvu", - "width": 1192, - "height": 1500, - "license": "Public domain", - "artist": "", - "source": "https://commons.wikimedia.org/wiki/File%3AJudge_v067_n1726_%281914-11-14.Leslie-Judge%29_%28Darwin-IA%29.djvu", - "queries": 1 - }, { "file": "009_Milk_(2655574568).jpg", "title": "File:Milk (2655574568).jpg", @@ -111,16 +91,6 @@ "source": "https://commons.wikimedia.org/wiki/File%3ANatsuge-mikado_okashi.jpg", "queries": 1 }, - { - "file": "011_page1-1920px-Overland_through_Asia._by_Knox,_Thomas_Wallace.", - "title": "File:Overland through Asia. by Knox, Thomas Wallace.djvu", - "width": 2596, - "height": 4212, - "license": "Public domain", - "artist": "Thomas W. Knox", - "source": "https://commons.wikimedia.org/wiki/File%3AOverland_through_Asia._by_Knox%2C_Thomas_Wallace.djvu", - "queries": 1 - }, { "file": "012_1920px-Supermarket_in_2006_(646332846).jpg", "title": "File:Supermarket in 2006 (646332846).jpg", @@ -131,16 +101,6 @@ "source": "https://commons.wikimedia.org/wiki/File%3ASupermarket_in_2006_%28646332846%29.jpg", "queries": 1 }, - { - "file": "013_page1-1280px-Tangled_Hair.djvu.jpg", - "title": "File:Tangled Hair.djvu", - "width": 1371, - "height": 2129, - "license": "Public domain", - "artist": "Akiko Yosano", - "source": "https://commons.wikimedia.org/wiki/File%3ATangled_Hair.djvu", - "queries": 1 - }, { "file": "014_1920px-「ペヤング」予想通りの大売れ!_(18634213682).jpg", "title": "File:「ペヤング」予想通りの大売れ! (18634213682).jpg", @@ -202,7 +162,7 @@ "queries": 1 }, { - "file": "020_1920px-申し訳ございませんが_ごめんなさい_お魚本日の調理は終了いたしました。_どうぞよろしくお願いします_(11", + "file": "020_1920px-申し訳ございませんが_ごめんなさい_お魚本日の調理は終了いたしました。_どうぞよろしくお願いします_(11.jpg", "title": "File:申し訳ございませんが ごめんなさい お魚本日の調理は終了いたしました。 どうぞよろしくお願いします (11331761984).jpg", "width": 4000, "height": 2672, diff --git a/recognization/data/external-shelves/wikimedia-commons/eval_result.json b/recognization/data/external-shelves/wikimedia-commons/eval_result.json index c0f0fe1..b21976e 100644 --- a/recognization/data/external-shelves/wikimedia-commons/eval_result.json +++ b/recognization/data/external-shelves/wikimedia-commons/eval_result.json @@ -2,297 +2,325 @@ "dataset": "wikimedia-commons", "catalog": "stock-lopia-clean", "note": "Unrelated shelves: every accept is a false accept by construction.", - "images": 41, - "detections": 1876, + "images": 45, + "detections": 2133, "false_accepts": 7, - "false_accept_rate": 0.0037, + "false_accept_rate": 0.0033, "rows": [ { "file": "000_1920px-198円_中華弁当_2016_(25800617695).jpg", "title": "File:198円 中華弁当 2016 (25800617695).jpg", "detections": 2, "false_accepts": 0, - "ms": 813 + "ms": 1774 }, { "file": "001_1920px-2011年4月の牛乳_(5588310773).jpg", "title": "File:2011年4月の牛乳 (5588310773).jpg", "detections": 78, "false_accepts": 1, - "ms": 2983 + "ms": 4553 }, { "file": "002_1920px-20140909-0252_Costa_Mesa_Mitsuwa.JPG", "title": "File:20140909-0252 Costa Mesa Mitsuwa.JPG", "detections": 95, "false_accepts": 0, - "ms": 2204 + "ms": 3025 }, { "file": "003_1920px-Aomori_Home_(4721758999).jpg", "title": "File:Aomori Home (4721758999).jpg", "detections": 76, "false_accepts": 0, - "ms": 2995 + "ms": 3634 + }, + { + "file": "004_1920px-Asakusa_15_-_making_rice_crackers_the_old_way_(155797.jpg", + "title": "File:Asakusa 15 - making rice crackers the old way (15579727827).jpg", + "detections": 14, + "false_accepts": 0, + "ms": 162 + }, + { + "file": "005_1920px-Asakusa_16_-_making_rice_crackers_the_old_way_(155794.jpg", + "title": "File:Asakusa 16 - making rice crackers the old way (15579472088).jpg", + "detections": 3, + "false_accepts": 0, + "ms": 131 + }, + { + "file": "006_1920px-Asakusa_17_-_making_rice_crackers_the_old_way_(155794.jpg", + "title": "File:Asakusa 17 - making rice crackers the old way (15579471588).jpg", + "detections": 4, + "false_accepts": 0, + "ms": 132 + }, + { + "file": "007_1920px-Asakusa_19_-_the_woman_selling_the_rice_crackers_(157.jpg", + "title": "File:Asakusa 19 - the woman selling the rice crackers (15764889785).jpg", + "detections": 3, + "false_accepts": 0, + "ms": 67 }, { "file": "008_1920px-Azabudai-Hills---2025-04-05_015.jpg", "title": "File:Azabudai-Hills---2025-04-05 015.jpg", "detections": 37, "false_accepts": 2, - "ms": 2272 + "ms": 2113 }, { "file": "010_1920px-Breathalyzers_in_a_MaxValu_supermarket.jpg", "title": "File:Breathalyzers in a MaxValu supermarket.jpg", "detections": 5, "false_accepts": 0, - "ms": 306 + "ms": 368 }, { "file": "011_1920px-Chocolate_in_Japan_(5137097169).jpg", "title": "File:Chocolate in Japan (5137097169).jpg", "detections": 65, "false_accepts": 1, - "ms": 2295 + "ms": 3829 + }, + { + "file": "013_1920px-Confectionery_at_WCTC_Shopping_Center,_Koror_City,_Pa.jpg", + "title": "File:Confectionery at WCTC Shopping Center, Koror City, Palau.jpg", + "detections": 96, + "false_accepts": 0, + "ms": 6114 }, { "file": "014_1920px-Deer_cookies_at_Nara,_Japan.jpg", "title": "File:Deer cookies at Nara, Japan.jpg", "detections": 10, "false_accepts": 0, - "ms": 374 + "ms": 733 }, { "file": "015_1920px-ESL_Price_Tag.JPG", "title": "File:ESL Price Tag.JPG", "detections": 32, "false_accepts": 0, - "ms": 1022 + "ms": 1506 }, { "file": "017_1920px-Food-with-physiological-energy-value-example.jpg", "title": "File:Food-with-physiological-energy-value-example.jpg", "detections": 10, "false_accepts": 0, - "ms": 468 + "ms": 454 + }, + { + "file": "019_1920px-HK_CWB_Wellcome_Shop_Supermarket_goods_Carbonated_sof.jpg", + "title": "File:HK CWB Wellcome Shop Supermarket goods Carbonated soft drink codd-neck bottles 波子汽水 Apple Ramune Japanese products July 2017 IX1.jpg", + "detections": 18, + "false_accepts": 0, + "ms": 712 }, { "file": "021_1920px-Interior_of_Supermarket_in_Japan_02.jpg", "title": "File:Interior of Supermarket in Japan 02.jpg", "detections": 5, "false_accepts": 0, - "ms": 234 + "ms": 286 + }, + { + "file": "022_1920px-JP_日本_Japan_沖繩_OKINAWA_浦添市_Urasoe-city_AEON_Supermark.jpg", + "title": "File:JP 日本 Japan 沖繩 OKINAWA 浦添市 Urasoe-city AEON Supermarket food drinks February 2026 N13p 02.jpg", + "detections": 119, + "false_accepts": 0, + "ms": 4603 }, { "file": "023_1920px-thumbnail.jpg", "title": "File:JP 日本 Japan 沖繩 OKINAWA 那霸 Naha Omoromachi Shintoshin 新都心 Naha Main Place 商場 Shopping Mall shop Aeon Supermarket drink 益力多 January 2025 R12S 01.jpg", "detections": 117, "false_accepts": 0, - "ms": 2817 + "ms": 2581 }, { "file": "024_1920px-JaSupermarket_Instant_noodles.JPG", "title": "File:JaSupermarket Instant noodles.JPG", "detections": 97, "false_accepts": 0, - "ms": 2613 + "ms": 2750 }, { "file": "026_1920px-Kawasaki-Inryo-1.jpg", "title": "File:Kawasaki-Inryo-1.jpg", "detections": 12, "false_accepts": 0, - "ms": 701 - }, - { - "file": "027_page1-1920px-Mary_Barton_-_1848_-_Volume_1.djvu.jpg", - "title": "File:Mary Barton - 1848 - Volume 1.djvu", - "detections": 0, - "false_accepts": 0, - "ms": 19 + "ms": 892 }, { "file": "029_1920px-Miyazu_Mipple_1F_2021-04_ac.jpg", "title": "File:Miyazu Mipple 1F 2021-04 ac.jpg", "detections": 73, "false_accepts": 0, - "ms": 700 + "ms": 852 }, { "file": "030_1920px-Octopus_rice_crackers_No,1.JPG", "title": "File:Octopus rice crackers No,1.JPG", "detections": 5, "false_accepts": 0, - "ms": 237 + "ms": 247 }, { "file": "031_1920px-Octopus_senbei.JPG", "title": "File:Octopus senbei.JPG", "detections": 4, "false_accepts": 0, - "ms": 136 + "ms": 140 }, { "file": "032_1920px-Okaki_for_sale_in_Kawagoe.jpg", "title": "File:Okaki for sale in Kawagoe.jpg", "detections": 27, "false_accepts": 0, - "ms": 255 + "ms": 267 }, { "file": "033_Okonomiyaki_and_takoyaki_ingredients.jpg", "title": "File:Okonomiyaki and takoyaki ingredients.jpg", "detections": 39, "false_accepts": 0, - "ms": 1216 + "ms": 1228 }, { "file": "035_1920px-SW_4963.jpg", "title": "File:SW 4963.jpg", "detections": 5, "false_accepts": 0, - "ms": 238 + "ms": 200 }, { "file": "037_1920px-Soy_Sauce_selection_(6362318717).jpg", "title": "File:Soy Sauce selection (6362318717).jpg", "detections": 68, "false_accepts": 0, - "ms": 1631 + "ms": 1671 }, { "file": "038_1920px-Soy_sauce_(5846027636).jpg", "title": "File:Soy sauce (5846027636).jpg", "detections": 103, "false_accepts": 1, - "ms": 1603 + "ms": 1626 }, { "file": "039_1920px-Soy_sauce_in_supermarket.JPG", "title": "File:Soy sauce in supermarket.JPG", "detections": 71, "false_accepts": 0, - "ms": 2729 + "ms": 2380 }, { "file": "040_1920px-Spice_Supermarket_Japan.JPG", "title": "File:Spice Supermarket Japan.JPG", "detections": 254, "false_accepts": 0, - "ms": 2453 + "ms": 2544 }, { "file": "041_1920px-Strong_Zero_4962.jpg", "title": "File:Strong Zero 4962.jpg", "detections": 18, "false_accepts": 0, - "ms": 838 + "ms": 856 }, { "file": "042_1920px-Supermarket_Digital_Displays_(2927051130).jpg", "title": "File:Supermarket Digital Displays (2927051130).jpg", "detections": 89, "false_accepts": 1, - "ms": 3543 + "ms": 3561 }, { "file": "043_1920px-Tasty_Food_Abundance_in_Healthy_Europe.png", "title": "File:Tasty Food Abundance in Healthy Europe.png", "detections": 13, "false_accepts": 0, - "ms": 605 - }, - { - "file": "046_page1-1920px-Things_Japanese_(1905).djvu.jpg", - "title": "File:Things Japanese (1905).djvu", - "detections": 0, - "false_accepts": 0, - "ms": 20 + "ms": 1202 }, { "file": "047_1920px-Tokyo---Ebisu-and-Shibuya---2026-02-04_162.jpg", "title": "File:Tokyo---Ebisu-and-Shibuya---2026-02-04 162.jpg", "detections": 74, "false_accepts": 0, - "ms": 2095 + "ms": 4770 }, { "file": "048_1920px-Tokyo---Ebisu-and-Shibuya---2026-02-04_167.jpg", "title": "File:Tokyo---Ebisu-and-Shibuya---2026-02-04 167.jpg", "detections": 46, "false_accepts": 0, - "ms": 1424 - }, - { - "file": "049_page1-1280px-Tono-Bungay.djvu.jpg", - "title": "File:Tono-Bungay.djvu", - "detections": 0, - "false_accepts": 0, - "ms": 19 + "ms": 2557 }, { "file": "050_1920px-Umami_Snack_(41957534).jpeg", "title": "File:Umami Snack (41957534).jpeg", "detections": 33, "false_accepts": 0, - "ms": 1687 + "ms": 3096 }, { "file": "051_1920px-このかねをならすのはだーれ_(3079692697).jpg", "title": "File:このかねをならすのはだーれ (3079692697).jpg", "detections": 0, "false_accepts": 0, - "ms": 20 + "ms": 125 }, { "file": "052_1920px-スーパーの野菜コーナー_2008_(2785121488).jpg", "title": "File:スーパーの野菜コーナー 2008 (2785121488).jpg", "detections": 25, "false_accepts": 0, - "ms": 792 + "ms": 1681 }, { "file": "055_1920px-中央フード山手店_-_panoramio.jpg", "title": "File:中央フード山手店 - panoramio.jpg", "detections": 15, "false_accepts": 0, - "ms": 183 + "ms": 263 }, { "file": "056_1920px-何このリポD人気⁈買い占めてしまおう。_(4025507198).jpg", "title": "File:何このリポD人気⁈買い占めてしまおう。 (4025507198).jpg", "detections": 38, "false_accepts": 0, - "ms": 1700 + "ms": 2912 }, { "file": "057_1920px-味噌売り場_(16183474871).jpg", "title": "File:味噌売り場 (16183474871).jpg", "detections": 61, "false_accepts": 0, - "ms": 2085 + "ms": 3355 }, { "file": "058_1920px-塩ひかえめ_(25347152904).jpg", "title": "File:塩ひかえめ (25347152904).jpg", "detections": 66, "false_accepts": 0, - "ms": 2014 + "ms": 3043 }, { "file": "060_1920px-牛乳_豆乳_2016_(32081175436).jpg", "title": "File:牛乳 豆乳 2016 (32081175436).jpg", "detections": 103, "false_accepts": 1, - "ms": 3198 + "ms": 3677 }, { "file": "061_1920px-表示価格より100円引_(38057600585).jpg", "title": "File:表示価格より100円引 (38057600585).jpg", "detections": 5, "false_accepts": 0, - "ms": 580 + "ms": 632 } ] } \ No newline at end of file diff --git a/recognization/data/external-shelves/wikimedia-commons/manifest.json b/recognization/data/external-shelves/wikimedia-commons/manifest.json index 429124b..aaf1b1c 100644 --- a/recognization/data/external-shelves/wikimedia-commons/manifest.json +++ b/recognization/data/external-shelves/wikimedia-commons/manifest.json @@ -42,7 +42,7 @@ "queries": 2 }, { - "file": "004_1920px-Asakusa_15_-_making_rice_crackers_the_old_way_(155797", + "file": "004_1920px-Asakusa_15_-_making_rice_crackers_the_old_way_(155797.jpg", "title": "File:Asakusa 15 - making rice crackers the old way (15579727827).jpg", "width": 4288, "height": 2848, @@ -52,7 +52,7 @@ "queries": 1 }, { - "file": "005_1920px-Asakusa_16_-_making_rice_crackers_the_old_way_(155794", + "file": "005_1920px-Asakusa_16_-_making_rice_crackers_the_old_way_(155794.jpg", "title": "File:Asakusa 16 - making rice crackers the old way (15579472088).jpg", "width": 4288, "height": 2848, @@ -62,7 +62,7 @@ "queries": 1 }, { - "file": "006_1920px-Asakusa_17_-_making_rice_crackers_the_old_way_(155794", + "file": "006_1920px-Asakusa_17_-_making_rice_crackers_the_old_way_(155794.jpg", "title": "File:Asakusa 17 - making rice crackers the old way (15579471588).jpg", "width": 4288, "height": 2848, @@ -72,7 +72,7 @@ "queries": 1 }, { - "file": "007_1920px-Asakusa_19_-_the_woman_selling_the_rice_crackers_(157", + "file": "007_1920px-Asakusa_19_-_the_woman_selling_the_rice_crackers_(157.jpg", "title": "File:Asakusa 19 - the woman selling the rice crackers (15764889785).jpg", "width": 4288, "height": 2848, @@ -112,7 +112,7 @@ "queries": 2 }, { - "file": "013_1920px-Confectionery_at_WCTC_Shopping_Center,_Koror_City,_Pa", + "file": "013_1920px-Confectionery_at_WCTC_Shopping_Center,_Koror_City,_Pa.jpg", "title": "File:Confectionery at WCTC Shopping Center, Koror City, Palau.jpg", "width": 2305, "height": 1731, @@ -141,16 +141,6 @@ "source": "https://commons.wikimedia.org/wiki/File%3AESL_Price_Tag.JPG", "queries": 1 }, - { - "file": "016_page1-1280px-Eliza_Scidmore--Jinrikisha_days_in_Japan.djvu.j", - "title": "File:Eliza Scidmore--Jinrikisha days in Japan.djvu", - "width": 1719, - "height": 2599, - "license": "Public domain", - "artist": "Eliza Ruhamah Scidmore", - "source": "https://commons.wikimedia.org/wiki/File%3AEliza_Scidmore--Jinrikisha_days_in_Japan.djvu", - "queries": 1 - }, { "file": "017_1920px-Food-with-physiological-energy-value-example.jpg", "title": "File:Food-with-physiological-energy-value-example.jpg", @@ -162,17 +152,7 @@ "queries": 1 }, { - "file": "018_page1-1920px-Gissing_-_Isabel_Clarendon,_vol._I,_1886.djvu.j", - "title": "File:Gissing - Isabel Clarendon, vol. I, 1886.djvu", - "width": 2227, - "height": 3518, - "license": "Public domain", - "artist": "George Gissing", - "source": "https://commons.wikimedia.org/wiki/File%3AGissing_-_Isabel_Clarendon%2C_vol._I%2C_1886.djvu", - "queries": 1 - }, - { - "file": "019_1920px-HK_CWB_Wellcome_Shop_Supermarket_goods_Carbonated_sof", + "file": "019_1920px-HK_CWB_Wellcome_Shop_Supermarket_goods_Carbonated_sof.jpg", "title": "File:HK CWB Wellcome Shop Supermarket goods Carbonated soft drink codd-neck bottles 波子汽水 Apple Ramune Japanese products July 2017 IX1.jpg", "width": 2048, "height": 1368, @@ -181,16 +161,6 @@ "source": "https://commons.wikimedia.org/wiki/File%3AHK_CWB_Wellcome_Shop_Supermarket_goods_Carbonated_soft_drink_codd-neck_bottles_%E6%B3%A2%E5%AD%90%E6%B1%BD%E6%B0%B4_Apple_Ramune_Japanese_products_July_2017_IX1.jpg", "queries": 2 }, - { - "file": "020_page1-960px-Henry_Theophilus_Finck_-_Lotos-time_in_Japan_(18", - "title": "File:Henry Theophilus Finck - Lotos-time in Japan (1895).djvu", - "width": 1000, - "height": 1500, - "license": "Public domain", - "artist": "
\nHenry Theophilus Finck
", - "source": "https://commons.wikimedia.org/wiki/File%3AHenry_Theophilus_Finck_-_Lotos-time_in_Japan_%281895%29.djvu", - "queries": 2 - }, { "file": "021_1920px-Interior_of_Supermarket_in_Japan_02.jpg", "title": "File:Interior of Supermarket in Japan 02.jpg", @@ -202,7 +172,7 @@ "queries": 1 }, { - "file": "022_1920px-JP_日本_Japan_沖繩_OKINAWA_浦添市_Urasoe-city_AEON_Supermark", + "file": "022_1920px-JP_日本_Japan_沖繩_OKINAWA_浦添市_Urasoe-city_AEON_Supermark.jpg", "title": "File:JP 日本 Japan 沖繩 OKINAWA 浦添市 Urasoe-city AEON Supermarket food drinks February 2026 N13p 02.jpg", "width": 3060, "height": 4080, @@ -241,16 +211,6 @@ "source": "https://commons.wikimedia.org/wiki/File%3AKawasaki-Inryo-1.jpg", "queries": 2 }, - { - "file": "027_page1-1920px-Mary_Barton_-_1848_-_Volume_1.djvu.jpg", - "title": "File:Mary Barton - 1848 - Volume 1.djvu", - "width": 2148, - "height": 3615, - "license": "Public domain", - "artist": "
\nElizabeth Cleghorn Gaskell
", - "source": "https://commons.wikimedia.org/wiki/File%3AMary_Barton_-_1848_-_Volume_1.djvu", - "queries": 1 - }, { "file": "029_1920px-Miyazu_Mipple_1F_2021-04_ac.jpg", "title": "File:Miyazu Mipple 1F 2021-04 ac.jpg", @@ -302,7 +262,7 @@ "queries": 1 }, { - "file": "034_1920px-Rice_toppings_&_additional_ingredients_(5846028686).j", + "file": "034_1920px-Rice_toppings_&_additional_ingredients_(5846028686).jpg", "title": "File:Rice toppings & additional ingredients (5846028686).jpg", "width": 3072, "height": 2304, @@ -391,36 +351,6 @@ "source": "https://commons.wikimedia.org/wiki/File%3ATasty_Food_Abundance_in_Healthy_Europe.png", "queries": 1 }, - { - "file": "044_page1-1920px-The_Philippine_Islands,_1493-1803_(Volume_27).d", - "title": "File:The Philippine Islands, 1493-1803 (Volume 27).djvu", - "width": 2181, - "height": 3622, - "license": "Public domain", - "artist": "
\nd. 1911 Emma Helen Blair
", - "source": "https://commons.wikimedia.org/wiki/File%3AThe_Philippine_Islands%2C_1493-1803_%28Volume_27%29.djvu", - "queries": 1 - }, - { - "file": "045_page1-1920px-The_Philippine_Islands,_1493-1803_(Volume_38).d", - "title": "File:The Philippine Islands, 1493-1803 (Volume 38).djvu", - "width": 2261, - "height": 3587, - "license": "Public domain", - "artist": "
\nd. 1911 Emma Helen Blair
", - "source": "https://commons.wikimedia.org/wiki/File%3AThe_Philippine_Islands%2C_1493-1803_%28Volume_38%29.djvu", - "queries": 1 - }, - { - "file": "046_page1-1920px-Things_Japanese_(1905).djvu.jpg", - "title": "File:Things Japanese (1905).djvu", - "width": 2332, - "height": 3684, - "license": "Public domain", - "artist": "Basil Hall Chamberlain (1850-1935)", - "source": "https://commons.wikimedia.org/wiki/File%3AThings_Japanese_%281905%29.djvu", - "queries": 1 - }, { "file": "047_1920px-Tokyo---Ebisu-and-Shibuya---2026-02-04_162.jpg", "title": "File:Tokyo---Ebisu-and-Shibuya---2026-02-04 162.jpg", @@ -441,16 +371,6 @@ "source": "https://commons.wikimedia.org/wiki/File%3ATokyo---Ebisu-and-Shibuya---2026-02-04_167.jpg", "queries": 1 }, - { - "file": "049_page1-1280px-Tono-Bungay.djvu.jpg", - "title": "File:Tono-Bungay.djvu", - "width": 1757, - "height": 2916, - "license": "Public domain", - "artist": "
\nWells, H. G. (Herbert George), 1866-1946
", - "source": "https://commons.wikimedia.org/wiki/File%3ATono-Bungay.djvu", - "queries": 1 - }, { "file": "050_1920px-Umami_Snack_(41957534).jpeg", "title": "File:Umami Snack (41957534).jpeg", 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 6a10cff..8c4551b 100644 --- a/recognization/docs/research/2026-09-28-recognition-architecture/DECISION.md +++ b/recognization/docs/research/2026-09-28-recognition-architecture/DECISION.md @@ -57,11 +57,12 @@ store-scoped, enrolled catalog, with live-video evidence accumulation**. becomes retrieval plus verification (§6). - **Open set is the dominant difficulty, and it comes in two kinds.** *Far* unknowns (other categories) are rejected easily **once the accept lines are - calibrated against them**: 0.37 % and 0.24 % false accepts on 2297 crops from - 56 unrelated Wikimedia supermarket photos, at a threshold that keeps 42 of 48 - correct image6 labels. The audit's 0.2-0.7 % was measured on 602 crops from - the `add/` photos with the audit's own variant matcher; the shipped lane at - the shipped lines was 3.61 % until 2026-09-29 (§ Re-measured, far unknowns). + calibrated against them**: 3.09 % at the old lines, 0.30 % at the shipped + ones, on 2650 crops from 60 unrelated Wikimedia supermarket photos, at a + threshold that keeps 42 of 48 correct image6 labels. The audit's 0.2-0.7 % + was measured on 602 crops from the `add/` photos with the audit's own variant + matcher; the shipped lane at the shipped lines was 3.09 % until 2026-09-29 + (§ Re-measured, far unknowns). *Near* unknowns (siblings of enrolled products: Kewpie 450 g next to Kewpie からし, Pure Select plain next to Pure Select コクうま) produce genuine, @@ -396,7 +397,7 @@ with always-argmax, run on that same catalog. Status 2026-09-29, offline on image6 plus the Wikimedia distractor sets: **G2 passes** (95 % precision, full resolution). **G3's far-unknown half -passes** (0.37 % / 0.24 % on 2297 unrelated crops); its near-unknown half is +passes** (0.30 % on 2650 unrelated crops); its near-unknown half is measured on image6 only, where the size gate rejects the documented 450 g case. **G8 passes** (identity p95 well inside 60 ms). **G1, G4, G5, G6, G7 are not yet measured on held-out data** - Tier 2 does not exist, and G4/G5 need a @@ -656,13 +657,16 @@ facings sit at p25 2.07 (full) and 2.87 (live), wrong ones at p75 1.00 and 1.66, so 2.0 is the boundary in both. Sweeping it at full resolution, through the evaluator (`--accept`, columns as it defines them: end-to-end is accepted-and-correct over the 64 in-catalog facings, precision is over the -facings it answered): +facings it answered). Re-measured 2026-09-29 after the accept lines were +calibrated against unrelated shelves (§ Far unknowns); the 2.0 row is what the +audit measured, the 4.0 row is the shipped line: accept end-to-end precision false accepts - 2.0 75% 91% 5 - 3.0 67% 91% 4 - 4.0 67% 93% 3 - 6.0 62% 95% 2 + 2.0 75% 92% 4 + 3.0 66% 93% 3 + 4.0 66% 95% 2 + 5.0 62% 98% 1 + 6.0 59% 97% 1 The line is still provisional - it is tuned on Tier 1 and needs Tier-2 calibration - but it does not need to differ by input path, and the design @@ -853,12 +857,9 @@ precision 86% -> 91%, false accepts 8 -> 5, coverage unchanged at 79%. ### Far unknowns: the accept lines were tuned on a shelf that has no unknowns - -Every threshold in this document was fitted on image6, where each crop is a -facing of a product the shelf actually holds. That is a closed-set tuning set, -and it hid the far-unknown rate completely: the shipped lane accepted 83 of -2297 crops from 56 Wikimedia Commons supermarket photos of milk, soy and snack -shelves - 3.61 %, against G3's 1 %. +and it hid the far-unknown rate completely: the shipped lane accepted 82 of +2650 crops from 60 Wikimedia Commons supermarket photos of milk, soy and snack +shelves - 3.09 %, against G3's 1 %. Those photos share nothing with the LOPIA catalog, so every accept is a false accept by construction. Two mechanisms produced them: @@ -867,24 +868,24 @@ accept by construction. Two mechanisms produced them: drops bigrams no catalog name contains, so a short garbage read can end up with a perfect ratio on two pairs. 20 of 26 text-lane answers rested on exactly two: `避くて おいしい` named `sku_l12` through おい/いし. -- **The local lane accepted pure geometry.** The residual 25 were matches with - no text overlap at all, scoring 2.26-4.81 against an accept line of 2.0. +- **The local lane accepted pure geometry.** The residual accepts were matches + with no text overlap at all, scoring 2.26-4.81 against an accept line of 2.0. Both lines moved: `TEXT_MIN_SHARED` 2 -> 4, `LOCAL_ACCEPT` 2.0 -> 4.0. Measured -on 2297 distractor crops and 109 image6 facings: +on 2650 distractor crops and 109 image6 facings: | `LOCAL_ACCEPT` | `TEXT_MIN_SHARED` | image6 shown / correct | precision | false accepts | |---|---|---|---|---| -| 2.0 | 2 | 54 / 49 | 90.7 % | 83 (3.61 %) | -| 2.0 | 4 | 52 / 48 | 92.3 % | 30 (1.31 %) | -| **4.0** | **4** | **44 / 42** | **95.5 %** | **8 (0.35 %)** | -| 5.0 | 6 | 36 / 36 | 100.0 % | 0 (0.00 %) | +| 2.0 | 2 | 46 / 43 | 93.5 % | 82 (3.09 %) | +| 2.0 | 4 | 44 / 42 | 95.5 % | 8 (0.30 %) | +| **4.0** | **4** | **44 / 42** | **95.5 %** | **8 (0.30 %)** | +| 5.0 | 6 | 39 / 38 | 97.4 % | 3 (0.11 %) | 4.0/4 is the only region passing both G2 (>= 95 % precision) and G3 (<= 1 % far-unknown) with coverage left. On the shipped evaluator that is 66 % -end-to-end at 95 % precision with 2 false accepts, against 77 % / 91 % / 5 -before - the coverage is what the precision costs, and G2 is the gate that says -to pay it. +end-to-end at 95 % precision with 2 false accepts, against 75 % / 92 % / 4 at +the old 2.0 line - the coverage is what the precision costs, and G2 is the gate +that says to pay it. Reproduce: `.venv/bin/python code/eval_distractors.py --stock stock-lopia-clean --write data/external-shelves/wikimedia-commons data/external-shelves/wikimedia-commons-2`.