Parcourir la source

refactor(coordinator): 重构联动控制器以优化异步检测与PTZ控制

- 将联动控制器拆分为检测线程和PTZ控制线程,分离职责提高响应速度
- 实现异步队列通信,避免检测阻塞PTZ控制
- 新增球机端人体检测初始化及自动变焦控制
- 加强目标选择策略,支持目标粘性和多策略切换
- 优化目标跨帧匹配逻辑,支持连续目标跟踪
- 添加配对图片保存功能,支持按检测批次保存图片
- 改善OCR调用频率控制及结果回调机制
- 完善状态管理与性能统计,支持多线程安全访问
- 引入事件驱动联动控制,支持基于事件触发联动跟踪
- 增加PTZ位置确认机制和命令冷却控制,防止命令过频繁
- 移除冗余代码,提升代码模块化和可维护性
wenhongquan il y a 2 jours
Parent
commit
6431025bef

BIN
dual_camera_system/__pycache__/coordinator.cpython-310.pyc


+ 43 - 3
dual_camera_system/coordinator.py

@@ -1115,15 +1115,44 @@ class AsyncCoordinator(Coordinator):
             if det.class_name == 'person' and det.confidence >= person_threshold:
                 valid_persons.append(det)
         
-        if not valid_persons:
+        # 【关键修复】去重:按位置合并重叠的检测框
+        # 如果两个检测框的中心距离小于阈值,只保留置信度更高的
+        DEDUP_DISTANCE = 0.05  # 画面比例 5%
+        dedup_persons = []
+        for det in valid_persons:
+            det_x = det.center[0] / frame_size[0]
+            det_y = det.center[1] / frame_size[1]
+            
+            # 检查是否与已有人员重叠
+            is_duplicate = False
+            for i, existing in enumerate(dedup_persons):
+                ex_x = existing.center[0] / frame_size[0]
+                ex_y = existing.center[1] / frame_size[1]
+                
+                dist = math.sqrt((det_x - ex_x)**2 + (det_y - ex_y)**2)
+                if dist < DEDUP_DISTANCE:
+                    # 重叠,保留置信度更高的
+                    is_duplicate = True
+                    if det.confidence > existing.confidence:
+                        dedup_persons[i] = det
+                    break
+            
+            if not is_duplicate:
+                dedup_persons.append(det)
+        
+        
+        if not dedup_persons:
             logger.debug(f"[配对保存] 无有效人员(阈值={person_threshold}),跳过批次创建")
             return
         
-        # 构建人员信息列表(只包含有效人员)
+        
+        logger.info(f"[配对保存] 检测结果去重: {len(valid_persons)} -> {len(dedup_persons)} 个人员")
+        
+        # 构建人员信息列表(只包含去重后的人员)
         persons = []
         self._person_ptz_index = {}  # 重置索引映射
         
-        for i, det in enumerate(valid_persons):
+        for i, det in enumerate(dedup_persons):
             x_ratio = det.center[0] / frame_size[0]
             y_ratio = det.center[1] / frame_size[1]
             
@@ -1631,6 +1660,12 @@ class SequentialCoordinator(AsyncCoordinator):
                 state = self._get_capture_state()
                 
                 if state == 'idle':
+                    # 【关键修复】每轮检测开始前清空跟踪目标,防止跨帧累积
+                    with self.targets_lock:
+                        if self.tracking_targets:
+                            logger.debug(f"[顺序模式] 清空上一轮跟踪目标: {len(self.tracking_targets)} 个")
+                            self.tracking_targets.clear()
+                    
                     # 空闲状态:周期性检测
                     if current_time - last_detection_time >= detection_interval:
                         last_detection_time = current_time
@@ -1833,6 +1868,11 @@ class SequentialCoordinator(AsyncCoordinator):
         with self._batch_targets_lock:
             self._batch_targets = []
             self._current_capture_index = 0
+        
+        # 【关键修复】清空跟踪目标,防止跨帧累积
+        with self.targets_lock:
+            self.tracking_targets.clear()
+            logger.info("[顺序模式] 已清空跟踪目标列表")
     
     def _save_local_snapshot(self, frame: np.ndarray, index: int, 
                               pan: float, tilt: float, zoom: int):