feat: 新增人员徘徊/静止行为分析功能
本次提交实现了完整的人员行为分析系统,包括: 1. 新增基于位置和跟踪ID的两种行为检测算法 2. 新增徘徊检测服务与行为处理器模块 3. 前后端集成算法配置界面与告警展示 4. 支持图片和视频流场景下的行为分析 5. 新增算法配置接口与文档说明 具体改动: - 新增loitering_detection模型目录与算法实现 - 新增AlgorithmConfig组件实现可视化配置 - 扩展图片/视频检测接口支持算法参数传递 - 新增行为告警推送与前端展示页面 - 优化检测服务,集成行为分析逻辑 - 移除冗余日志输出,完善代码注释
This commit is contained in:
@@ -95,6 +95,13 @@
|
||||
/>
|
||||
<div class="slider-value">{{ config.iou.toFixed(2) }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 算法配置(仅对人员检测模型显示) -->
|
||||
<AlgorithmConfig
|
||||
v-model="config.algorithmConfig"
|
||||
@change="onAlgorithmChange"
|
||||
:model-id="config.model"
|
||||
/>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
@@ -186,6 +193,40 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 行为告警 -->
|
||||
<el-card v-if="alerts && alerts.length > 0" class="alerts-card" shadow="hover">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<div class="header-left">
|
||||
<el-icon class="header-icon"><Warning /></el-icon>
|
||||
<span>行为告警</span>
|
||||
<el-tag size="small" type="danger" class="alert-count">{{ alerts.length }} 条</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="alerts-container">
|
||||
<div
|
||||
v-for="(alert, index) in alerts"
|
||||
:key="index"
|
||||
class="alert-item"
|
||||
>
|
||||
<div class="alert-header">
|
||||
<el-tag :type="alert.type === 'stationary' ? 'warning' : 'danger'" size="small">
|
||||
{{ alert.type === 'stationary' ? '静止' : '徘徊' }}
|
||||
</el-tag>
|
||||
<span class="alert-time">{{ new Date(alert.timestamp * 1000).toLocaleTimeString('zh-CN') }}</span>
|
||||
</div>
|
||||
<div class="alert-detail">
|
||||
<span class="alert-message">{{ alert.message }}</span>
|
||||
<span v-if="alert.duration" class="alert-duration">持续: {{ alert.duration.toFixed(1) }}s</span>
|
||||
</div>
|
||||
<div v-if="alert.bbox" class="alert-bbox">
|
||||
<code class="bbox-code">[{{ alert.bbox.join(', ') }}]</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 检测详情 -->
|
||||
<el-card v-if="detections.length > 0" class="details-card" shadow="hover">
|
||||
<template #header>
|
||||
@@ -273,6 +314,7 @@ import {
|
||||
Timer,
|
||||
Delete
|
||||
} from '@element-plus/icons-vue'
|
||||
import AlgorithmConfig from './AlgorithmConfig.vue'
|
||||
|
||||
const props = defineProps({
|
||||
models: {
|
||||
@@ -284,7 +326,8 @@ const props = defineProps({
|
||||
const config = ref({
|
||||
model: props.models.length > 0 ? props.models[0].id : 'fire_detection',
|
||||
confidence: 0.5,
|
||||
iou: 0.45
|
||||
iou: 0.45,
|
||||
algorithmConfig: {}
|
||||
})
|
||||
|
||||
// 可拖拽调整宽度相关
|
||||
@@ -321,6 +364,7 @@ const originalCameraFrame = ref('')
|
||||
const resultCameraFrame = ref('')
|
||||
const detections = ref([])
|
||||
const stats = ref(null)
|
||||
const alerts = ref([])
|
||||
const websocket = ref(null)
|
||||
|
||||
// 检测日志
|
||||
@@ -387,14 +431,21 @@ const startCamera = async () => {
|
||||
cameraConnected.value = true
|
||||
cameraStarting.value = false
|
||||
|
||||
websocket.value.send(JSON.stringify({
|
||||
const startConfig = {
|
||||
action: 'start',
|
||||
config: {
|
||||
model_id: config.value.model,
|
||||
confidence: config.value.confidence,
|
||||
iou: config.value.iou
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
// 添加算法配置
|
||||
if (config.value.algorithmConfig && Object.keys(config.value.algorithmConfig).length > 0) {
|
||||
startConfig.config.algorithm_config = config.value.algorithmConfig
|
||||
}
|
||||
|
||||
websocket.value.send(JSON.stringify(startConfig))
|
||||
}
|
||||
|
||||
websocket.value.onmessage = (event) => {
|
||||
@@ -450,14 +501,29 @@ const stopCamera = () => {
|
||||
|
||||
const updateCameraConfig = () => {
|
||||
if (websocket.value && cameraConnected.value) {
|
||||
websocket.value.send(JSON.stringify({
|
||||
const wsConfig = {
|
||||
action: 'update_config',
|
||||
config: {
|
||||
model_id: config.value.model,
|
||||
confidence: config.value.confidence,
|
||||
iou: config.value.iou
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
// 添加算法配置
|
||||
if (config.value.algorithmConfig && Object.keys(config.value.algorithmConfig).length > 0) {
|
||||
wsConfig.config.algorithm_config = config.value.algorithmConfig
|
||||
}
|
||||
|
||||
websocket.value.send(JSON.stringify(wsConfig))
|
||||
}
|
||||
}
|
||||
|
||||
const onAlgorithmChange = (algoConfig) => {
|
||||
config.value.algorithmConfig = algoConfig
|
||||
// 如果摄像头已连接,实时更新配置
|
||||
if (websocket.value && cameraConnected.value) {
|
||||
updateCameraConfig()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -847,6 +913,78 @@ onUnmounted(() => {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
/* 告警卡片 */
|
||||
.alerts-card {
|
||||
margin-bottom: 20px;
|
||||
border: 2px solid #f56c6c;
|
||||
}
|
||||
|
||||
.alerts-card .card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.alert-count {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.alerts-container {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.alert-item {
|
||||
background: #fef0f0;
|
||||
border-left: 4px solid #f56c6c;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.alert-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.alert-time {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.alert-detail {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.alert-message {
|
||||
font-size: 14px;
|
||||
color: #f56c6c;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.alert-duration {
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
background: #fff;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.alert-bbox {
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
background: #fff;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* 响应式布局 */
|
||||
@media (max-width: 768px) {
|
||||
.video-detection-container {
|
||||
|
||||
Reference in New Issue
Block a user