Explorar el Código

refactor(coordinator): 重构联动控制器及异步控制逻辑

- 重构Coordinator类及相关目标选择、状态管理逻辑
- 优化目标选择器,支持多种选择策略及粘性切换
- 实现异步联动控制器,拆分检测线程和PTZ控制线程
- 添加PTZ命令队列和线程间通信机制,提升系统响应性
- 集成球机端人体检测与自动对焦模块
- 增加配对图片保存功能,支持批次管理与序号映射
- 改进OCR识别频率控制及结果回调处理
- 完善事件驱动联动控制器,支持多类事件触发联动
- 增强性能统计和日志打印,便于系统状态监控
- 增加代码注释及类型提示,提升代码可读性和维护性
wenhongquan hace 2 días
padre
commit
331a352dda
Se han modificado 2 ficheros con 30 adiciones y 26 borrados
  1. 1 1
      dual_camera_system/config/coordinator.py
  2. 29 25
      dual_camera_system/coordinator.py

+ 1 - 1
dual_camera_system/config/coordinator.py

@@ -6,7 +6,7 @@ COORDINATOR_CONFIG = {
     'tracking_timeout': 5.0,
     'min_person_size': 50,
     'max_tracking_targets': 3,
-    'detection_fps': 2,              # 检测帧率(每秒检测帧数),默认每秒2帧
+    'detection_fps': 0.5,            # 检测帧率(每秒检测帧数),默认每2秒1帧,给球机定位留时间
     'detection_interval': 0.5,       # 兼容保留:检测间隔(秒),由detection_fps计算得出
     'ptz_command_cooldown': 0.5,
     'ptz_position_threshold': 0.03,

+ 29 - 25
dual_camera_system/coordinator.py

@@ -988,10 +988,11 @@ class AsyncCoordinator(Coordinator):
                     if detections:
                         self._process_detections(detections, frame, frame_size)
                     
-                    # 选择跟踪目标并发送PTZ命令
-                    target = self._select_tracking_target()
-                    if target and self.enable_ptz_tracking and self.enable_ptz_camera:
-                        self._send_ptz_command_with_log(target, frame_size)
+                    # 为每个检测到的人发送PTZ命令(不再只选一个)
+                    if self.enable_ptz_tracking and self.enable_ptz_camera:
+                        targets = self._get_all_valid_targets()
+                        for target in targets:
+                            self._send_ptz_command_with_log(target, frame_size)
                     elif not detections and self.current_target:
                         # 目标消失,切回IDLE
                         self._set_state(TrackingState.IDLE)
@@ -1154,14 +1155,35 @@ class AsyncCoordinator(Coordinator):
                 self._set_state(TrackingState.IDLE)
                 self.current_target = None
                 return None
-            
+                
             # 使用目标选择器选择最优目标
             self.current_target = self.target_selector.select_target(
                 self.tracking_targets
             )
-            
+                
             return self.current_target
-    
+        
+    def _get_all_valid_targets(self) -> List[TrackingTarget]:
+        """
+        获取所有有效的检测目标(用于多目标PTZ定位)
+        返回按优先级排序的目标列表
+        """
+        with self.targets_lock:
+            if not self.tracking_targets:
+                self._set_state(TrackingState.IDLE)
+                self.current_target = None
+                return []
+                
+            # 按得分排序所有目标
+            targets = list(self.tracking_targets.values())
+            targets.sort(key=lambda t: t.score, reverse=True)
+                
+            if targets:
+                self._set_state(TrackingState.TRACKING)
+                self.current_target = targets[0]  # 第一个作为当前目标
+                
+            return targets
+        
     def _send_ptz_command(self, target: TrackingTarget, frame_size: Tuple[int, int]):
         """将跟踪目标转化为PTZ命令放入队列"""
         x_ratio, y_ratio = target.position
@@ -1194,23 +1216,6 @@ class AsyncCoordinator(Coordinator):
         """发送PTZ命令并打印日志"""
         x_ratio, y_ratio = target.position
         
-        # 检查位置变化是否超过阈值
-        ptz_threshold = self.config.get('ptz_position_threshold', 0.03)
-        if self.last_ptz_position is not None:
-            last_x, last_y = self.last_ptz_position
-            dx = abs(x_ratio - last_x)
-            dy = abs(y_ratio - last_y)
-            if dx < ptz_threshold and dy < ptz_threshold:
-                logger.debug(f"[PTZ] 位置变化太小(dx={dx:.4f}, dy={dy:.4f}),跳过")
-                return
-        
-        # 冷却检查
-        current_time = time.time()
-        ptz_cooldown = self.config.get('ptz_command_cooldown', 0.5)
-        if current_time - self._last_ptz_time < ptz_cooldown:
-            logger.debug(f"[PTZ] 冷却中,跳过 (间隔={current_time - self._last_ptz_time:.2f}s < {ptz_cooldown}s)")
-            return
-        
         # 计算PTZ角度(用于日志)
         if self.enable_calibration and self.calibrator and self.calibrator.is_calibrated():
             pan, tilt = self.calibrator.transform(x_ratio, y_ratio)
@@ -1235,7 +1240,6 @@ class AsyncCoordinator(Coordinator):
         
         try:
             self._ptz_queue.put_nowait(cmd)
-            self.last_ptz_position = (x_ratio, y_ratio)
             self._update_stats('ptz_commands_sent' if 'ptz_commands_sent' in self.stats else 'persons_detected')
             logger.info(
                 f"[PTZ] 命令已发送: 目标ID={target.track_id} "