无人机大图合并优化

This commit is contained in:
lcj
2025-11-24 19:32:15 +08:00
parent 04430d8853
commit c0fef2521f
7 changed files with 146 additions and 9 deletions

View File

@ -336,8 +336,8 @@ ys7:
app-key: 3acf9f1a43dc4209841e0893003db0a2 app-key: 3acf9f1a43dc4209841e0893003db0a2
app-secret: 09e29c70ae1161fbc3ce2030fc09ba2e app-secret: 09e29c70ae1161fbc3ce2030fc09ba2e
job: job:
capture-enabled: true # 控制是否启用萤石抓拍任务 capture-enabled: false # 控制是否启用萤石抓拍任务
device-sync-enabled: true # 控制是否同步萤石设备 device-sync-enabled: false # 控制是否同步萤石设备
# 斯巴达算法 # 斯巴达算法
sparta: sparta:
url: http://119.3.204.120:8040 url: http://119.3.204.120:8040

View File

@ -76,9 +76,9 @@ spring:
servlet: servlet:
multipart: multipart:
# 单个文件大小 # 单个文件大小
max-file-size: 200MB max-file-size: 1024MB
# 设置总上传的文件大小 # 设置总上传的文件大小
max-request-size: 200MB max-request-size: 1024MB
mvc: mvc:
# 设置静态资源路径 防止所有请求都去查静态资源 # 设置静态资源路径 防止所有请求都去查静态资源
static-path-pattern: /static/** static-path-pattern: /static/**

View File

@ -7,10 +7,12 @@ import lombok.Data;
import org.dromara.common.translation.annotation.Translation; import org.dromara.common.translation.annotation.Translation;
import org.dromara.common.translation.constant.TransConstant; import org.dromara.common.translation.constant.TransConstant;
import org.dromara.drone.domain.DroDroneBigPicture; import org.dromara.drone.domain.DroDroneBigPicture;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailRecognizerVo;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List;
/** /**
@ -91,6 +93,11 @@ public class DroDroneBigPictureVo implements Serializable {
*/ */
private String recognizeResult; private String recognizeResult;
/**
* 识别结果列表
*/
private String recognizeResultStr;
/** /**
* tif文件 * tif文件
*/ */

View File

