feat: 新增人员徘徊/静止行为分析功能
本次提交实现了完整的人员行为分析系统,包括: 1. 新增基于位置和跟踪ID的两种行为检测算法 2. 新增徘徊检测服务与行为处理器模块 3. 前后端集成算法配置界面与告警展示 4. 支持图片和视频流场景下的行为分析 5. 新增算法配置接口与文档说明 具体改动: - 新增loitering_detection模型目录与算法实现 - 新增AlgorithmConfig组件实现可视化配置 - 扩展图片/视频检测接口支持算法参数传递 - 新增行为告警推送与前端展示页面 - 优化检测服务,集成行为分析逻辑 - 移除冗余日志输出,完善代码注释
This commit is contained in:
163
models/README.md
163
models/README.md
@@ -38,6 +38,169 @@ cp /path/to/behavior_detection/Loitering-Detection/yolov8n.pt models/loitering_d
|
||||
bash scripts/setup-models.sh
|
||||
```
|
||||
|
||||
## 算法目录规范
|
||||
|
||||
当需要在检测模型基础上添加自定义算法逻辑时,请在对应模型目录下创建以下子目录:
|
||||
|
||||
### `algorithms/` - 独立算法模块
|
||||
|
||||
用于存放独立的算法实现,如密度估计、流动分析、行为识别等。
|
||||
|
||||
```
|
||||
crowd_detection/
|
||||
├── yolov8l.pt
|
||||
└── algorithms/
|
||||
├── __init__.py
|
||||
├── density_estimator.py # 人群密度估计算法
|
||||
├── flow_analysis.py # 人群流动分析算法
|
||||
├── anomaly_detector.py # 异常行为检测算法
|
||||
└── crowd_counting.py # 人群计数算法
|
||||
```
|
||||
|
||||
**示例代码:**
|
||||
```python
|
||||
# crowd_detection/algorithms/density_estimator.py
|
||||
import numpy as np
|
||||
|
||||
class DensityEstimator:
|
||||
"""人群密度估计器"""
|
||||
|
||||
def __init__(self, grid_size=10):
|
||||
self.grid_size = grid_size
|
||||
|
||||
def estimate(self, detections, image_shape):
|
||||
"""
|
||||
根据检测结果估计人群密度
|
||||
|
||||
Args:
|
||||
detections: YOLO检测结果 [(x1,y1,x2,y2,conf,cls), ...]
|
||||
image_shape: (height, width)
|
||||
|
||||
Returns:
|
||||
density_map: 密度热力图
|
||||
"""
|
||||
h, w = image_shape
|
||||
grid_h, grid_w = h // self.grid_size, w // self.grid_size
|
||||
density_map = np.zeros((grid_h, grid_w))
|
||||
|
||||
for det in detections:
|
||||
cx, cy = int((det[0] + det[2]) / 2), int((det[1] + det[3]) / 2)
|
||||
grid_x, grid_y = cx // self.grid_size, cy // self.grid_size
|
||||
if 0 <= grid_x < grid_w and 0 <= grid_y < grid_h:
|
||||
density_map[grid_y, grid_x] += 1
|
||||
|
||||
return density_map
|
||||
|
||||
def is_crowded(self, density_map, threshold=5):
|
||||
"""判断是否拥挤"""
|
||||
return np.max(density_map) > threshold
|
||||
```
|
||||
|
||||
### `processors/` - 检测结果二次处理
|
||||
|
||||
用于对模型检测结果进行后处理,如过滤、分析、告警判断等。
|
||||
|
||||
```
|
||||
crowd_detection/
|
||||
├── yolov8l.pt
|
||||
└── processors/
|
||||
├── __init__.py
|
||||
├── post_processor.py # 检测结果后处理
|
||||
├── crowd_analyzer.py # 人群分析器
|
||||
└── alert_rules.py # 告警规则判断
|
||||
```
|
||||
|
||||
**示例代码:**
|
||||
```python
|
||||
# crowd_detection/processors/alert_rules.py
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
class CrowdAlertRules:
|
||||
"""人群检测告警规则"""
|
||||
|
||||
def __init__(self):
|
||||
self.alert_history = []
|
||||
self.cooldown_minutes = 5
|
||||
|
||||
def check_crowd_gathering(self, person_count, density, duration_seconds):
|
||||
"""
|
||||
检查是否触发人群聚集告警
|
||||
|
||||
Args:
|
||||
person_count: 检测到的人数
|
||||
density: 人群密度值
|
||||
duration_seconds: 持续时长
|
||||
|
||||
Returns:
|
||||
alert: 告警信息或None
|
||||
"""
|
||||
# 规则:人数>20 且 密度>0.5 且 持续>30秒
|
||||
if person_count > 20 and density > 0.5 and duration_seconds > 30:
|
||||
if self._can_trigger_alert("crowd_gathering"):
|
||||
alert = {
|
||||
"type": "crowd_gathering",
|
||||
"level": "high" if person_count > 50 else "medium",
|
||||
"message": f"检测到人群聚集,人数: {person_count}",
|
||||
"timestamp": datetime.now()
|
||||
}
|
||||
self._record_alert("crowd_gathering")
|
||||
return alert
|
||||
return None
|
||||
|
||||
def check_intrusion(self, detections, restricted_zones):
|
||||
"""
|
||||
检查是否触发区域入侵告警
|
||||
|
||||
Args:
|
||||
detections: 检测结果
|
||||
restricted_zones: 限制区域列表 [(x1,y1,x2,y2), ...]
|
||||
"""
|
||||
alerts = []
|
||||
for det in detections:
|
||||
person_box = (det[0], det[1], det[2], det[3])
|
||||
for zone in restricted_zones:
|
||||
if self._is_intersect(person_box, zone):
|
||||
alerts.append({
|
||||
"type": "zone_intrusion",
|
||||
"level": "high",
|
||||
"message": "检测到人员进入限制区域"
|
||||
})
|
||||
return alerts
|
||||
|
||||
def _can_trigger_alert(self, alert_type):
|
||||
"""检查是否可以通过冷却期触发告警"""
|
||||
cutoff_time = datetime.now() - timedelta(minutes=self.cooldown_minutes)
|
||||
recent_alerts = [
|
||||
a for a in self.alert_history
|
||||
if a["type"] == alert_type and a["timestamp"] > cutoff_time
|
||||
]
|
||||
return len(recent_alerts) == 0
|
||||
|
||||
def _record_alert(self, alert_type):
|
||||
"""记录告警历史"""
|
||||
self.alert_history.append({
|
||||
"type": alert_type,
|
||||
"timestamp": datetime.now()
|
||||
})
|
||||
|
||||
@staticmethod
|
||||
def _is_intersect(box1, box2):
|
||||
"""判断两个框是否相交"""
|
||||
x1 = max(box1[0], box2[0])
|
||||
y1 = max(box1[1], box2[1])
|
||||
x2 = min(box1[2], box2[2])
|
||||
y2 = min(box1[3], box2[3])
|
||||
return x1 < x2 and y1 < y2
|
||||
```
|
||||
|
||||
### 目录选择建议
|
||||
|
||||
| 场景 | 推荐目录 | 说明 |
|
||||
|------|----------|------|
|
||||
| 实现新的检测算法(如密度估计、行为识别) | `algorithms/` | 独立的算法逻辑,可复用 |
|
||||
| 对检测结果进行过滤、分析 | `processors/` | 针对业务场景的后处理 |
|
||||
| 简单的工具函数 | `utils/` | 辅助函数,无状态逻辑 |
|
||||
|
||||
## 注意
|
||||
|
||||
模型文件较大,未包含在 Git 仓库中。请从原始位置复制或创建符号链接。
|
||||
|
||||
Reference in New Issue
Block a user