fix(recognition): calibrate the accept lines against unrelated shelves

Every threshold was fitted on image6, where each crop is a facing of a product
the shelf holds, so the set could not price a false accept. Measured on 4580
crops from 64 unrelated Wikimedia shelf photos at the shipped configuration:

  LOCAL_ACCEPT 2.0 -> 4.0   false accepts 60 (1.31%) -> 3 (0.07%)
  TEXT_MIN_SHARED 2 -> 4    the two-bigram reads that named sku_l12 via おい/いし

On image6 that is 44 shown / 42 correct at full resolution - 95.5% precision,
65.6% coverage - the highest-coverage cell of the joint sweep that passes both
G2 (>= 95%) and G3 (<= 1%). At live resolution 56% end-to-end at 97%.

The text lane's evidence floor gates its answer only: zeroing the row's score
would reorder the ranking and make the margin gate compare a different pair
than the one it was measured on.

code/sweep_accept_lines.py sweeps both axes jointly through the shipped
DecisionPolicy; the earlier table swept one axis while pinning the other, so
its baseline rows were not the old line.
This commit is contained in:
kiyo9w 2026-09-29 09:28:13 +09:00
parent 4ce41ecb17
commit 5094b5f6ca
12 changed files with 815 additions and 195 deletions

View file

@ -18,6 +18,7 @@ import cv2 # noqa: E402
import numpy as np # noqa: E402
from eval_live import ( # noqa: E402
IDENTITY_BACKENDS,
EvalInputError,
identity_level,
labelled_top1,
@ -296,5 +297,42 @@ class IdentityContractTests(unittest.TestCase):
{"identity_backend": "matcher"},
])
def test_van_is_accepted_by_the_cli_and_by_a_recording_that_names_it(self):
self.assertIn("van", IDENTITY_BACKENDS)
self.assertEqual(resolve_identity("van", None), "van")
self.assertEqual(recorded_identity([{"identity_backend": "van"}]), "van")
root = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, root, ignore_errors=True)
stock = os.path.join(root, "stock")
os.makedirs(stock)
recording = os.path.join(root, "session")
os.makedirs(recording)
write_jpeg(os.path.join(recording, "000000.jpg"), np.zeros((8, 8, 3), dtype=np.uint8))
line = {"frame": 1, "path": "000000.jpg", "tracks": [], "identity_backend": "van"}
with open(os.path.join(recording, "index.jsonl"), "w", encoding="utf-8") as handle:
handle.write(json.dumps(line) + "\n")
for extra in ([], ["--identity", "van"]):
report_path = os.path.join(root, "eval_live.json")
completed = subprocess.run(
[
sys.executable,
os.path.join(current_dir, "eval_live.py"),
recording,
"--stock-dir",
stock,
"--json",
report_path,
*extra,
],
capture_output=True,
text=True,
check=False,
)
self.assertEqual(completed.returncode, 0, completed.stdout + completed.stderr)
with open(report_path, "r", encoding="utf-8") as handle:
report = json.load(handle)
self.assertEqual(report["identity"]["backend"], "van")
self.assertEqual(report["fingerprints"]["model"]["identity"], "van")
if __name__ == "__main__":
unittest.main()