The header said 'Audited 2026-09-28' while the document now carries 2026-09-29 implementation results; it says both, and that audit-time figures are kept beside the later ones rather than replaced. The OCR cost row claimed 18.0 ms on 40 production crops with no committed script behind it. code/bench_ocr.py is that measurement: 23.3 ms p50, 37.2 ms p95, mean 23.1 - inside the recorded 18-26 ms band, at its upper half.
42 lines
1.3 KiB
Python
42 lines
1.3 KiB
Python
"""OCR cost per crop, on production-shaped crops.
|
|
|
|
The decision record claims ~18-26 ms per crop on Mac and re-measured 18.0 ms on
|
|
40 production crops. This is that measurement, so the number is reproducible
|
|
rather than remembered.
|
|
|
|
.venv/bin/python code/bench_ocr.py
|
|
"""
|
|
import json, statistics, sys, time
|
|
sys.path.insert(0, 'code')
|
|
import cv2
|
|
from eval_identity import LocalLaneAdapter, crop_of
|
|
|
|
lane = LocalLaneAdapter('stock-lopia-clean')
|
|
labels = json.load(open('eval/labels/image6.json'))
|
|
image = cv2.imread('add/image6.jpg')
|
|
|
|
crops = []
|
|
for facing in labels['facings']:
|
|
if facing.get('label') in (None, 'exclude'):
|
|
continue
|
|
crop = crop_of(image, facing['box'])
|
|
if crop is not None and crop.size:
|
|
crops.append(crop)
|
|
if len(crops) >= 40:
|
|
break
|
|
|
|
# Warm the recognizer: the first call loads the Vision model.
|
|
lane.text_lane.read(crops[0])
|
|
|
|
times = []
|
|
for crop in crops:
|
|
started = time.perf_counter()
|
|
lane.text_lane.read(crop)
|
|
times.append((time.perf_counter() - started) * 1000)
|
|
|
|
times.sort()
|
|
print(f'{len(times)} crops')
|
|
print(f' p50 {statistics.median(times):.1f} ms')
|
|
print(f' mean {statistics.mean(times):.1f} ms')
|
|
print(f' p95 {times[int(len(times) * 0.95)]:.1f} ms')
|
|
print(f' min {times[0]:.1f} max {times[-1]:.1f}')
|