From 75ea66c452caa2334bbb59b08984be9ed156f7fa Mon Sep 17 00:00:00 2001 From: 16337 <1633794139@qq.com> Date: Wed, 25 Feb 2026 09:12:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(intrusion):=20=E6=8B=86=E5=88=86=E5=8F=82?= =?UTF-8?q?=E6=95=B0=EF=BC=8C=E6=B6=88=E5=A4=B1=E7=A1=AE=E8=AE=A43?= =?UTF-8?q?=E5=88=86=E9=92=9F=EF=BC=8C=E6=8C=81=E7=BB=AD=E6=9C=89=E4=BA=BA?= =?UTF-8?q?5=E7=A7=92=E6=89=8D=E9=87=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 拆分confirm_seconds为confirm_intrusion_seconds(5秒)和confirm_clear_seconds(180秒) - 入侵确认:持续检测到人5秒 → 触发告警 - 消失确认:持续无人180秒 → 自动resolve - 消失确认期间逻辑: - 短暂有人(<5秒):继续倒计时 - 持续有人(≥5秒):回到ALARMED状态 - 向后兼容:保留confirm_seconds参数 --- algorithms.py | 88 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 28 deletions(-) diff --git a/algorithms.py b/algorithms.py index a8b1b5a..1bf5af1 100644 --- a/algorithms.py +++ b/algorithms.py @@ -371,16 +371,19 @@ class LeavePostAlgorithm: class IntrusionAlgorithm: """ - 周界入侵检测算法(状态机版本 v2.0) + 周界入侵检测算法(状态机版本 v3.0) 状态机: IDLE → CONFIRMING_INTRUSION → ALARMED → CONFIRMING_CLEAR → IDLE 业务流程: - 1. 检测到人 → 入侵确认期(confirm_seconds,默认5秒) + 1. 检测到人 → 入侵确认期(confirm_intrusion_seconds,默认5秒) 2. 确认入侵 → 触发告警(ALARMED状态) - 3. 人离开ROI → 入侵消失确认期(confirm_seconds,默认5秒) - 4. 确认消失 → 发送resolve事件 → 回到空闲状态 + 3. 人离开ROI → 入侵消失确认期(confirm_clear_seconds,默认180秒) + 4. 消失确认期间: + - 短暂有人(<5秒):继续倒计时 + - 持续有人(≥5秒):回到ALARMED状态 + 5. 确认消失(持续无人180秒)→ 发送resolve事件 → 回到空闲状态 """ # 状态定义 @@ -395,11 +398,20 @@ class IntrusionAlgorithm: def __init__( self, cooldown_seconds: int = 300, - confirm_seconds: int = 5, + confirm_seconds: int = 5, # 向后兼容:同时设置入侵和消失确认时间 + confirm_intrusion_seconds: Optional[int] = None, # 入侵确认时间(默认5秒) + confirm_clear_seconds: Optional[int] = None, # 消失确认时间(默认180秒) target_class: Optional[str] = None, ): self.cooldown_seconds = cooldown_seconds + + # 参数兼容处理 + self.confirm_intrusion_seconds = confirm_intrusion_seconds if confirm_intrusion_seconds is not None else confirm_seconds + self.confirm_clear_seconds = confirm_clear_seconds if confirm_clear_seconds is not None else 180 + + # 向后兼容 self.confirm_seconds = confirm_seconds + self.target_class = target_class # 状态变量 @@ -410,6 +422,9 @@ class IntrusionAlgorithm: self._last_alarm_id: Optional[str] = None self._intrusion_start_time: Optional[datetime] = None + # CONFIRMING_CLEAR状态下检测到人的时间(用于判断是否持续5秒) + self._person_detected_in_clear_time: Optional[datetime] = None + # 冷却期管理 self.alert_cooldowns: Dict[str, datetime] = {} @@ -487,7 +502,7 @@ class IntrusionAlgorithm: self.state = self.STATE_IDLE self.state_start_time = None logger.debug(f"ROI {roi_id}: CONFIRMING_INTRUSION → IDLE (人消失)") - elif elapsed >= self.confirm_seconds: + elif elapsed >= self.confirm_intrusion_seconds: # 入侵确认成功,检查冷却期 cooldown_key = f"{camera_id}_{roi_id}" if cooldown_key not in self.alert_cooldowns or \ @@ -534,30 +549,46 @@ class IntrusionAlgorithm: elapsed = (current_time - self.state_start_time).total_seconds() if roi_has_person: - # 人又出现了,回到ALARMED - self.state = self.STATE_ALARMED - self.state_start_time = current_time - logger.debug(f"ROI {roi_id}: CONFIRMING_CLEAR → ALARMED (人又出现)") - elif elapsed >= self.confirm_seconds: - # 消失确认成功,发送resolve事件 - if self._last_alarm_id and self._intrusion_start_time: - duration_ms = int((current_time - self._intrusion_start_time).total_seconds() * 1000) - alerts.append({ - "alert_type": "alarm_resolve", - "resolve_alarm_id": self._last_alarm_id, - "duration_ms": duration_ms, - "last_frame_time": current_time.strftime('%Y-%m-%d %H:%M:%S'), - "resolve_type": "intrusion_cleared", - }) + # 检测到有人 + if self._person_detected_in_clear_time is None: + # 第一次检测到人,记录时间 + self._person_detected_in_clear_time = current_time + logger.debug(f"ROI {roi_id}: CONFIRMING_CLEAR 检测到人,开始确认(需持续{self.confirm_intrusion_seconds}秒)") + else: + # 持续有人,检查是否达到确认时间 + person_elapsed = (current_time - self._person_detected_in_clear_time).total_seconds() + if person_elapsed >= self.confirm_intrusion_seconds: + # 确认有人重新入侵,回到ALARMED + self.state = self.STATE_ALARMED + self.state_start_time = None + self._person_detected_in_clear_time = None + logger.info(f"ROI {roi_id}: CONFIRMING_CLEAR → ALARMED (确认有人重新入侵,持续{person_elapsed:.1f}秒)") + else: + # 没有人 + self._person_detected_in_clear_time = None # 清除临时计时 - logger.info(f"ROI {roi_id}: 告警已解决(入侵消失)") + # 检查是否达到消失确认时间 + if elapsed >= self.confirm_clear_seconds: + # 消失确认成功,发送resolve事件 + if self._last_alarm_id and self._intrusion_start_time: + duration_ms = int((current_time - self._intrusion_start_time).total_seconds() * 1000) + alerts.append({ + "alert_type": "alarm_resolve", + "resolve_alarm_id": self._last_alarm_id, + "duration_ms": duration_ms, + "last_frame_time": current_time.strftime('%Y-%m-%d %H:%M:%S'), + "resolve_type": "intrusion_cleared", + }) - # 重置状态 - self.state = self.STATE_IDLE - self.state_start_time = None - self._last_alarm_id = None - self._intrusion_start_time = None - logger.debug(f"ROI {roi_id}: CONFIRMING_CLEAR → IDLE (消失确认成功)") + logger.info(f"ROI {roi_id}: 告警已解决(入侵消失,持续无人{elapsed:.1f}秒)") + + # 重置状态 + self.state = self.STATE_IDLE + self.state_start_time = None + self._last_alarm_id = None + self._intrusion_start_time = None + self._person_detected_in_clear_time = None + logger.debug(f"ROI {roi_id}: CONFIRMING_CLEAR → IDLE (消失确认成功)") return alerts @@ -571,6 +602,7 @@ class IntrusionAlgorithm: self.state_start_time = None self._last_alarm_id = None self._intrusion_start_time = None + self._person_detected_in_clear_time = None self.alert_cooldowns.clear() # 向后兼容 self.last_alert_time.clear()