fix: 修复10个关键bug提升系统稳定性和性能
1. YOLO11输出解析错误: 移除不存在的objectness行,正确使用class_scores.max() 2. CPU NMS逻辑错误: keep_mask同时标记保留和抑制框导致NMS失效,改用独立suppressed集合 3. 坐标映射缺失: _build_tracks中scale_info未使用,添加revert_boxes还原到ROI裁剪空间 4. batch=1限制: 恢复真正的动态batch推理(1~8),BatchPreprocessor支持多图stack 5. 帧率控制缺失: _read_frame添加time.monotonic()间隔控制,按target_fps跳帧 6. 拉流推理耦合: 新增独立推理线程(InferenceWorker),生产者-消费者模式解耦 7. 攒批形同虚设: 添加50ms攒批窗口+max_batch阈值,替代>=1立即处理 8. LeavePost双重等待: LEAVING确认后直接触发告警,不再进入OFF_DUTY二次等待 9. register_algorithm每帧调用: 添加_registered_keys缓存,O(1)快速路径跳过 10. GPU context线程安全: TensorRT infer()内部加锁,防止多线程CUDA context竞争 附带修复: - reset_algorithm中未定义algorithm_type变量(NameError) - update_roi_params中循环变量key覆盖外层key - AlertInfo缺少bind_id字段(TypeError) - _logger.log_alert在标准logger上不存在(AttributeError) - AlarmStateMachine死锁(Lock改为RLock) - ROICropper.create_mask坐标解析错误 - 更新测试用例适配新API Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -161,16 +161,10 @@ class LeavePostAlgorithm:
|
||||
self.state = self.STATE_ON_DUTY
|
||||
self.state_start_time = current_time
|
||||
elif elapsed >= self.confirm_leave_sec:
|
||||
# 确认离岗后直接触发告警,不再进入 OFF_DUTY 二次等待
|
||||
self.state = self.STATE_OFF_DUTY
|
||||
self.state_start_time = current_time
|
||||
|
||||
elif self.state == self.STATE_OFF_DUTY:
|
||||
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
|
||||
elif elapsed >= self.confirm_leave_sec:
|
||||
cooldown_key = f"{camera_id}_{roi_id}"
|
||||
now = datetime.now()
|
||||
if cooldown_key not in self.alert_cooldowns or (now - self.alert_cooldowns[cooldown_key]).total_seconds() > self.cooldown_sec:
|
||||
@@ -186,6 +180,28 @@ class LeavePostAlgorithm:
|
||||
})
|
||||
self.alert_cooldowns[cooldown_key] = now
|
||||
|
||||
elif self.state == self.STATE_OFF_DUTY:
|
||||
# OFF_DUTY 状态:等待人员回岗或冷却后可再次告警
|
||||
if roi_has_person:
|
||||
self.state = self.STATE_ON_DUTY
|
||||
self.state_start_time = current_time
|
||||
else:
|
||||
elapsed = (current_time - self.state_start_time).total_seconds()
|
||||
cooldown_key = f"{camera_id}_{roi_id}"
|
||||
now = datetime.now()
|
||||
if cooldown_key in self.alert_cooldowns and (now - self.alert_cooldowns[cooldown_key]).total_seconds() > self.cooldown_sec:
|
||||
bbox = self._get_latest_bbox(tracks, roi_id)
|
||||
elapsed_minutes = int(elapsed / 60)
|
||||
alerts.append({
|
||||
"track_id": roi_id,
|
||||
"camera_id": camera_id,
|
||||
"bbox": bbox,
|
||||
"duration_minutes": elapsed_minutes,
|
||||
"alert_type": "leave_post",
|
||||
"message": f"持续离岗 {elapsed_minutes} 分钟",
|
||||
})
|
||||
self.alert_cooldowns[cooldown_key] = now
|
||||
|
||||
return alerts
|
||||
|
||||
def reset(self):
|
||||
@@ -373,6 +389,7 @@ class AlgorithmManager:
|
||||
self.algorithms: Dict[str, Dict[str, Any]] = {}
|
||||
self.working_hours = working_hours or []
|
||||
self._update_lock = threading.Lock()
|
||||
self._registered_keys: set = set() # 已注册的 (roi_id, bind_id, algo_type) 缓存
|
||||
|
||||
self.default_params = {
|
||||
"leave_post": {
|
||||
@@ -580,11 +597,14 @@ class AlgorithmManager:
|
||||
algorithm_type: str,
|
||||
params: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""注册算法(支持绑定ID)"""
|
||||
key = f"{roi_id}_{bind_id}"
|
||||
|
||||
if key in self.algorithms and algorithm_type in self.algorithms[key]:
|
||||
"""注册算法(支持绑定ID),使用缓存避免每帧重复查询"""
|
||||
cache_key = (roi_id, bind_id, algorithm_type)
|
||||
|
||||
# 快速路径:已注册直接返回
|
||||
if cache_key in self._registered_keys:
|
||||
return
|
||||
|
||||
key = f"{roi_id}_{bind_id}"
|
||||
|
||||
if roi_id not in self.algorithms:
|
||||
self.algorithms[roi_id] = {}
|
||||
@@ -618,6 +638,8 @@ class AlgorithmManager:
|
||||
cooldown_seconds=algo_params.get("cooldown_seconds", 300),
|
||||
target_class=algo_params.get("target_class", "person"),
|
||||
)
|
||||
|
||||
self._registered_keys.add(cache_key)
|
||||
|
||||
def process(
|
||||
self,
|
||||
@@ -646,24 +668,33 @@ class AlgorithmManager:
|
||||
key = f"{roi_id}_{bind_id}"
|
||||
if roi_id in self.algorithms and key in self.algorithms[roi_id] and algorithm_type in self.algorithms[roi_id][key]:
|
||||
algo = self.algorithms[roi_id][key][algorithm_type]
|
||||
for key, value in params.items():
|
||||
if hasattr(algo, key):
|
||||
setattr(algo, key, value)
|
||||
for param_key, value in params.items():
|
||||
if hasattr(algo, param_key):
|
||||
setattr(algo, param_key, value)
|
||||
|
||||
def reset_algorithm(self, roi_id: str, bind_id: Optional[str] = None):
|
||||
"""重置算法状态(支持绑定ID)"""
|
||||
if roi_id not in self.algorithms:
|
||||
return
|
||||
|
||||
|
||||
if bind_id:
|
||||
key = f"{roi_id}_{bind_id}"
|
||||
if key in self.algorithms[roi_id]:
|
||||
if algorithm_type in self.algorithms[roi_id][key]:
|
||||
self.algorithms[roi_id][key][algorithm_type].reset()
|
||||
for algo in self.algorithms[roi_id][key].values():
|
||||
algo.reset()
|
||||
# 清除注册缓存
|
||||
self._registered_keys = {
|
||||
k for k in self._registered_keys
|
||||
if not (k[0] == roi_id and k[1] == bind_id)
|
||||
}
|
||||
else:
|
||||
for key in self.algorithms[roi_id]:
|
||||
for algo in self.algorithms[roi_id][key].values():
|
||||
algo.reset()
|
||||
# 清除该 roi 的所有注册缓存
|
||||
self._registered_keys = {
|
||||
k for k in self._registered_keys if k[0] != roi_id
|
||||
}
|
||||
|
||||
def reset_all(self):
|
||||
"""重置所有算法"""
|
||||
|
||||
Reference in New Issue
Block a user