From 6fc17ccf64cda5b728932db3e3f16c0779198228 Mon Sep 17 00:00:00 2001 From: 16337 <1633794139@qq.com> Date: Thu, 22 Jan 2026 15:08:28 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8D=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E9=A1=BA=E5=BA=8F=E9=94=99=E8=AF=AF=E3=80=81ROI=20=E5=8C=B9?= =?UTF-8?q?=E9=85=8D=E5=A4=B1=E6=95=88=E3=80=81=E7=8A=B6=E6=80=81=E6=9C=BA?= =?UTF-8?q?=E7=BC=BA=E5=A4=B1=20INIT=20=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 调整 process() 函数参数顺序,确保 roi_id 和 camera_id 正确对应 - 重构 ROI 匹配逻辑,使用明确的 roi_id 进行区域归属判断 - 引入 INIT 状态:启动时若 ROI 无人,先进入 INIT, 经 off_duty_confirm_sec 确认后才进入 OFF_DUTY 倒计时 --- inference/rules/algorithms.py | 84 +++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/inference/rules/algorithms.py b/inference/rules/algorithms.py index 3511498..f3c355f 100644 --- a/inference/rules/algorithms.py +++ b/inference/rules/algorithms.py @@ -16,6 +16,7 @@ class LeavePostAlgorithm: STATE_ON_DUTY = "ON_DUTY" STATE_OFF_DUTY_COUNTDOWN = "OFF_DUTY_COUNTDOWN" STATE_NON_WORK_TIME = "NON_WORK_TIME" + STATE_INIT = "INIT" def __init__( self, @@ -32,11 +33,13 @@ class LeavePostAlgorithm: self.alert_cooldowns: Dict[str, datetime] = {} self.cooldown_seconds = 300 - self.state: str = self.STATE_ON_DUTY + self.state: str = self.STATE_INIT self.state_start_time: Optional[datetime] = None self.on_duty_window = deque() self.alarm_sent: bool = False self.last_person_seen_time: Optional[datetime] = None + self.last_detection_time: Optional[datetime] = None + self.init_start_time: Optional[datetime] = None def is_in_working_hours(self, dt: Optional[datetime] = None) -> bool: if not self.working_hours: @@ -62,64 +65,95 @@ class LeavePostAlgorithm: def process( self, + roi_id: str, camera_id: str, tracks: List[Dict], current_time: Optional[datetime] = None, ) -> List[Dict]: current_time = current_time or datetime.now() + roi_has_person = False + for det in tracks: + if self.check_detection_in_roi(det, roi_id): + roi_has_person = True + break + in_work = self.is_in_working_hours(current_time) alerts = [] if not in_work: self.state = self.STATE_NON_WORK_TIME self.last_person_seen_time = None + self.last_detection_time = None self.on_duty_window.clear() self.alarm_sent = False + self.init_start_time = None else: if self.state == self.STATE_NON_WORK_TIME: - self.state = self.STATE_ON_DUTY + self.state = self.STATE_INIT + self.init_start_time = current_time self.on_duty_window.clear() self.alarm_sent = False - roi_has_person = False - for det in tracks: - if self.check_detection_in_roi(det, camera_id): - roi_has_person = True - break - - if self.state == self.STATE_ON_DUTY: - self.on_duty_window.append((current_time, roi_has_person)) - while self.on_duty_window and (current_time - self.on_duty_window[0][0]).total_seconds() > self.confirm_sec: - self.on_duty_window.popleft() - - hit_ratio = sum(1 for t, detected in self.on_duty_window if detected) / max(len(self.on_duty_window), 1) - - if not roi_has_person and hit_ratio == 0: - self.state = self.STATE_OFF_DUTY_COUNTDOWN + if self.state == self.STATE_INIT: + if roi_has_person: + self.state = self.STATE_ON_DUTY self.state_start_time = current_time - self.alarm_sent = False - elif hit_ratio >= 0.75 and (current_time - self.on_duty_window[0][0]).total_seconds() >= self.confirm_sec: + self.on_duty_window.clear() + self.on_duty_window.append((current_time, True)) self.last_person_seen_time = current_time + self.last_detection_time = current_time + self.init_start_time = None + else: + if self.init_start_time is None: + self.init_start_time = current_time + + elapsed_since_init = (current_time - self.init_start_time).total_seconds() + if elapsed_since_init >= self.threshold_sec: + self.state = self.STATE_OFF_DUTY_COUNTDOWN + self.state_start_time = current_time + self.alarm_sent = False + + elif self.state == self.STATE_ON_DUTY: + if roi_has_person: + self.last_person_seen_time = current_time + self.last_detection_time = current_time + + self.on_duty_window.append((current_time, True)) + while self.on_duty_window and (current_time - self.on_duty_window[0][0]).total_seconds() > self.confirm_sec: + self.on_duty_window.popleft() + else: + self.on_duty_window.append((current_time, False)) + while self.on_duty_window and (current_time - self.on_duty_window[0][0]).total_seconds() > self.confirm_sec: + self.on_duty_window.popleft() + + hit_ratio = sum(1 for t, detected in self.on_duty_window if detected) / max(len(self.on_duty_window), 1) + + if hit_ratio == 0: + self.state = self.STATE_OFF_DUTY_COUNTDOWN + self.state_start_time = current_time + self.alarm_sent = False elif self.state == self.STATE_OFF_DUTY_COUNTDOWN: elapsed = (current_time - self.state_start_time).total_seconds() if roi_has_person: self.state = self.STATE_ON_DUTY + self.state_start_time = current_time self.on_duty_window.clear() self.on_duty_window.append((current_time, True)) + self.last_person_seen_time = current_time self.alarm_sent = False elif elapsed >= self.threshold_sec: if not self.alarm_sent: - cooldown_key = f"{camera_id}" + cooldown_key = f"{roi_id}" if cooldown_key not in self.alert_cooldowns or ( current_time - self.alert_cooldowns[cooldown_key] ).total_seconds() > self.cooldown_seconds: - bbox = self.get_latest_bbox_in_roi(tracks, camera_id) + bbox = self.get_latest_bbox_in_roi(tracks, roi_id) elapsed_minutes = int(elapsed / 60) alerts.append({ - "track_id": camera_id, + "track_id": roi_id, "bbox": bbox, "off_duty_duration": elapsed, "alert_type": "leave_post", @@ -137,11 +171,13 @@ class LeavePostAlgorithm: return [] def reset(self): - self.state = self.STATE_ON_DUTY + self.state = self.STATE_INIT self.state_start_time = None self.on_duty_window.clear() self.alarm_sent = False self.last_person_seen_time = None + self.last_detection_time = None + self.init_start_time = None self.alert_cooldowns.clear() def get_state(self, track_id: str) -> Optional[Dict[str, Any]]: @@ -279,7 +315,7 @@ class AlgorithmManager: algo = self.algorithms.get(roi_id, {}).get(algorithm_type) if algo is None: return [] - return algo.process(camera_id, tracks, current_time) + return algo.process(roi_id, camera_id, tracks, current_time) def update_roi_params( self,