@ -100,6 +100,15 @@ public interface IDroDroneBigPictureService extends IService<DroDroneBigPicture>
*/ */
Boolean compressPicture(String ossIds, List<Long> compressPicIds); Boolean compressPicture(String ossIds, List<Long> compressPicIds);
/**
* 异步合成大图
*
* @param businessName 业务名称
* @param imageUrls 图片URL列表
* @return 任务id
*/
CompletableFuture<String> asyncAddBigPicture(String businessName, List<String> imageUrls);
/** /**
* 异步添加压缩图片 * 异步添加压缩图片
* *

View File

@ -2,6 +2,7 @@ package org.dromara.drone.service.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -27,7 +28,9 @@ import org.dromara.drone.service.IDroDroneBigPictureService;
import org.dromara.manager.dronemanager.DroneManager; import org.dromara.manager.dronemanager.DroneManager;
import org.dromara.manager.dronemanager.vo.DroneImgMergeProgressVo; import org.dromara.manager.dronemanager.vo.DroneImgMergeProgressVo;
import org.dromara.manager.dronemanager.vo.DroneImgMergeUrlVo; import org.dromara.manager.dronemanager.vo.DroneImgMergeUrlVo;
import org.dromara.manager.recognizermanager.enums.RecognizerTypeEnum;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailAINumberReq; import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailAINumberReq;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailRecognizerVo;
import org.dromara.progress.service.IPgsProgressPlanDetailService; import org.dromara.progress.service.IPgsProgressPlanDetailService;
import org.dromara.system.domain.vo.SysOssVo; import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.service.ISysOssService; import org.dromara.system.service.ISysOssService;
@ -90,11 +93,34 @@ public class DroDroneBigPictureServiceImpl extends ServiceImpl<DroDroneBigPictur
BigDecimal p = progressVo.getProgress() BigDecimal p = progressVo.getProgress()
.multiply(new BigDecimal("100")); .multiply(new BigDecimal("100"));
pictureVo.setProgress(p.compareTo(BigDecimal.valueOf(100)) == 0 ? pictureVo.setProgress(p.compareTo(BigDecimal.valueOf(100)) == 0 ?
BigDecimal.valueOf(100) : p.setScale(4, RoundingMode.HALF_UP)); BigDecimal.valueOf(100) : p.setScale(2, RoundingMode.HALF_UP));
} }
} catch (Exception e) { } catch (Exception e) {
log.error("查询图片合成进度异常", e); log.error("查询图片合成进度异常", e);
} }
if (StringUtils.isNotBlank(pictureVo.getRecognizeResult())) {
List<PgsProgressPlanDetailRecognizerVo> recognizerList =
JSONUtil.toList(pictureVo.getRecognizeResult(), PgsProgressPlanDetailRecognizerVo.class);
if (CollUtil.isNotEmpty(recognizerList)) {
// 1. 按类型名称分组
Map<String, List<PgsProgressPlanDetailRecognizerVo>> groupMap = recognizerList.stream()
.collect(Collectors.groupingBy(r -> {
RecognizerTypeEnum typeEnum = RecognizerTypeEnum.fromValue(r.getType());
return typeEnum != null ? typeEnum.getText() : "未知类型";
}));
// 2. 将每组转换为 “类型name1, name2”
String recognizerStr = groupMap.entrySet().stream()
.map(entry -> {
String type = entry.getKey();
String names = entry.getValue().stream()
.map(PgsProgressPlanDetailRecognizerVo::getName)
.collect(Collectors.joining(", "));
return type + "" + names;
})
.collect(Collectors.joining("")); // 组之间用分号分隔
pictureVo.setRecognizeResultStr(recognizerStr);
}
}
} }
return pictureVo; return pictureVo;
} }
@ -123,13 +149,36 @@ public class DroDroneBigPictureServiceImpl extends ServiceImpl<DroDroneBigPictur
BigDecimal p = progressVo.getProgress() BigDecimal p = progressVo.getProgress()
.multiply(new BigDecimal("100")); .multiply(new BigDecimal("100"));
pictureVo.setProgress(p.compareTo(BigDecimal.valueOf(100)) == 0 ? pictureVo.setProgress(p.compareTo(BigDecimal.valueOf(100)) == 0 ?
BigDecimal.valueOf(100) : p.setScale(4, RoundingMode.HALF_UP)); BigDecimal.valueOf(100) : p.setScale(2, RoundingMode.HALF_UP));
} }
} catch (Exception e) { } catch (Exception e) {
pictureVo.setStatus("4"); pictureVo.setStatus("4");
pictureVo.setRemark(e.getMessage()); pictureVo.setRemark(e.getMessage());
log.error("查询图片合成进度异常", e); log.error("查询图片合成进度异常", e);
} }
if (StringUtils.isNotBlank(pictureVo.getRecognizeResult())) {
List<PgsProgressPlanDetailRecognizerVo> recognizerList =
JSONUtil.toList(pictureVo.getRecognizeResult(), PgsProgressPlanDetailRecognizerVo.class);
if (CollUtil.isNotEmpty(recognizerList)) {
// 1. 按类型名称分组
Map<String, List<PgsProgressPlanDetailRecognizerVo>> groupMap = recognizerList.stream()
.collect(Collectors.groupingBy(r -> {
RecognizerTypeEnum typeEnum = RecognizerTypeEnum.fromValue(r.getType());
return typeEnum != null ? typeEnum.getText() : "未知类型";
}));
// 2. 将每组转换为 “类型name1, name2”
String recognizerStr = groupMap.entrySet().stream()
.map(entry -> {
String type = entry.getKey();
String names = entry.getValue().stream()
.map(PgsProgressPlanDetailRecognizerVo::getName)
.collect(Collectors.joining(", "));
return type + "" + names;
})
.collect(Collectors.joining("")); // 组之间用分号分隔
pictureVo.setRecognizeResultStr(recognizerStr);
}
}
} }
} }
result.setRecords(records); result.setRecords(records);
@ -173,10 +222,14 @@ public class DroDroneBigPictureServiceImpl extends ServiceImpl<DroDroneBigPictur
if (add == null) { if (add == null) {
return false; return false;
} }
if (StringUtils.isNotBlank(add.getBigPic()) && StringUtils.isNotBlank(add.getTifFile())) {
add.setStatus("3");
}
boolean save = this.save(add); boolean save = this.save(add);
if (!save) { if (!save) {
throw new ServiceException("新增无人机大图信息失败"); throw new ServiceException("新增无人机大图信息失败");
} }
Long id = add.getId();
// 压缩图片 // 压缩图片
String smallPic = add.getSmallPic(); String smallPic = add.getSmallPic();
if (StringUtils.isNotBlank(smallPic)) { if (StringUtils.isNotBlank(smallPic)) {
@ -188,7 +241,7 @@ public class DroDroneBigPictureServiceImpl extends ServiceImpl<DroDroneBigPictur
.map(String::valueOf) .map(String::valueOf)
.collect(Collectors.joining(",")); .collect(Collectors.joining(","));
DroDroneBigPicture update = new DroDroneBigPicture(); DroDroneBigPicture update = new DroDroneBigPicture();
update.setId(add.getId()); update.setId(id);
update.setCompressPic(ossIds); update.setCompressPic(ossIds);
this.updateById(update); this.updateById(update);
}).exceptionally(ex -> { }).exceptionally(ex -> {
@ -196,6 +249,26 @@ public class DroDroneBigPictureServiceImpl extends ServiceImpl<DroDroneBigPictur
return null; return null;
}); });
} }
if (StringUtils.isNotBlank(smallPic) && StringUtils.isBlank(add.getBigPic())) {
List<Long> picIds = StringUtils.splitTo(smallPic, Convert::toLong);
List<SysOssVo> ossVos = ossService.listByIds(picIds);
List<String> picUrls = ossVos.stream().map(SysOssVo::getUrl).toList();
// 异步执行大图合并
self.asyncAddBigPicture(add.getTaskName(), picUrls)
.thenAccept(result -> {
DroDroneBigPicture update = new DroDroneBigPicture();
update.setId(id);
update.setStatus("2");
update.setTaskId(result);
this.updateById(update);
}).exceptionally(ex -> {
log.error("无人机大图信息[{}]异步执行合成图片失败", add.getTaskName(), ex);
return null;
});
}
if (StringUtils.isNotBlank(add.getBigPic()) && StringUtils.isNotBlank(add.getTifFile())) {
return this.createProgressRecognize(id);
}
return true; return true;
} }
@ -254,8 +327,26 @@ public class DroDroneBigPictureServiceImpl extends ServiceImpl<DroDroneBigPictur
fileUrl = mergeUrlVo.getPngUrl(); fileUrl = mergeUrlVo.getPngUrl();
tifUrl = mergeUrlVo.getTifUrl(); tifUrl = mergeUrlVo.getTifUrl();
} else { } else {
fileUrl = bigPicture.getBigPic(); String bigPic = bigPicture.getBigPic();
tifUrl = bigPicture.getTifFile(); if (isLong(bigPic)) {
SysOssVo ossVo = ossService.getById(Long.parseLong(bigPic));
if (ossVo != null) {
bigPic = ossVo.getUrl();
} else {
throw new ServiceException("图片不存在");
}
}
fileUrl = bigPic;
String tifFile = bigPicture.getTifFile();
if (isLong(tifFile)) {
SysOssVo ossVo = ossService.getById(Long.parseLong(tifFile));
if (ossVo != null) {
tifFile = ossVo.getUrl();
} else {
throw new ServiceException("TIF文件不存在");
}
}
tifUrl = tifFile;
} }
// 创建进度识别 // 创建进度识别
PgsProgressPlanDetailAINumberReq ai = new PgsProgressPlanDetailAINumberReq(); PgsProgressPlanDetailAINumberReq ai = new PgsProgressPlanDetailAINumberReq();
@ -413,6 +504,19 @@ public class DroDroneBigPictureServiceImpl extends ServiceImpl<DroDroneBigPictur
return true; return true;
} }
/**
* 异步合成大图
*
* @param businessName 业务名称
* @param imageUrls 图片URL列表
* @return 任务id
*/
@Async
@Override
public CompletableFuture<String> asyncAddBigPicture(String businessName, List<String> imageUrls) {
return CompletableFuture.completedFuture(droneManager.createImageMergeTask(businessName, imageUrls));
}
/** /**
* 异步添加压缩图片 * 异步添加压缩图片
* *
@ -516,4 +620,19 @@ public class DroDroneBigPictureServiceImpl extends ServiceImpl<DroDroneBigPictur
.collect(Collectors.toSet()); .collect(Collectors.toSet());
return set1.equals(set2); return set1.equals(set2);
} }
/**
* 判断字符串是否为Long
*
* @param str 字符串
* @return 是否为Long
*/
private static boolean isLong(String str) {
try {
Long.parseLong(str);
return true;
} catch (Exception e) {
return false;
}
}
} }

View File

@ -34,6 +34,7 @@ public class DroneManager {
* *
* @param businessName 业务名称 * @param businessName 业务名称
* @param imageUrls 图片URL列表 * @param imageUrls 图片URL列表
* @return 任务ID
*/ */
public String createImageMergeTask(String businessName, List<String> imageUrls) { public String createImageMergeTask(String businessName, List<String> imageUrls) {
return DroneRequestUtils.createImgMergeTask(droneProperties.getUrl(), businessName, imageUrls); return DroneRequestUtils.createImgMergeTask(droneProperties.getUrl(), businessName, imageUrls);

View File

@ -67,6 +67,7 @@ public class DroneRequestUtils {
* *
* @param businessName 业务名称 * @param businessName 业务名称
* @param imageUrls 图片URL列表 * @param imageUrls 图片URL列表
* @return 任务ID
*/ */
public static String createImgMergeTask(String url, String businessName, List<String> imageUrls) { public static String createImgMergeTask(String url, String businessName, List<String> imageUrls) {
if (StringUtils.isBlank(businessName) || CollUtil.isEmpty(imageUrls)) { if (StringUtils.isBlank(businessName) || CollUtil.isEmpty(imageUrls)) {