diff --git a/algorithms.py b/algorithms.py index ef07d0d..eff814f 100644 --- a/algorithms.py +++ b/algorithms.py @@ -18,6 +18,7 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) class LeavePostAlgorithm: STATE_WAITING = "WAITING" + STATE_CONFIRMING = "CONFIRMING" STATE_ON_DUTY = "ON_DUTY" STATE_LEAVING = "LEAVING" STATE_OFF_DUTY = "OFF_DUTY" @@ -26,7 +27,7 @@ class LeavePostAlgorithm: def __init__( self, confirm_on_duty_sec: int = 10, - confirm_leave_sec: int = 10, + confirm_leave_sec: int = 30, cooldown_sec: int = 600, working_hours: Optional[List[Dict]] = None, target_class: Optional[str] = "person", @@ -140,13 +141,28 @@ class LeavePostAlgorithm: if self.state == self.STATE_WAITING: if roi_has_person: - self.state = self.STATE_ON_DUTY + # 检测到人,进入上岗确认阶段 + self.state = self.STATE_CONFIRMING self.state_start_time = current_time self.detection_history.clear() self.detection_history.append((current_time, True)) else: pass + elif self.state == self.STATE_CONFIRMING: + self.detection_history.append((current_time, roi_has_person)) + if not roi_has_person: + # 人消失,回到等待状态 + self.state = self.STATE_WAITING + self.state_start_time = None + self.detection_history.clear() + else: + elapsed = (current_time - self.state_start_time).total_seconds() + if elapsed >= self.confirm_on_duty_sec: + # 持续在岗达到确认时长,正式确认上岗 + self.state = self.STATE_ON_DUTY + self.state_start_time = current_time + elif self.state == self.STATE_ON_DUTY: self.detection_history.append((current_time, roi_has_person)) if not roi_has_person: @@ -395,7 +411,7 @@ class AlgorithmManager: self.default_params = { "leave_post": { "confirm_on_duty_sec": 10, - "confirm_leave_sec": 10, + "confirm_leave_sec": 30, "cooldown_sec": 600, "target_class": "person", }, @@ -520,7 +536,7 @@ class AlgorithmManager: if algo_code == "leave_post": algo_params = { "confirm_on_duty_sec": params.get("confirm_on_duty_sec", 10), - "confirm_leave_sec": params.get("confirm_leave_sec", 10), + "confirm_leave_sec": params.get("confirm_leave_sec", 30), "cooldown_sec": params.get("cooldown_sec", 600), "working_hours": params.get("working_hours", []), "target_class": params.get("target_class", bind_config.get("target_class", "person")), @@ -638,7 +654,7 @@ class AlgorithmManager: roi_working_hours = algo_params.get("working_hours") or self.working_hours self.algorithms[roi_id][key]["leave_post"] = LeavePostAlgorithm( confirm_on_duty_sec=algo_params.get("confirm_on_duty_sec", 10), - confirm_leave_sec=algo_params.get("confirm_leave_sec", 10), + confirm_leave_sec=algo_params.get("confirm_leave_sec", 30), cooldown_sec=algo_params.get("cooldown_sec", 600), working_hours=roi_working_hours, target_class=algo_params.get("target_class", "person"), diff --git a/config/database.py b/config/database.py index 3048745..b1eda4e 100644 --- a/config/database.py +++ b/config/database.py @@ -265,7 +265,7 @@ class SQLiteManager: 'target_class': 'person', 'param_schema': json.dumps({ "confirm_on_duty_sec": {"type": "int", "default": 10, "min": 1}, - "confirm_leave_sec": {"type": "int", "default": 10, "min": 1}, + "confirm_leave_sec": {"type": "int", "default": 30, "min": 1}, "cooldown_sec": {"type": "int", "default": 600, "min": 0}, "working_hours": {"type": "list", "default": []}, }), diff --git a/main.py b/main.py index 47a384f..01e8e2d 100644 --- a/main.py +++ b/main.py @@ -404,12 +404,12 @@ class EdgeInferenceService: for idx, (camera_id, roi, bind, frame, _, scale_info) in enumerate(roi_items): boxes, scores, class_ids = batch_results[idx] - if len(boxes) > 0: - self._handle_detections( - camera_id, roi, bind, frame, - boxes, scores, class_ids, - scale_info - ) + # 无论是否检测到目标都要调用算法(离岗检测需要"无人"信号) + self._handle_detections( + camera_id, roi, bind, frame, + boxes, scores, class_ids, + scale_info + ) except Exception as e: self._logger.error(f"批量处理 ROI 失败: {e}") @@ -489,8 +489,7 @@ class EdgeInferenceService: tracks = self._build_tracks(roi, boxes, scores, class_ids, scale_info) - if not tracks: - return + # 离岗检测需要"无人"信号,不能因为 tracks 为空就跳过算法 # 诊断日志:tracks 内容(非告警诊断日志,使用 DEBUG 级别) self._logger.debug(f"[{camera_id}] tracks: {[t.get('class') for t in tracks]}, target_class={bind.target_class}")