修复工作
This commit is contained in:
@@ -1,40 +1,56 @@
|
||||
package com.ruoyi.video.domain;
|
||||
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 告警记录实体类
|
||||
* 报警记录对象 v_alarm_record
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-09-27
|
||||
*/
|
||||
public class AlarmRecord {
|
||||
/** 告警ID */
|
||||
public class AlarmRecord extends BaseEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 报警记录ID */
|
||||
private Long alarmId;
|
||||
|
||||
/** 设备ID */
|
||||
private Long deviceId;
|
||||
|
||||
/** 告警类型 */
|
||||
private String alarmType;
|
||||
|
||||
/** 告警级别 */
|
||||
private String alarmLevel;
|
||||
|
||||
/** 告警内容 */
|
||||
private String alarmContent;
|
||||
|
||||
/** 巡检任务ID */
|
||||
private Long taskId;
|
||||
|
||||
/** 图像对象存储ID */
|
||||
private Long imageOssId;
|
||||
/** 任务名称 */
|
||||
private String taskName;
|
||||
|
||||
/** 帧位置 */
|
||||
private long framePosition;
|
||||
/** 设备ID */
|
||||
private Long deviceId;
|
||||
|
||||
/** 置信度 */
|
||||
private double confidence;
|
||||
/** 设备名称 */
|
||||
private String deviceName;
|
||||
|
||||
/** 处理状态(0-未处理,1-已处理) */
|
||||
private Integer status;
|
||||
/** 报警类型 */
|
||||
private String alarmType;
|
||||
|
||||
/** 报警级别(1=低,2=中,3=高) */
|
||||
private String alarmLevel;
|
||||
|
||||
/** 报警描述 */
|
||||
private String alarmDesc;
|
||||
|
||||
/** 检测置信度 */
|
||||
private BigDecimal confidence;
|
||||
|
||||
/** 报警图片路径 */
|
||||
private String imagePath;
|
||||
|
||||
/** 报警视频路径 */
|
||||
private String videoPath;
|
||||
|
||||
/** 报警时间 */
|
||||
private Date alarmTime;
|
||||
|
||||
/** 处理状态(0=未处理,1=已处理,2=已忽略) */
|
||||
private String handleStatus;
|
||||
|
||||
/** 处理人 */
|
||||
private String handleBy;
|
||||
@@ -44,154 +60,132 @@ public class AlarmRecord {
|
||||
|
||||
/** 处理备注 */
|
||||
private String handleRemark;
|
||||
|
||||
/** 创建时间 */
|
||||
private Date createTime;
|
||||
|
||||
/** 备注 */
|
||||
private String remark;
|
||||
|
||||
public Long getAlarmId() {
|
||||
return alarmId;
|
||||
}
|
||||
|
||||
public void setAlarmId(Long alarmId) {
|
||||
this.alarmId = alarmId;
|
||||
}
|
||||
|
||||
public Long getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(Long deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public String getAlarmType() {
|
||||
return alarmType;
|
||||
}
|
||||
|
||||
public void setAlarmType(String alarmType) {
|
||||
this.alarmType = alarmType;
|
||||
}
|
||||
|
||||
public String getAlarmContent() {
|
||||
return alarmContent;
|
||||
}
|
||||
|
||||
public void setAlarmContent(String alarmContent) {
|
||||
this.alarmContent = alarmContent;
|
||||
}
|
||||
|
||||
public Long getTaskId() {
|
||||
return taskId;
|
||||
public Long getAlarmId() {
|
||||
return alarmId;
|
||||
}
|
||||
|
||||
public void setTaskId(Long taskId) {
|
||||
this.taskId = taskId;
|
||||
}
|
||||
|
||||
public Long getImageOssId() {
|
||||
return imageOssId;
|
||||
public Long getTaskId() {
|
||||
return taskId;
|
||||
}
|
||||
|
||||
public void setImageOssId(Long imageOssId) {
|
||||
this.imageOssId = imageOssId;
|
||||
public void setTaskName(String taskName) {
|
||||
this.taskName = taskName;
|
||||
}
|
||||
|
||||
public long getFramePosition() {
|
||||
return framePosition;
|
||||
public String getTaskName() {
|
||||
return taskName;
|
||||
}
|
||||
|
||||
public void setFramePosition(long framePosition) {
|
||||
this.framePosition = framePosition;
|
||||
public void setDeviceId(Long deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public double getConfidence() {
|
||||
return confidence;
|
||||
public Long getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setConfidence(double confidence) {
|
||||
public void setDeviceName(String deviceName) {
|
||||
this.deviceName = deviceName;
|
||||
}
|
||||
|
||||
public String getDeviceName() {
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
public void setAlarmType(String alarmType) {
|
||||
this.alarmType = alarmType;
|
||||
}
|
||||
|
||||
public String getAlarmType() {
|
||||
return alarmType;
|
||||
}
|
||||
|
||||
public void setAlarmLevel(String alarmLevel) {
|
||||
this.alarmLevel = alarmLevel;
|
||||
}
|
||||
|
||||
public String getAlarmLevel() {
|
||||
return alarmLevel;
|
||||
}
|
||||
|
||||
public void setAlarmDesc(String alarmDesc) {
|
||||
this.alarmDesc = alarmDesc;
|
||||
}
|
||||
|
||||
public String getAlarmDesc() {
|
||||
return alarmDesc;
|
||||
}
|
||||
|
||||
public void setConfidence(BigDecimal confidence) {
|
||||
this.confidence = confidence;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
public BigDecimal getConfidence() {
|
||||
return confidence;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
public void setImagePath(String imagePath) {
|
||||
this.imagePath = imagePath;
|
||||
}
|
||||
|
||||
public String getHandleBy() {
|
||||
return handleBy;
|
||||
public String getImagePath() {
|
||||
return imagePath;
|
||||
}
|
||||
|
||||
public void setVideoPath(String videoPath) {
|
||||
this.videoPath = videoPath;
|
||||
}
|
||||
|
||||
public String getVideoPath() {
|
||||
return videoPath;
|
||||
}
|
||||
|
||||
public void setAlarmTime(Date alarmTime) {
|
||||
this.alarmTime = alarmTime;
|
||||
}
|
||||
|
||||
public Date getAlarmTime() {
|
||||
return alarmTime;
|
||||
}
|
||||
|
||||
public void setHandleStatus(String handleStatus) {
|
||||
this.handleStatus = handleStatus;
|
||||
}
|
||||
|
||||
public String getHandleStatus() {
|
||||
return handleStatus;
|
||||
}
|
||||
|
||||
public void setHandleBy(String handleBy) {
|
||||
this.handleBy = handleBy;
|
||||
}
|
||||
|
||||
public Date getHandleTime() {
|
||||
return handleTime;
|
||||
public String getHandleBy() {
|
||||
return handleBy;
|
||||
}
|
||||
|
||||
public void setHandleTime(Date handleTime) {
|
||||
this.handleTime = handleTime;
|
||||
}
|
||||
|
||||
public String getHandleRemark() {
|
||||
return handleRemark;
|
||||
public Date getHandleTime() {
|
||||
return handleTime;
|
||||
}
|
||||
|
||||
public void setHandleRemark(String handleRemark) {
|
||||
this.handleRemark = handleRemark;
|
||||
}
|
||||
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
|
||||
public void setRemark(String remark) {
|
||||
this.remark = remark;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取ID的兼容方法,保持与原有代码兼容
|
||||
*/
|
||||
public Long getId() {
|
||||
return alarmId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置ID的兼容方法,保持与原有代码兼容
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.alarmId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置告警级别
|
||||
*
|
||||
* @param alarmLevel 告警级别
|
||||
*/
|
||||
public void setAlarmLevel(String alarmLevel) {
|
||||
this.alarmLevel = alarmLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取告警级别
|
||||
*
|
||||
* @return 告警级别
|
||||
*/
|
||||
public String getAlarmLevel() {
|
||||
return alarmLevel;
|
||||
public String getHandleRemark() {
|
||||
return handleRemark;
|
||||
}
|
||||
}
|
||||
@@ -241,27 +241,23 @@ public class VideoAnalysisService {
|
||||
String bucketName = "alarm-images";
|
||||
|
||||
CustomMultipartFile multipartFile = new CustomMultipartFile(alarmImageFile, fileName, "image/jpeg");
|
||||
String objectUrl = minioService.putObject(bucketName, fileName, multipartFile.getInputStream());
|
||||
String imagePath = minioService.putObject(bucketName, fileName, multipartFile.getInputStream());
|
||||
|
||||
VMinioObject minioObject = new VMinioObject();
|
||||
minioObject.setBucketName(bucketName);
|
||||
minioObject.setObjectName(fileName);
|
||||
minioObject.setUrl(objectUrl);
|
||||
minioObject.setCreateBy("system");
|
||||
minioObject.setCreateTime(new Date());
|
||||
Long objectId = vMinioObjectService.insertVMinioObject(minioObject);
|
||||
|
||||
// 创建告警记录
|
||||
// 创建告警记录(严格按照DDL)
|
||||
AlarmRecord alarmRecord = new AlarmRecord();
|
||||
alarmRecord.setDeviceId(task.getDeviceId());
|
||||
alarmRecord.setAlarmType("detection");
|
||||
alarmRecord.setAlarmContent(detection.getLabel() + " - 置信度: " + String.format("%.2f", detection.getConfidence()));
|
||||
alarmRecord.setTaskId(task.getTaskId());
|
||||
alarmRecord.setImageOssId(objectId);
|
||||
alarmRecord.setFramePosition(frameCount);
|
||||
alarmRecord.setConfidence(detection.getConfidence());
|
||||
alarmRecord.setTaskName(task.getTaskName());
|
||||
alarmRecord.setDeviceId(task.getDeviceId());
|
||||
alarmRecord.setDeviceName(task.getDeviceName());
|
||||
alarmRecord.setAlarmType("detection");
|
||||
alarmRecord.setAlarmLevel("2"); // 2=中级
|
||||
alarmRecord.setAlarmDesc(detection.getLabel() + " - 置信度: " + String.format("%.2f", detection.getConfidence()));
|
||||
alarmRecord.setConfidence(java.math.BigDecimal.valueOf(detection.getConfidence()));
|
||||
alarmRecord.setImagePath(imagePath);
|
||||
alarmRecord.setAlarmTime(new Date());
|
||||
alarmRecord.setHandleStatus("0"); // 0=未处理
|
||||
alarmRecord.setCreateBy("system");
|
||||
alarmRecord.setCreateTime(new Date());
|
||||
alarmRecord.setStatus(0); // 未处理
|
||||
|
||||
alarmRecordMapper.insertAlarmRecord(alarmRecord);
|
||||
|
||||
@@ -293,89 +289,31 @@ public class VideoAnalysisService {
|
||||
minioObject.setCreateTime(new Date());
|
||||
Long objectId = vMinioObjectService.insertVMinioObject(minioObject);
|
||||
|
||||
// 更新任务的处理后视频ID
|
||||
task.setProcessedVideoOssId(objectId);
|
||||
task.setVideoStatus(2); // 2: 已分析
|
||||
taskMapper.updateInspectionTask(task);
|
||||
|
||||
// 更新记录的附件信息,添加处理后的视频URL
|
||||
String currentAccessory = record.getAccessory();
|
||||
record.setAccessory(currentAccessory + ";" + objectUrl);
|
||||
if (currentAccessory == null || currentAccessory.isEmpty()) {
|
||||
record.setAccessory(objectUrl);
|
||||
} else {
|
||||
record.setAccessory(currentAccessory + ";" + objectUrl);
|
||||
}
|
||||
inspectionTaskRecordMapper.updateInspectionTaskRecord(record);
|
||||
|
||||
log.info("处理后视频已上传: 任务ID={}, 记录ID={}, MinIO对象ID={}",
|
||||
task.getTaskId(), record.getRecordId(), objectId);
|
||||
log.info("处理后视频已上传: 任务ID={}, 记录ID={}, MinIO对象ID={}, URL={}",
|
||||
task.getTaskId(), record.getRecordId(), objectId, objectUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步分析视频
|
||||
* @param taskId 巡检任务ID
|
||||
*/
|
||||
@Async
|
||||
public void analyzeVideo(Long taskId) {
|
||||
log.info("开始异步分析视频: 任务ID={}", taskId);
|
||||
|
||||
try {
|
||||
// 1. 获取任务信息
|
||||
InspectionTask task = taskMapper.selectInspectionTaskById(taskId);
|
||||
if (task == null) {
|
||||
log.error("任务不存在: {}", taskId);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 获取原始视频信息
|
||||
Long videoOssId = task.getVideoOssId();
|
||||
if (videoOssId == null) {
|
||||
log.error("任务视频不存在: {}", taskId);
|
||||
return;
|
||||
}
|
||||
|
||||
VMinioObject videoObject = vMinioObjectService.selectVMinioObjectById(videoOssId);
|
||||
if (videoObject == null) {
|
||||
log.error("MinIO对象不存在: {}", videoOssId);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 下载原始视频到临时文件
|
||||
File videoTempFile = File.createTempFile("analysis_input_", ".mp4");
|
||||
try (InputStream inputStream = minioService.getObject(videoObject.getBucketName(), videoObject.getObjectName());
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(videoTempFile)) {
|
||||
byte[] buffer = new byte[8192];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
fileOutputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 创建输出视频文件
|
||||
File outputVideoFile = File.createTempFile("analysis_output_", ".mp4");
|
||||
|
||||
// 5. 创建检测器
|
||||
HttpYoloDetector detector = new HttpYoloDetector("garbage", PYTHON_API_URL, MODEL_NAME, 0x00FF00);
|
||||
|
||||
// 6. 处理视频
|
||||
processVideo(videoTempFile, outputVideoFile, detector, task);
|
||||
|
||||
// 7. 清理临时文件
|
||||
if (videoTempFile.exists()) {
|
||||
videoTempFile.delete();
|
||||
}
|
||||
|
||||
log.info("视频分析完成: 任务ID={}", taskId);
|
||||
} catch (Exception e) {
|
||||
log.error("视频分析失败: 任务ID={}, 错误={}", taskId, e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理视频
|
||||
* 处理视频记录
|
||||
* @param inputFile 输入视频文件
|
||||
* @param outputFile 输出视频文件
|
||||
* @param detector 检测器
|
||||
* @param task 巡检任务
|
||||
* @param record 巡检记录
|
||||
*/
|
||||
private void processVideo(File inputFile, File outputFile, HttpYoloDetector detector, InspectionTask task) throws Exception {
|
||||
private void processVideoForRecord(File inputFile, File outputFile, HttpYoloDetector detector,
|
||||
InspectionTask task, com.ruoyi.video.domain.InspectionTaskRecord record) throws Exception {
|
||||
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile);
|
||||
grabber.start();
|
||||
|
||||
@@ -386,10 +324,12 @@ public class VideoAnalysisService {
|
||||
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
|
||||
recorder.setFrameRate(grabber.getFrameRate());
|
||||
recorder.setVideoBitrate(grabber.getVideoBitrate());
|
||||
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
|
||||
recorder.setAudioBitrate(grabber.getAudioBitrate());
|
||||
recorder.setAudioChannels(grabber.getAudioChannels());
|
||||
recorder.setSampleRate(grabber.getSampleRate());
|
||||
if (grabber.getAudioChannels() > 0) {
|
||||
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
|
||||
recorder.setAudioBitrate(grabber.getAudioBitrate());
|
||||
recorder.setAudioChannels(grabber.getAudioChannels());
|
||||
recorder.setSampleRate(grabber.getSampleRate());
|
||||
}
|
||||
recorder.start();
|
||||
|
||||
OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();
|
||||
@@ -397,7 +337,7 @@ public class VideoAnalysisService {
|
||||
// 用于去重的垃圾检测结果缓存
|
||||
Map<String, Long> detectedGarbageCache = new HashMap<>();
|
||||
// 跟踪检测到的垃圾ID
|
||||
final Long[] detectionId = {1L}; // 使用数组实现effectively final
|
||||
final Long[] detectionId = {1L};
|
||||
// 帧计数
|
||||
long frameCount = 0;
|
||||
|
||||
@@ -425,8 +365,8 @@ public class VideoAnalysisService {
|
||||
// 这是新检测到的垃圾
|
||||
detectedGarbageCache.put(detectionKey, detectionId[0]++);
|
||||
|
||||
// 创建告警记录
|
||||
createAlarmRecord(task, detection, mat, frameCount);
|
||||
// 创建告警记录(关联到记录)
|
||||
createAlarmRecordForRecord(task, record, detection, mat, frameCount);
|
||||
} else {
|
||||
// 更新上次检测时间
|
||||
detectedGarbageCache.put(detectionKey, detectionId[0]++);
|
||||
@@ -458,40 +398,11 @@ public class VideoAnalysisService {
|
||||
grabber.stop();
|
||||
grabber.close();
|
||||
|
||||
// 上传处理后的视频
|
||||
uploadProcessedVideo(outputFile, task);
|
||||
// 上传处理后的视频(更新记录)
|
||||
uploadProcessedVideoForRecord(outputFile, task, record);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传处理后的视频到MinIO
|
||||
*/
|
||||
private void uploadProcessedVideo(File videoFile, InspectionTask task) throws Exception {
|
||||
String fileName = "processed_" + System.currentTimeMillis() + ".mp4";
|
||||
String bucketName = "inspection-videos";
|
||||
|
||||
CustomMultipartFile multipartFile = new CustomMultipartFile(videoFile, fileName, "video/mp4");
|
||||
String objectUrl = minioService.putObject(bucketName, fileName, multipartFile.getInputStream());
|
||||
|
||||
VMinioObject minioObject = new VMinioObject();
|
||||
minioObject.setBucketName(bucketName);
|
||||
minioObject.setObjectName(fileName);
|
||||
minioObject.setUrl(objectUrl);
|
||||
minioObject.setCreateBy("system");
|
||||
minioObject.setCreateTime(new Date());
|
||||
Long objectId = vMinioObjectService.insertVMinioObject(minioObject);
|
||||
|
||||
// 更新任务的处理后视频ID
|
||||
task.setProcessedVideoOssId(objectId);
|
||||
task.setVideoStatus(2); // 2: 已分析
|
||||
taskMapper.updateInspectionTask(task);
|
||||
|
||||
log.info("处理后视频已上传: 任务ID={}, MinIO对象ID={}", task.getTaskId(), objectId);
|
||||
|
||||
// 删除临时文件
|
||||
if (videoFile.exists()) {
|
||||
videoFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成检测结果的唯一键,用于检测结果去重
|
||||
@@ -507,59 +418,7 @@ public class VideoAnalysisService {
|
||||
return String.format("%s_%d_%d_%d_%d", detection.getLabel(), x, y, w, h);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建告警记录
|
||||
*/
|
||||
private void createAlarmRecord(InspectionTask task, Detection detection, Mat frame, long frameCount) throws Exception {
|
||||
// 创建告警图像临时文件
|
||||
File alarmImageFile = File.createTempFile("alarm_", ".jpg");
|
||||
|
||||
// 裁剪检测区域,略微扩大区域
|
||||
Rect rect = detection.getRect();
|
||||
int x = Math.max(0, rect.x() - 10);
|
||||
int y = Math.max(0, rect.y() - 10);
|
||||
int w = Math.min(frame.cols() - x, rect.width() + 20);
|
||||
int h = Math.min(frame.rows() - y, rect.height() + 20);
|
||||
|
||||
// 使用OpenCV保存告警图片
|
||||
Mat roi = new Mat(frame, new Rect(x, y, w, h));
|
||||
org.bytedeco.opencv.global.opencv_imgcodecs.imwrite(alarmImageFile.getAbsolutePath(), roi);
|
||||
|
||||
// 上传告警图片到MinIO
|
||||
String fileName = "alarm_" + System.currentTimeMillis() + ".jpg";
|
||||
String bucketName = "alarm-images";
|
||||
|
||||
CustomMultipartFile multipartFile = new CustomMultipartFile(alarmImageFile, fileName, "image/jpeg");
|
||||
String objectUrl = minioService.putObject(bucketName, fileName, multipartFile.getInputStream());
|
||||
|
||||
VMinioObject minioObject = new VMinioObject();
|
||||
minioObject.setBucketName(bucketName);
|
||||
minioObject.setObjectName(fileName);
|
||||
minioObject.setUrl(objectUrl);
|
||||
minioObject.setCreateBy("system");
|
||||
minioObject.setCreateTime(new Date());
|
||||
Long objectId = vMinioObjectService.insertVMinioObject(minioObject);
|
||||
|
||||
// 创建告警记录
|
||||
AlarmRecord alarmRecord = new AlarmRecord();
|
||||
alarmRecord.setDeviceId(task.getDeviceId());
|
||||
alarmRecord.setAlarmType("garbage");
|
||||
alarmRecord.setAlarmContent(detection.getLabel() + " - 置信度: " + String.format("%.2f", detection.getConfidence()));
|
||||
alarmRecord.setTaskId(task.getTaskId());
|
||||
alarmRecord.setImageOssId(objectId);
|
||||
alarmRecord.setFramePosition(frameCount);
|
||||
alarmRecord.setConfidence(detection.getConfidence());
|
||||
alarmRecord.setCreateTime(new Date());
|
||||
|
||||
alarmRecordMapper.insertAlarmRecord(alarmRecord);
|
||||
|
||||
log.info("创建告警记录: 类型={}, 任务ID={}, 告警ID={}", detection.getLabel(), task.getTaskId(), alarmRecord.getAlarmId());
|
||||
|
||||
// 删除临时文件
|
||||
if (alarmImageFile.exists()) {
|
||||
alarmImageFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 在图像上绘制检测框
|
||||
|
||||
Reference in New Issue
Block a user