perf: bound OCR so a walking scan stays real-time, and add walk pacing
macOS Vision holds the GIL for the ~124 ms it takes to read a rail band, so the tag pass decides the live frame rate: with 2 bands every 15 frames a walking session fell to 1.7 results/s, and 1 band every 30 frames brings it back to 7.2 with tags still settling in a second or two. Measured, not guessed - the same walk, same method (orb), only the OCR duty cycle changed. The walk also gained a `pan` parameter (default 0.06, clamped 0.005-0.5) so a demo can choose its pace: pan=0.02 sweeps a row over ~8 s, which reads like a person rather than a time-lapse. Demo configuration measured end to end on the walk (20 s, 1280x720, one client): orb, pan=0.02, 1 band/30 frames -> 7.2 results/s, 178 labelled tracks, 21 distinct SKUs, first label 0.7 s, 3 readable price tags. Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
00367a95c9
commit
d38d863873
3 changed files with 34 additions and 10 deletions
|
|
@ -56,9 +56,15 @@ class Bay:
|
|||
class DemoCamera:
|
||||
"""Plans and renders the virtual walk over one or more shelf photos."""
|
||||
|
||||
def __init__(self, samples: Dict[str, Dict[str, str]], window: Tuple[int, int] = DEFAULT_WINDOW):
|
||||
def __init__(self, samples: Dict[str, Dict[str, str]], window: Tuple[int, int] = DEFAULT_WINDOW,
|
||||
pan_overlap: float = PAN_OVERLAP):
|
||||
self._samples = samples
|
||||
self._window = window
|
||||
# How far the window advances per step. The demo's pacing knob: a smaller
|
||||
# value is a slower, more deliberate sweep (more steps, a facing in view
|
||||
# for longer). Clamped so a client cannot ask for a frozen or teleporting
|
||||
# camera.
|
||||
self.pan_overlap = max(0.005, min(0.5, float(pan_overlap)))
|
||||
self._lock = threading.Lock()
|
||||
self._images: Dict[str, Any] = {}
|
||||
self._sizes: Dict[str, Tuple[int, int]] = {}
|
||||
|
|
@ -104,7 +110,7 @@ class DemoCamera:
|
|||
def _pan_steps(self, image_width: int, window_width: int) -> int:
|
||||
if window_width >= image_width:
|
||||
return 1
|
||||
stride = max(1, int(window_width * PAN_OVERLAP))
|
||||
stride = max(1, int(window_width * self.pan_overlap))
|
||||
return max(1, int(math.ceil((image_width - window_width) / stride)) + 1)
|
||||
|
||||
def plan(self, sample_ids: Sequence[str], window: Optional[Tuple[int, int]] = None) -> Dict[str, Any]:
|
||||
|
|
@ -136,7 +142,7 @@ class DemoCamera:
|
|||
],
|
||||
"steps": total,
|
||||
"row_overlap": ROW_OVERLAP,
|
||||
"pan_overlap": PAN_OVERLAP,
|
||||
"pan_overlap": self.pan_overlap,
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------ rendering
|
||||
|
|
@ -181,7 +187,7 @@ class DemoCamera:
|
|||
# Ascending: band 0 is the bottom of the shelf.
|
||||
y_bottom = min(image_height - win_h, band * stride_y)
|
||||
y = max(0, image_height - win_h - y_bottom)
|
||||
stride_x = max(1, int(win_w * PAN_OVERLAP))
|
||||
stride_x = max(1, int(win_w * self.pan_overlap))
|
||||
max_x = max(0, image_width - win_w)
|
||||
if within < per_band:
|
||||
pan = within
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue