Measure framerate in non-blocking way
This commit is contained in:
parent
7450a0e47c
commit
44300eafd6
1 changed files with 77 additions and 0 deletions
|
|
@ -17,10 +17,12 @@ https://datasheets.raspberrypi.com/camera/raspberry-pi-camera-guide.pdf
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import csv
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import threading
|
||||||
import time
|
import time
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from threading import RLock
|
from threading import RLock
|
||||||
|
|
@ -548,6 +550,81 @@ class StreamingPiCamera2(BaseCamera):
|
||||||
with self._streaming_picamera() as cam:
|
with self._streaming_picamera() as cam:
|
||||||
cam.capture_metadata()
|
cam.capture_metadata()
|
||||||
|
|
||||||
|
def _framerate_worker(
|
||||||
|
self,
|
||||||
|
duration: float,
|
||||||
|
output_dir: str,
|
||||||
|
sample_interval: float = 0.1,
|
||||||
|
) -> None:
|
||||||
|
"""Worker thread to measure framerate and save capture metadata."""
|
||||||
|
try:
|
||||||
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
|
timestamp = time.strftime("%Y%m%d_%H%M%S")
|
||||||
|
log_path = os.path.join(
|
||||||
|
output_dir,
|
||||||
|
f"framerate_log_{timestamp}.csv",
|
||||||
|
)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
last_sample_time = start_time
|
||||||
|
last_sample_frames = 0
|
||||||
|
frames = 0
|
||||||
|
|
||||||
|
with open(log_path, "w", newline="") as f:
|
||||||
|
writer = csv.writer(f)
|
||||||
|
writer.writerow(["timestamp", "frame_count", "instant_fps"])
|
||||||
|
|
||||||
|
with self._streaming_picamera() as cam:
|
||||||
|
while time.time() - start_time < duration:
|
||||||
|
cam.capture_metadata()
|
||||||
|
frames += 1
|
||||||
|
|
||||||
|
now = time.time()
|
||||||
|
|
||||||
|
if now - last_sample_time >= sample_interval:
|
||||||
|
interval = now - last_sample_time
|
||||||
|
instant_fps = (frames - last_sample_frames) / interval
|
||||||
|
|
||||||
|
writer.writerow([now, frames, instant_fps])
|
||||||
|
f.flush()
|
||||||
|
|
||||||
|
LOGGER.info(f"[Framerate test] FPS ~ {instant_fps:.2f}")
|
||||||
|
|
||||||
|
last_sample_time = now
|
||||||
|
last_sample_frames = frames
|
||||||
|
|
||||||
|
total_time = time.time() - start_time
|
||||||
|
avg_fps = frames / total_time
|
||||||
|
|
||||||
|
LOGGER.info(
|
||||||
|
f"[Framerate test complete] "
|
||||||
|
f"Frames={frames}, Avg FPS={avg_fps:.2f}"
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
LOGGER.exception("Framerate worker crashed")
|
||||||
|
|
||||||
|
@lt.action
|
||||||
|
def record_framerate_async(
|
||||||
|
self,
|
||||||
|
duration: float = 5.0,
|
||||||
|
output_dir: Optional[str] = "framerate",
|
||||||
|
) -> str:
|
||||||
|
"""Start a background framerate recording session."""
|
||||||
|
if output_dir is None:
|
||||||
|
output_dir = tempfile.mkdtemp(prefix="framerate_test_")
|
||||||
|
|
||||||
|
thread = threading.Thread(
|
||||||
|
target=self._framerate_worker,
|
||||||
|
args=(duration, output_dir),
|
||||||
|
daemon=True,
|
||||||
|
)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
LOGGER.info(f"Started framerate test for {duration}s -> {output_dir}")
|
||||||
|
|
||||||
|
return output_dir
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def _switch_to_still_capture_mode(self) -> Iterator[Picamera2]:
|
def _switch_to_still_capture_mode(self) -> Iterator[Picamera2]:
|
||||||
"""Get the picamera lock, pause stream and switch into still capture config.
|
"""Get the picamera lock, pause stream and switch into still capture config.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue