修复工作

This commit is contained in:
2025-10-01 22:19:45 +08:00
parent dcd905bfde
commit 20f0481f3a
3 changed files with 159 additions and 305 deletions

View File

@@ -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();
}
}
/**
* 在图像上绘制检测框