Skip to content

Speed up frame reading with sequential access optimization#970

Merged
mprib merged 6 commits intomainfrom
feature/processing-speed-and-dashboard
Mar 17, 2026
Merged

Speed up frame reading with sequential access optimization#970
mprib merged 6 commits intomainfrom
feature/processing-speed-and-dashboard

Conversation

@mprib
Copy link
Copy Markdown
Owner

@mprib mprib commented Mar 17, 2026

Summary

  • IntrinsicCalibrationPresenter._run_collection() and api._process_camera() both create a dedicated single-owner FrameSource and read frames sequentially (every Nth frame). They were using get_frame(), which acquires a lock and seeks from a keyframe on every call.
  • Switched both to read_frame_at(), which has no lock and uses an O(1) sequential fast path for in-order reads.
  • FramePacketStreamer calls left unchanged — those involve concurrent access (peek methods called from UI thread) and genuine random-access seeks, where get_frame() is correct.

Test plan

  • Full test suite passes (389/389)
  • Manual: launch clean test project, run intrinsic collection on multiple cameras simultaneously — noticeably faster

mprib added 6 commits March 17, 2026 10:54
…board

Phase 1: FrameSource.read_frame_at() with sequential access optimization.
Tracks decode position to avoid per-frame keyframe seeks — O(1) for
sequential reads vs O(GOP) for random access. Three paths: fast (gap=1),
small-gap (decode forward), and seek fallback.

Phase 2: ThreadPoolExecutor for per-camera processing within each sync
index. Each camera gets its own FrameSource and thread. Callbacks remain
single-threaded (invoked from the sync-index loop, not pool threads).
parallel=True by default with serial escape hatch.

Phase 3: ETA display after 3s warmup, incremental coverage heatmap matrix
updated O(1) per sync index with throttled signal emission every 5s.
Coverage content panel shown during processing for live feedback.

Charuco profiling: 1.41x speedup (64.8 vs 46.0 cam-frames/s on 5-cam
demo). GIL-bound OpenCV limits thread parallelism; ONNX expected better.

389/389 tests pass, 60/60 stability runs clean, 0 type errors.
FrameSource.__del__ guard (added in 07c4c2e) surfaced 17 warnings from
tests that created streamers via create_streamer() or SynchronizedStreamManager
but never called close()/cleanup(). Added cleanup calls at end of each test.
Widen adaptiveThreshWinSizeStep from 10 to 20, reducing threshold
passes from 3 to 2 for ~2x faster failure paths. Add per-camera
mirror hint (_last_mirrored dict) to try the previously-successful
orientation first, avoiding the ~107ms wrong-orientation penalty.

Combined with parallel processing from prior commit, this brings
throughput from 64.8 to 162.6 cam-frames/s (2.5x improvement)
with zero detection rate regression.
The heatmap rendering is trivially cheap (~15 fillRect calls for a
5-camera grid), so the conservative 5s throttle made the display
feel frozen. At 2 updates/second the heatmap visibly fills in during
processing, providing useful real-time feedback.
The collection thread creates a dedicated FrameSource and reads frames
sequentially (indices [0, 10, 20, ...]). get_frame() acquires a lock and
seeks from a keyframe on every call — designed for concurrent random access.
read_frame_at() has no lock and uses an O(1) sequential fast path, which
matches the single-owner in-order access pattern exactly.
_process_camera() creates a dedicated single-owner FrameSource and iterates
frames sequentially. Same access pattern as intrinsic collection — read_frame_at
uses the O(1) sequential fast path instead of get_frame's lock-and-seek.
@mprib mprib merged commit 5e867c4 into main Mar 17, 2026
3 checks passed
@mprib mprib deleted the feature/processing-speed-and-dashboard branch March 21, 2026 15:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant