Files
rtsp-video-analysis-system/INSPECTION-WORKFLOW.md
2025-09-30 14:23:33 +08:00

544 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 巡检任务工作流程说明
## 📋 功能概述
本文档说明巡检任务的完整执行流程包括视频录制、保存、AI识别和告警创建。
## 🔄 完整工作流程
### 1. 任务启动
当巡检任务启动时:
```
InspectionTaskServiceImpl.executeInspectionTask(taskId)
├── 创建 InspectionTaskRecord记录ID
├── 更新任务状态为"执行中"
└── 调用 performVideoAnalysisWithRecord()
```
### 2. 视频录制和保存
```
performVideoAnalysisWithRecord()
├── 从RTSP流抓取视频
├── 录制指定时长的视频
├── 保存为临时文件
├── 上传视频到MinIO
├── 更新InspectionTaskRecord.accessory视频URL
└── 调用Python服务进行分析
```
### 3. AI识别处理
```
VideoAnalysisService.analyzeVideoWithRecord()
├── 创建HttpYoloDetector连接Python服务
├── 逐帧分析视频
├── 每10帧调用一次Python API检测
├── 绘制检测框
├── 去重检测结果(避免重复告警)
├── 创建告警记录
├── 上传处理后的视频
├── 生成检测结果摘要
└── 更新InspectionTaskRecord.result识别结果
```
### 4. 告警创建(去重)
```
createAlarmRecordForRecord()
├── 提取检测区域图像
├── 上传告警图片到MinIO
├── 创建AlarmRecord
│ ├── 设备ID
│ ├── 告警类型
│ ├── 告警内容(检测类别+置信度)
│ ├── 关联的任务ID
│ ├── 图片URL
│ └── 帧位置
└── 保存到数据库(仅新检测的对象)
```
## 📊 数据表关系
```
InspectionTask (巡检任务)
↓ 1:N
InspectionTaskRecord (巡检记录)
├── accessory: 原始视频URL + 处理后视频URL
├── result: AI识别结果摘要
├── duration: 执行时长
└── status: 0=成功, 1=失败, 2=部分成功
InspectionTaskRecord → AlarmRecord (1:N)
├── 同一个record可以有多个告警
└── 告警自动去重(相同位置的相同对象只记录一次)
```
## 🎯 关键字段说明
### InspectionTaskRecord
| 字段 | 说明 | 示例 |
|------|------|------|
| recordId | 记录ID | 自增主键 |
| taskId | 关联的任务ID | 1001 |
| executeTime | 执行时间 | 2025-09-30 14:30:00 |
| duration | 执行时长(秒) | 30 |
| accessory | 附件URL | video1.mp4;video2.mp4 |
| result | 识别结果 | 共检测到3个问题详情垃圾(2) 烟雾(1) |
| status | 执行状态 | 0=成功, 1=失败, 2=部分成功 |
### AlarmRecord
| 字段 | 说明 | 示例 |
|------|------|------|
| alarmId | 告警ID | 自增主键 |
| deviceId | 设备ID | 1001 |
| taskId | 任务ID | 1001 |
| alarmType | 告警类型 | detection |
| alarmContent | 告警内容 | 垃圾 - 置信度: 0.95 |
| imageOssId | 告警图片ID | MinIO对象ID |
| framePosition | 视频帧位置 | 150 |
| confidence | 置信度 | 0.95 |
| status | 处理状态 | 0=未处理, 1=已处理 |
## 🔧 关键实现细节
### 1. 去重机制
使用`generateDetectionKey`生成唯一键:
```java
private String generateDetectionKey(Detection detection) {
Rect rect = detection.getRect();
// 取10的倍数允许小范围波动
int x = rect.x() / 10 * 10;
int y = rect.y() / 10 * 10;
int w = rect.width() / 10 * 10;
int h = rect.height() / 10 * 10;
return String.format("%s_%d_%d_%d_%d", detection.getLabel(), x, y, w, h);
}
```
**原理**
- 相同类别 + 相似位置 → 认为是同一个对象
- 允许10像素的波动
- 超过60秒未检测到自动清除
### 2. Python服务调用
使用容器名调用:
```java
private static final String PYTHON_API_URL = "http://rtsp-python-service:8000/api/detect/file";
private static final String MODEL_NAME = "yolov8_detector";
```
### 3. 视频处理流程
```
RTSP流 → FFmpegFrameGrabber → 录制 → 临时文件
→ 上传MinIO → 保存URL到record.accessory
→ 逐帧分析 → 调用Python API → 绘制检测框
→ 保存处理后视频 → 追加URL到record.accessory
→ 更新record.result
```
### 4. 附件字段格式
`accessory`字段使用分号分隔多个URL
```
原始视频URL;处理后视频URL
```
示例:
```
http://minio.com/inspection-videos/inspection_1001_1234567890.mp4;http://minio.com/inspection-videos/processed_1234567891.mp4
```
## 🚀 使用方法
### 1. 创建巡检任务
```java
InspectionTask task = new InspectionTask();
task.setDeviceId(deviceId);
task.setDuration(30); // 录制30秒
task.setStatus(0); // 待执行
inspectionTaskService.insertInspectionTask(task);
```
### 2. 启动任务
```java
// 异步执行
inspectionTaskService.executeInspectionTask(taskId);
```
### 3. 查看执行记录
```sql
-- 查询某任务的所有执行记录
SELECT * FROM v_inspection_task_record WHERE task_id = 1001 ORDER BY execute_time DESC;
-- 查询成功的记录
SELECT * FROM v_inspection_task_record WHERE status = 0;
-- 查询某记录的所有告警
SELECT * FROM v_alarm_record WHERE task_id = 1001;
```
### 4. 查看告警
```sql
-- 查询某任务的所有告警
SELECT * FROM v_alarm_record WHERE task_id = 1001 ORDER BY create_time DESC;
-- 查询未处理的告警
SELECT * FROM v_alarm_record WHERE status = 0;
```
## 📝 执行示例
### 执行流程
1. **任务创建**
```
Task ID: 1001
Device ID: 5001
Duration: 30秒
```
2. **记录创建**
```
Record ID: 2001
Task ID: 1001
Execute Time: 2025-09-30 14:30:00
Status: 1 (执行中)
```
3. **视频录制**
```
录制30秒视频
保存到MinIO: inspection_1001_1234567890.mp4
更新Record.accessory: http://minio.com/.../inspection_1001_1234567890.mp4
```
4. **AI识别**
```
调用Python服务
检测到: 垃圾(2个), 烟雾(1个)
```
5. **告警创建**(去重)
```
Alarm 1: 垃圾 - 位置(100,200) - 置信度0.95
Alarm 2: 垃圾 - 位置(300,400) - 置信度0.87
Alarm 3: 烟雾 - 位置(500,100) - 置信度0.92
```
6. **处理后视频**
```
带检测框的视频上传
保存到MinIO: processed_1234567891.mp4
更新Record.accessory: 原始URL;处理后URL
```
7. **更新记录**
```
Record.result: "共检测到 3 个问题,详情:垃圾(2) 烟雾(1)"
Record.status: 0 (成功)
Record.duration: 32秒
```
## ⚙️ 配置说明
### Python服务配置
在Docker环境中Python服务地址为
```
http://rtsp-python-service:8000
```
### 模型配置
确保Python服务使用正确的模型名称
```json
{
"name": "yolov8_detector",
"path": "models/yolov8_model.py",
"size": [640, 640]
}
```
### 检测参数
在`VideoAnalysisService`中可调整:
```java
// 检测频率每N帧检测一次
if (frameCount % 10 == 0) { ... }
// 去重时间窗口(秒)
detectedGarbageCache.entrySet().removeIf(entry ->
(currentId - entry.getValue()) > grabber.getFrameRate() * 60);
```
## 🐛 故障排查
### 问题1: 视频未保存
**检查**
```sql
-- 查看record的accessory字段
SELECT record_id, accessory FROM v_inspection_task_record WHERE task_id = ?;
-- 查看MinIO对象
SELECT * FROM v_minio_object WHERE bucket_name = 'inspection-videos' ORDER BY create_time DESC;
```
**解决**
- 检查MinIO服务是否可用
- 检查网络连接
- 查看后端日志
### 问题2: Python识别未执行
**检查**
```bash
# 查看Python服务日志
docker-compose logs python-service
# 测试Python服务
curl http://rtsp-python-service:8000/health
curl http://rtsp-python-service:8000/api/models
```
**解决**
- 确认Python服务运行正常
- 确认模型文件存在
- 检查网络连通性
### 问题3: 告警未创建
**检查**
```sql
-- 查看告警记录
SELECT * FROM v_alarm_record WHERE task_id = ? ORDER BY create_time DESC;
-- 查看检测结果
SELECT result FROM v_inspection_task_record WHERE record_id = ?;
```
**解决**
- 检查检测置信度阈值
- 查看视频内容是否有检测对象
- 检查Python服务返回结果
### 问题4: 重复告警
**检查**
- 去重机制是否正常工作
- `generateDetectionKey`逻辑是否合理
**调整**
```java
// 调整去重的位置容差
int x = rect.x() / 20 * 20; // 从10改为20更宽松的去重
```
## 📊 性能优化
### 1. 检测频率
```java
// 降低检测频率以提升性能CPU模式
if (frameCount % 30 == 0) { // 从10改为30
// 每30帧检测一次
}
```
### 2. 视频质量
```java
// 降低视频比特率节省存储
recorder.setVideoBitrate(500000); // 降低比特率
```
### 3. 去重时间窗口
```java
// 缩短去重时间窗口
(currentId - entry.getValue()) > grabber.getFrameRate() * 30 // 从60秒改为30秒
```
## 🔍 调试方法
### 查看执行日志
```bash
# 查看后端日志
docker-compose logs -f backend | grep "inspection"
# 查看Python服务日志
docker-compose logs -f python-service
# 查看特定记录的处理过程
docker-compose logs backend | grep "recordId=2001"
```
### 数据库查询
```sql
-- 查看最新的执行记录
SELECT
r.record_id,
r.task_id,
r.execute_time,
r.duration,
r.status,
r.result,
LENGTH(r.accessory) as accessory_length
FROM v_inspection_task_record r
ORDER BY r.create_time DESC
LIMIT 10;
-- 查看记录对应的告警
SELECT
a.alarm_id,
a.alarm_content,
a.confidence,
a.frame_position,
a.create_time
FROM v_alarm_record a
WHERE a.task_id = ?
ORDER BY a.create_time DESC;
-- 统计告警数量
SELECT
r.record_id,
r.execute_time,
COUNT(a.alarm_id) as alarm_count
FROM v_inspection_task_record r
LEFT JOIN v_alarm_record a ON r.task_id = a.task_id
AND a.create_time >= r.execute_time
AND a.create_time <= DATE_ADD(r.execute_time, INTERVAL r.duration SECOND)
GROUP BY r.record_id
ORDER BY r.create_time DESC;
```
## 💡 扩展建议
### 1. 添加检测类型过滤
在`createAlarmRecordForRecord`中:
```java
// 只对特定类型创建告警
List<String> alarmTypes = Arrays.asList("垃圾", "烟雾", "火焰");
if (!alarmTypes.contains(detection.getLabel())) {
return; // 忽略其他类型
}
```
### 2. 添加置信度阈值
```java
// 只对高置信度的检测创建告警
if (detection.getConfidence() < 0.7) {
return; // 忽略低置信度检测
}
```
### 3. 添加区域过滤
```java
// 只对特定区域的检测创建告警
Rect rect = detection.getRect();
if (!isInMonitorArea(rect, task)) {
return; // 忽略监控区域外的检测
}
```
### 4. 添加告警级别
```java
// 根据检测类型设置告警级别
String alarmLevel = "medium";
if (detection.getLabel().contains("火焰")) {
alarmLevel = "high";
} else if (detection.getLabel().contains("垃圾")) {
alarmLevel = "low";
}
alarmRecord.setAlarmLevel(alarmLevel);
```
## 🔒 安全考虑
### 1. 异常处理
所有方法都包含完整的异常处理:
- 视频录制失败 → 更新record状态为失败
- Python服务调用失败 → 记录错误但不影响整体流程
- MinIO上传失败 → 记录错误并回滚
### 2. 资源清理
使用try-finally确保资源释放
- FFmpegFrameGrabber自动关闭
- FFmpegFrameRecorder自动关闭
- 临时文件自动删除
### 3. 并发控制
使用`@Async`异步执行,避免阻塞:
- 任务执行不阻塞API响应
- 多个任务可并发执行
- 通过runningTasks避免重复执行
## 📈 监控指标
### 建议监控的指标
1. **执行成功率**
```sql
SELECT
COUNT(CASE WHEN status = 0 THEN 1 END) * 100.0 / COUNT(*) as success_rate
FROM v_inspection_task_record
WHERE execute_time >= DATE_SUB(NOW(), INTERVAL 1 DAY);
```
2. **平均执行时长**
```sql
SELECT AVG(duration) as avg_duration
FROM v_inspection_task_record
WHERE status = 0 AND execute_time >= DATE_SUB(NOW(), INTERVAL 1 DAY);
```
3. **告警统计**
```sql
SELECT
alarm_type,
COUNT(*) as count
FROM v_alarm_record
WHERE create_time >= DATE_SUB(NOW(), INTERVAL 1 DAY)
GROUP BY alarm_type;
```
## 📞 技术支持
如有问题,请查看:
1. 后端日志:`docker-compose logs backend`
2. Python服务日志`docker-compose logs python-service`
3. 数据库记录:查询`v_inspection_task_record`和`v_alarm_record`表
4. MinIO对象查询`v_minio_object`表
---
**文档版本**: 1.0
**最后更新**: 2025-09-30
**适用版本**: YOLOv8, Docker Compose部署