浏览代码

feat(安全检测): 增强安全检测模块的日志和状态监控

添加详细的日志记录和状态监控功能到安全检测模块
在AsyncCoordinator中增加检测统计和日志输出
禁用系统配置中的自动校准和PTZ跟踪联动
wenhongquan 3 天之前
父节点
当前提交
e81289f47a
共有 3 个文件被更改,包括 106 次插入13 次删除
  1. 2 2
      dual_camera_system/config/system.py
  2. 36 4
      dual_camera_system/coordinator.py
  3. 68 7
      dual_camera_system/safety_coordinator.py

+ 2 - 2
dual_camera_system/config/system.py

@@ -20,8 +20,8 @@ SYSTEM_CONFIG = {
     'enable_safety_detection': True,     # 启用安全检测 (安全帽/反光衣)
     
     # 联动与校准
-    'enable_calibration': True,          # 启用自动校准
-    'enable_ptz_tracking': True,         # 启用 PTZ 跟踪联动
+    'enable_calibration': False,          # 启用自动校准
+    'enable_ptz_tracking': False,         # 启用 PTZ 跟踪联动
     
     # OCR 与大模型
     'enable_ocr': False,                  # 启用 OCR 编号识别

+ 36 - 4
dual_camera_system/coordinator.py

@@ -667,11 +667,20 @@ class AsyncCoordinator(Coordinator):
         frame_count = 0
         last_log_time = time.time()
         log_interval = 5.0  # 每5秒打印一次帧率统计
+        detection_run_count = 0
+        detection_person_count = 0
+        last_no_detect_log_time = 0
+        no_detect_log_interval = 30.0
         
         with self.stats_lock:
             self.stats['start_time'] = time.time()
         
-        logger.info(f"[检测线程] 启动, 检测间隔={detection_interval}s, PTZ冷却={ptz_cooldown}s")
+        if self.detector is None:
+            logger.warning("[检测线程] ⚠️ 人体检测器未初始化! 检测功能不可用, 请检查 YOLO 模型是否正确加载")
+        elif not self.enable_detection:
+            logger.warning("[检测线程] ⚠️ 人体检测已禁用 (enable_detection=False)")
+        else:
+            logger.info(f"[检测线程] ✓ 人体检测器已就绪, 检测间隔={detection_interval}s, PTZ冷却={ptz_cooldown}s")
         
         while self.running:
             try:
@@ -685,23 +694,39 @@ class AsyncCoordinator(Coordinator):
                 self._update_stats('frames_processed')
                 frame_size = (frame.shape[1], frame.shape[0])
                 
-                # 每隔 log_interval 打印帧率统计
                 if current_time - last_log_time >= log_interval:
                     elapsed = current_time - last_log_time
                     fps = frame_count / elapsed if elapsed > 0 else 0
-                    logger.info(f"[检测线程] 帧率={fps:.1f}fps, 处理帧={frame_count}")
+                    
+                    state_str = self.state.name if hasattr(self.state, 'name') else str(self.state)
+                    stats_parts = [f"帧率={fps:.1f}fps", f"处理帧={frame_count}", f"状态={state_str}"]
+                    
+                    if self.detector is None:
+                        stats_parts.append("检测器=未加载")
+                    elif not self.enable_detection:
+                        stats_parts.append("检测=已禁用")
+                    else:
+                        stats_parts.append(f"检测轮次={detection_run_count}(有人={detection_person_count})")
+                    
+                    with self.targets_lock:
+                        target_count = len(self.tracking_targets)
+                    stats_parts.append(f"跟踪目标={target_count}")
+                    
+                    logger.info(f"[检测线程] {', '.join(stats_parts)}")
                     frame_count = 0
                     last_log_time = current_time
                 
                 # 周期性检测(约1次/秒)
                 if current_time - last_detection_time >= detection_interval:
                     last_detection_time = current_time
+                    detection_run_count += 1
                     
                     # YOLO 人体检测
                     detections = self._detect_persons(frame)
                     
                     if detections:
                         self._update_stats('persons_detected', len(detections))
+                        detection_person_count += 1
                     
                     # 更新跟踪
                     tracked = self.tracker.update(detections)
@@ -712,7 +737,7 @@ class AsyncCoordinator(Coordinator):
                         for t in tracked:
                             x_ratio, y_ratio = t.position
                             logger.info(
-                                f"[检测] 目标ID={t.track_id} "
+                                f"[检测] 目标ID={t.track_id} "
                                 f"位置=({x_ratio:.3f}, {y_ratio:.3f}) "
                                 f"置信度={getattr(t, 'confidence', 0):.2f}"
                             )
@@ -720,6 +745,13 @@ class AsyncCoordinator(Coordinator):
                         # 有检测但没跟踪上
                         for d in detections:
                             logger.debug(f"[检测] 未跟踪: {d.class_name} @ {d.center}")
+                    else:
+                        if current_time - last_no_detect_log_time >= no_detect_log_interval:
+                            logger.info(
+                                f"[检测] · YOLO检测运行正常, 本轮未检测到人员 "
+                                f"(累计检测{detection_run_count}轮, 检测到人{detection_person_count}轮)"
+                            )
+                            last_no_detect_log_time = current_time
                     
                     if tracked:
                         self._process_detections(tracked, frame, frame_size)

+ 68 - 7
dual_camera_system/safety_coordinator.py

@@ -223,33 +223,94 @@ class SafetyCoordinator:
         """工作线程"""
         detection_interval = SAFETY_DETECTION_CONFIG.get('detection_interval', 0.1)
         last_detection_time = 0
+        detection_run_count = 0
+        detection_violation_count = 0
+        frame_count = 0
+        last_log_time = time.time()
+        heartbeat_interval = 30.0
+        last_no_detect_log_time = 0
+        
+        import logging
+        sc_logger = logging.getLogger(__name__)
+        
+        if self.detector is None:
+            sc_logger.warning("[安全检测] ⚠️ 安全检测器未初始化! 安全检测不可用")
+        else:
+            sc_logger.info(f"[安全检测] ✓ 安全检测器已就绪, 检测间隔={detection_interval}s")
         
         while self.running:
             try:
                 current_time = time.time()
                 
-                # 获取帧
                 frame = self.camera.get_frame() if self.camera else None
                 if frame is None:
                     time.sleep(0.01)
                     continue
                 
+                frame_count += 1
                 self._update_stats('frames_processed')
                 
-                # 周期性检测
+                if current_time - last_log_time >= heartbeat_interval:
+                    stats = self.get_stats()
+                    state_str = self.state.name if hasattr(self.state, 'name') else str(self.state)
+                    sc_logger.info(
+                        f"[安全检测] 状态={state_str}, "
+                        f"检测轮次={detection_run_count}(有人={detection_violation_count}), "
+                        f"帧数={frame_count}"
+                    )
+                    frame_count = 0
+                    last_log_time = current_time
+                
                 if current_time - last_detection_time >= detection_interval:
                     last_detection_time = current_time
-                    self._process_frame(frame)
-                
-                # 清理过期跟踪
-                self._cleanup_tracks()
+                    detection_run_count += 1
+                    
+                    result = self._process_frame_with_logging(frame, detection_run_count, detection_violation_count, last_no_detect_log_time, sc_logger)
+                    detection_violation_count = result
+                    
+                    self._cleanup_tracks()
                 
                 time.sleep(0.01)
                 
             except Exception as e:
-                print(f"处理错误: {e}")
+                sc_logger.error(f"[安全检测] 处理错误: {e}")
                 time.sleep(0.1)
     
+    def _process_frame_with_logging(self, frame: np.ndarray, run_count: int, violation_count: int, last_no_detect_time: float, sc_logger) -> int:
+        """处理帧并返回更新的violation_count"""
+        if self.detector is None:
+            return violation_count
+        
+        self._set_state(CoordinatorState.DETECTING)
+        
+        detections = self.detector.detect(frame)
+        status_list = self.detector.check_safety(frame, detections)
+        
+        self._update_stats('persons_detected', len(status_list))
+        self._update_tracks(detections)
+        
+        has_violation = False
+        for status in status_list:
+            if status.is_violation:
+                self._handle_violation(status, frame)
+                has_violation = True
+        
+        if has_violation:
+            violation_count += 1
+        
+        if not status_list:
+            current_time = time.time()
+            if current_time - last_no_detect_time >= 30.0:
+                sc_logger.info(
+                    f"[安全检测] · YOLO检测运行正常, 本轮未检测到人员 "
+                    f"(累计检测{run_count}轮, 违规{violation_count}轮)"
+                )
+        
+        if self.on_frame_processed:
+            self.on_frame_processed(frame, detections, status_list)
+        
+        return violation_count
+    
     def _process_frame(self, frame: np.ndarray):
         """处理帧"""
         if self.detector is None: