Refactor detection handling by separating DetectionWorker and integrating it into MainWindow

This commit is contained in:
2026-05-07 19:37:40 +02:00
parent 673cc64169
commit b65d0e2130
2 changed files with 73 additions and 32 deletions

View File

@@ -50,38 +50,20 @@ def rotate_frame(frame: np.ndarray, degrees: int) -> np.ndarray:
class CameraWorker(QThread):
frame_ready = Signal(object)
detection_ready = Signal(object)
camera_error = Signal(str)
def __init__(self, config: dict[str, Any], app_config: Any) -> None:
super().__init__()
self.config = config
self.app_config = app_config
self.pipeline = DetectionPipeline(config, app_config)
self._running = threading.Event()
self._running.set()
self._detecting = False
self._accepted = False
self._frame_count = 0
self._capture: cv2.VideoCapture | None = None
self._lock = threading.Lock()
def stop(self) -> None:
self._running.clear()
@Slot()
def start_detection(self) -> None:
with self._lock:
self._detecting = True
self._accepted = False
self._frame_count = 0
@Slot()
def accept_detection(self) -> None:
with self._lock:
self._detecting = False
self._accepted = True
@Slot(dict)
def update_camera_config(self, camera_config: dict[str, Any]) -> None:
with self._lock:
@@ -115,7 +97,6 @@ class CameraWorker(QThread):
rotation_degrees = int(self.config["camera"].get("rotation_degrees", 0))
frame = rotate_frame(frame, rotation_degrees)
self.frame_ready.emit(frame)
self._maybe_detect(frame)
finally:
capture.release()
self._capture = None
@@ -131,15 +112,53 @@ class CameraWorker(QThread):
continue
capture.set(CV_CAP_PROPS[name], float(value))
def _maybe_detect(self, frame: np.ndarray) -> None:
class DetectionWorker(QThread):
detection_ready = Signal(object)
def __init__(self, config: dict[str, Any], app_config: Any) -> None:
super().__init__()
self.config = config
self.app_config = app_config
self.pipeline: DetectionPipeline | None = None
self._running = threading.Event()
self._running.set()
self._pending = threading.Event()
self._lock = threading.Lock()
self._pending_frame: np.ndarray | None = None
self._busy = False
def stop(self) -> None:
self._running.clear()
self._pending.set()
def request_detection(self, frame: np.ndarray) -> bool:
with self._lock:
detecting = self._detecting and not self._accepted
frame_stride = max(1, int(self.config["detection"].get("frame_stride", 5)))
self._frame_count += 1
should_detect = detecting and self._frame_count % frame_stride == 0
if self._busy or self._pending_frame is not None:
return False
self._pending_frame = frame.copy()
self._pending.set()
return True
if not should_detect:
return
def run(self) -> None:
while self._running.is_set():
self._pending.wait(0.2)
if not self._running.is_set():
break
result: DetectionResult = self.pipeline.process(frame)
self.detection_ready.emit(result)
with self._lock:
frame = self._pending_frame
self._pending_frame = None
self._pending.clear()
if frame is None:
continue
self._busy = True
try:
if self.pipeline is None:
self.pipeline = DetectionPipeline(self.config, self.app_config)
result: DetectionResult = self.pipeline.process(frame)
self.detection_ready.emit(result)
finally:
with self._lock:
self._busy = False