feat: a synthetic store walk, and the live tuning it forced out
/v1/demo/plan + /v1/demo/frame give a demo the one thing a still image cannot: motion. The virtual camera pans a shelf row left to right, steps up, and pans back - a store employee sweeping a shelf - over a real shelf photo, ~1 ms per frame, deterministic, and wrapping so an unattended demo loops. The client drives only `step`, so the walk's speed follows whatever frame rate it can sustain. Three real defects came out of measuring the walk rather than a still: - Bands were keyed by on-screen position, so a walking camera minted a new key every few pixels of pan and re-read the same shelf continuously. Keyed by row now; OCR stops chasing the window. - The classification budget was consumed by retries of products already leaving the frame. Retries now skip anything near the edge, and a track gets 2 attempts. - The pan advance was 0.22 of the window per step: a facing was in view for one or two frames, so nothing could ever be classified (9 labelled tracks in 20 s). 0.06 keeps a product in view for about a second. Measured on the walk (20 s, 1280x720 frames, one client): orb labels 296 tracks across 21 SKUs with the first label at 0.2 s, while hybrid manages 13 tracks / 4 SKUs at 5.4 s - so the live default for a demo is the fast method, with hybrid kept for tap-to-inspect. Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
a18a80a21e
commit
00367a95c9
5 changed files with 466 additions and 16 deletions
|
|
@ -64,10 +64,13 @@ class LiveSettings:
|
|||
tags: bool = True
|
||||
min_hits: int = 2
|
||||
min_crop_px: int = 40
|
||||
max_attempts: int = 3
|
||||
max_attempts: int = 2
|
||||
retry_gap: int = 8
|
||||
# A product drifting out of the frame is not worth a retry: the budget belongs
|
||||
# to what is still in front of the camera.
|
||||
retry_edge_ratio: float = 0.06
|
||||
area_growth: float = 1.3
|
||||
max_inflight_per_session: int = 12
|
||||
max_inflight_per_session: int = 16
|
||||
edge_margin_ratio: float = 0.015
|
||||
glare_fraction: float = 0.02
|
||||
glare_pixel: int = 245
|
||||
|
|
@ -545,8 +548,14 @@ class LiveSession:
|
|||
continue
|
||||
if track.attempts >= self.settings.max_attempts:
|
||||
continue
|
||||
if track.attempts > 0 and (seq - track.last_attempt_seq) < self.settings.retry_gap:
|
||||
if track.area() < self.settings.area_growth * max(1, track.last_attempt_area):
|
||||
if track.attempts > 0:
|
||||
if (seq - track.last_attempt_seq) < self.settings.retry_gap:
|
||||
if track.area() < self.settings.area_growth * max(1, track.last_attempt_area):
|
||||
continue
|
||||
retry_margin_x = int(frame_w * self.settings.retry_edge_ratio)
|
||||
retry_margin_y = int(frame_h * self.settings.retry_edge_ratio)
|
||||
if (x1 <= retry_margin_x or y1 <= retry_margin_y
|
||||
or x2 >= frame_w - retry_margin_x or y2 >= frame_h - retry_margin_y):
|
||||
continue
|
||||
eligible.append(track)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue