parent
e73257514b
commit
8cba5fe502
13
core/pom.xml
13
core/pom.xml
|
@ -149,7 +149,20 @@
|
|||
<version>1.3.0-91</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.microsoft.onnxruntime</groupId>
|
||||
<artifactId>onnxruntime</artifactId>
|
||||
<version>1.16.1</version>
|
||||
</dependency>
|
||||
<!-- javacv 和 opencv 别同时用 -->
|
||||
<dependency>
|
||||
<groupId>org.openpnp</groupId>
|
||||
<artifactId>opencv</artifactId>
|
||||
<version>4.7.0-0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
package com.dite.znpt.config;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.dite.znpt.constant.Constants;
|
||||
import com.dite.znpt.enums.FilePathEnum;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -27,7 +24,7 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
|||
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
|
||||
registry.addResourceHandler("/swagger-ui/**").addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
|
||||
for (FilePathEnum pathEnum : FilePathEnum.values()) {
|
||||
registry.addResourceHandler(pathEnum.getUrlPath() + "**").addResourceLocations("file:" + pathEnum.getFileAbsolutePath());
|
||||
registry.addResourceHandler(pathEnum.getUrlPath() + "**").addResourceLocations("file:" + pathEnum.getFileAbsolutePathPrefix());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package com.dite.znpt.config;
|
||||
|
||||
import ai.onnxruntime.OrtEnvironment;
|
||||
import ai.onnxruntime.OrtException;
|
||||
import ai.onnxruntime.OrtSession;
|
||||
import lombok.Getter;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Getter
|
||||
@Configuration
|
||||
public class YoloModelConfig {
|
||||
|
||||
private OrtEnvironment env;
|
||||
private OrtSession session;
|
||||
private String[] labels;
|
||||
private List<double[]> colors;
|
||||
|
||||
@PostConstruct
|
||||
public void init() throws OrtException {
|
||||
env = OrtEnvironment.getEnvironment();
|
||||
OrtSession.SessionOptions options = new OrtSession.SessionOptions();
|
||||
session = env.createSession("d:\\tmp\\best.onnx", options);
|
||||
|
||||
// 解析 labels
|
||||
String names = session.getMetadata().getCustomMetadata().get("names");
|
||||
Pattern pattern = Pattern.compile("'([^']*)'");
|
||||
Matcher matcher = pattern.matcher(names);
|
||||
List<String> labelList = new ArrayList<>();
|
||||
colors = new ArrayList<>();
|
||||
|
||||
Random random = new Random();
|
||||
while (matcher.find()) {
|
||||
labelList.add(matcher.group(1));
|
||||
colors.add(new double[]{random.nextDouble()*256, random.nextDouble()*256, random.nextDouble()*256});
|
||||
}
|
||||
labels = labelList.toArray(new String[0]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
package com.dite.znpt.config;
|
||||
|
||||
import ai.onnxruntime.OrtEnvironment;
|
||||
import ai.onnxruntime.OrtException;
|
||||
import ai.onnxruntime.OrtSession;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.dite.znpt.domain.entity.ModelConfigEntity;
|
||||
import com.dite.znpt.enums.FilePathEnum;
|
||||
import com.dite.znpt.mapper.ModelConfigMapper;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class YoloModelRegistry {
|
||||
|
||||
private final ModelConfigMapper modelConfigMapper;
|
||||
|
||||
private final Map<String, OrtSession> sessionMap = new ConcurrentHashMap<>();
|
||||
private final Map<String, ModelMetadata> metaMap = new ConcurrentHashMap<>();
|
||||
private final Map<String, ModelConfigEntity> modelParamMap = new ConcurrentHashMap<>();
|
||||
@Getter
|
||||
private final OrtEnvironment environment = OrtEnvironment.getEnvironment();
|
||||
|
||||
static {
|
||||
// 加载opencv动态库
|
||||
nu.pattern.OpenCV.loadLocally();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void loadModelsOnStartup() throws OrtException {
|
||||
List<ModelConfigEntity> configs = modelConfigMapper.selectList(Wrappers.emptyWrapper());
|
||||
for (ModelConfigEntity config : configs) {
|
||||
loadModel(config);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadModel(ModelConfigEntity config) throws OrtException {
|
||||
OrtSession.SessionOptions opts = new OrtSession.SessionOptions();
|
||||
// 使用gpu,需要本机安装过cuda,并修改pom.xml,不安装也能运行本程序
|
||||
// sessionOptions.addCUDA(0);
|
||||
OrtSession session = environment.createSession(FilePathEnum.ATTACH.getFileAbsolutePath(config.getModelPath()), opts);
|
||||
String labelStr = session.getMetadata().getCustomMetadata().get("names");
|
||||
|
||||
// label解析
|
||||
List<String> labels = new ArrayList<>();
|
||||
List<double[]> colors = new ArrayList<>();
|
||||
Pattern pattern = Pattern.compile("'([^']*)'");
|
||||
Matcher matcher = pattern.matcher(labelStr);
|
||||
Random random = new Random();
|
||||
while (matcher.find()) {
|
||||
labels.add(matcher.group(1));
|
||||
colors.add(new double[]{random.nextDouble() * 256, random.nextDouble() * 256, random.nextDouble() * 256});
|
||||
}
|
||||
|
||||
sessionMap.put(config.getModelId(), session);
|
||||
metaMap.put(config.getModelId(), new ModelMetadata(labels.toArray(new String[0]), colors, config));
|
||||
modelParamMap.put(config.getModelId(), config);
|
||||
}
|
||||
|
||||
public OrtSession getSession(String modelId) {
|
||||
return sessionMap.get(modelId);
|
||||
}
|
||||
|
||||
public ModelMetadata getMetadata(String modelId) {
|
||||
return metaMap.get(modelId);
|
||||
}
|
||||
|
||||
public ModelConfigEntity getModelConfig(String modelId) {
|
||||
return modelParamMap.get(modelId);
|
||||
}
|
||||
|
||||
public void unloadModel(String modelId) {
|
||||
OrtSession session = sessionMap.remove(modelId);
|
||||
if (session != null) {
|
||||
try {
|
||||
session.close(); // 释放 ONNX runtime 资源
|
||||
} catch (OrtException e) {
|
||||
log.warn("模型 {} 卸载时发生错误: {}", modelId, e.getMessage());
|
||||
}
|
||||
}
|
||||
metaMap.remove(modelId);
|
||||
}
|
||||
|
||||
public void reloadModel(ModelConfigEntity modelConfig) throws OrtException {
|
||||
unloadModel(modelConfig.getModelId());
|
||||
loadModel(modelConfig);
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public static class ModelMetadata {
|
||||
private String[] labels;
|
||||
private List<double[]> colors;
|
||||
private ModelConfigEntity config;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.dite.znpt.domain.bo;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Detection{
|
||||
|
||||
@ApiModelProperty("标签")
|
||||
public String label;
|
||||
@ApiModelProperty("分类id")
|
||||
private Integer clsId;
|
||||
@ApiModelProperty("位置")
|
||||
private float[] bbox;
|
||||
@ApiModelProperty("置信度")
|
||||
private float confidence;
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package com.dite.znpt.domain.bo;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.opencv.core.Core;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Size;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
|
||||
public class Letterbox {
|
||||
|
||||
@Setter
|
||||
private Size newShape ;
|
||||
private final double[] color = new double[]{114,114,114};
|
||||
private final Boolean auto = false;
|
||||
private final Boolean scaleUp = true;
|
||||
@Setter
|
||||
private Integer stride = 32;
|
||||
|
||||
@Getter
|
||||
private double ratio;
|
||||
@Getter
|
||||
private double dw;
|
||||
@Getter
|
||||
private double dh;
|
||||
|
||||
public Letterbox(int w,int h) {
|
||||
this.newShape = new Size(w, h);
|
||||
}
|
||||
|
||||
public Letterbox() {
|
||||
this.newShape = new Size(640, 640);
|
||||
}
|
||||
|
||||
|
||||
public Integer getWidth() {
|
||||
return (int) this.newShape.width;
|
||||
}
|
||||
|
||||
public Integer getHeight() {
|
||||
return (int) this.newShape.height;
|
||||
}
|
||||
|
||||
public Mat letterbox(Mat im) { // 调整图像大小和填充图像,使满足步长约束,并记录参数
|
||||
|
||||
int[] shape = {im.rows(), im.cols()}; // 当前形状 [height, width]
|
||||
// Scale ratio (new / old)
|
||||
double r = Math.min(this.newShape.height / shape[0], this.newShape.width / shape[1]);
|
||||
if (!this.scaleUp) { // 仅缩小,不扩大(一且为了mAP)
|
||||
r = Math.min(r, 1.0);
|
||||
}
|
||||
// Compute padding
|
||||
Size newUnpad = new Size(Math.round(shape[1] * r), Math.round(shape[0] * r));
|
||||
double dw = this.newShape.width - newUnpad.width, dh = this.newShape.height - newUnpad.height; // wh 填充
|
||||
if (this.auto) { // 最小矩形
|
||||
dw = dw % this.stride;
|
||||
dh = dh % this.stride;
|
||||
}
|
||||
dw /= 2; // 填充的时候两边都填充一半,使图像居于中心
|
||||
dh /= 2;
|
||||
if (shape[1] != newUnpad.width || shape[0] != newUnpad.height) { // resize
|
||||
Imgproc.resize(im, im, newUnpad, 0, 0, Imgproc.INTER_LINEAR);
|
||||
}
|
||||
int top = (int) Math.round(dh - 0.1), bottom = (int) Math.round(dh + 0.1);
|
||||
int left = (int) Math.round(dw - 0.1), right = (int) Math.round(dw + 0.1);
|
||||
// 将图像填充为正方形
|
||||
Core.copyMakeBorder(im, im, top, bottom, left, right, Core.BORDER_CONSTANT, new org.opencv.core.Scalar(this.color));
|
||||
this.ratio = r;
|
||||
this.dh = dh;
|
||||
this.dw = dw;
|
||||
return im;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.dite.znpt.domain.bo;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public final class ODConfig {
|
||||
|
||||
|
||||
public static final Integer lineThicknessRatio = 333;
|
||||
public static final Double fontSizeRatio = 1080.0;
|
||||
|
||||
private static final List<String> default_names = new ArrayList<>(Arrays.asList(
|
||||
"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train",
|
||||
"truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter",
|
||||
"bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear",
|
||||
"zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase",
|
||||
"frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat",
|
||||
"baseball glove", "skateboard", "surfboard", "tennis racket", "bottle",
|
||||
"wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
|
||||
"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut",
|
||||
"cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet",
|
||||
"tv", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave",
|
||||
"oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors",
|
||||
"teddy bear", "hair drier", "toothbrush"));
|
||||
|
||||
|
||||
private static final List<String> names = new ArrayList<>(Arrays.asList(
|
||||
"no_helmet", "helmet"));
|
||||
|
||||
private final Map<String, double[]> colors;
|
||||
|
||||
public ODConfig() {
|
||||
this.colors = new HashMap<>();
|
||||
default_names.forEach(name->{
|
||||
Random random = new Random();
|
||||
double[] color = {random.nextDouble()*256, random.nextDouble()*256, random.nextDouble()*256};
|
||||
colors.put(name, color);
|
||||
});
|
||||
}
|
||||
|
||||
public String getName(int clsId) {
|
||||
return names.get(clsId);
|
||||
}
|
||||
|
||||
public double[] getColor(int clsId) {
|
||||
return colors.get(getName(clsId));
|
||||
}
|
||||
|
||||
public double[] getNameColor(String Name){
|
||||
return colors.get(Name);
|
||||
}
|
||||
|
||||
public double[] getOtherColor(int clsId) {
|
||||
return colors.get(default_names.get(clsId));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.dite.znpt.domain.entity;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.dite.znpt.domain.AuditableEntity;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
* @Description: 模型配置表实体类
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@TableName("model_config")
|
||||
@ApiModel(value="ModelConfigEntity对象", description="模型配置表")
|
||||
public class ModelConfigEntity extends AuditableEntity implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = -73052440757340126L;
|
||||
|
||||
@ExcelProperty("模型id")
|
||||
@ApiModelProperty("模型id")
|
||||
@TableId(value = "model_id", type = IdType.ASSIGN_ID)
|
||||
private String modelId;
|
||||
|
||||
@ExcelProperty("模型名称")
|
||||
@ApiModelProperty("模型名称")
|
||||
@TableField("model_name")
|
||||
private String modelName;
|
||||
|
||||
@ExcelProperty("模型路径")
|
||||
@ApiModelProperty("模型路径")
|
||||
@TableField("model_path")
|
||||
private String modelPath;
|
||||
|
||||
@ExcelProperty("模型置信度")
|
||||
@ApiModelProperty("模型置信度")
|
||||
@TableField("conf_threshold")
|
||||
private Float confThreshold;
|
||||
|
||||
@ExcelProperty("非极大抑制")
|
||||
@ApiModelProperty("非极大抑制")
|
||||
@TableField("nms_threshold")
|
||||
private Float nmsThreshold;
|
||||
}
|
||||
|
|
@ -1,24 +1,27 @@
|
|||
package com.dite.znpt.domain.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.dite.znpt.domain.AuditableEntity;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author huise23
|
||||
* @date 2025/04/11 23:17
|
||||
* @Description: 表实体类
|
||||
* @Description: 部件表实体类
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@TableName("part")
|
||||
@ApiModel(value="PartEntity对象", description="表")
|
||||
@ApiModel(value="PartEntity对象", description="部件表")
|
||||
public class PartEntity extends AuditableEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -53853862365306266L;
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package com.dite.znpt.domain.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
* @Description: 请求实体
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("列表请求实体")
|
||||
public class ModelConfigListReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = -41204426418525667L;
|
||||
|
||||
@ApiModelProperty("查询关键字")
|
||||
private String keyword;
|
||||
|
||||
@ApiModelProperty("Id")
|
||||
private String modelId;
|
||||
|
||||
@ApiModelProperty("模型名称")
|
||||
private String modelName;
|
||||
|
||||
@ApiModelProperty("模型路径")
|
||||
private String modelPath;
|
||||
|
||||
@ApiModelProperty("模型置信度")
|
||||
private Float confThreshold;
|
||||
|
||||
@ApiModelProperty("非极大抑制")
|
||||
private Float nmsThreshold;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.dite.znpt.domain.vo;
|
||||
|
||||
import com.dite.znpt.util.ValidationGroup;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
* @Description: 模型配置表请求类
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@ApiModel(value="ModelConfig请求对象", description="模型配置表")
|
||||
public class ModelConfigReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 930798215980875267L;
|
||||
|
||||
@ApiModelProperty("模型id")
|
||||
private String modelId;
|
||||
|
||||
@NotBlank(groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "模型名称不能为空")
|
||||
@Size(max = 50, groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "模型名称长度不能超过50")
|
||||
@ApiModelProperty("模型名称")
|
||||
private String modelName;
|
||||
|
||||
@NotEmpty(groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "模型附件不能为空")
|
||||
@ApiModelProperty("模型附件id")
|
||||
private String attachId;
|
||||
|
||||
@NotNull(groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "模型置信度不能为空")
|
||||
@Min(value = 0, groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "模型置信度只能在0-100之间")
|
||||
@Max(value = 100, groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "模型置信度只能在0-100之间")
|
||||
@ApiModelProperty("模型置信度")
|
||||
private Float confThreshold;
|
||||
|
||||
@NotNull(groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "nms不能为空")
|
||||
@Min(value = 0, groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "nms只能在0-1之间")
|
||||
@Max(value = 1, groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "nms只能在0-1之间")
|
||||
@ApiModelProperty("nms")
|
||||
private Float nmsThreshold;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.dite.znpt.domain.vo;
|
||||
|
||||
import com.dite.znpt.domain.entity.ModelConfigEntity;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
* @Description: 响应实体
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ApiModel("响应实体")
|
||||
public class ModelConfigResp extends ModelConfigEntity {
|
||||
}
|
||||
|
|
@ -1,21 +1,13 @@
|
|||
package com.dite.znpt.domain.vo;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
|
||||
import com.dite.znpt.util.ValidationGroup;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
/**
|
||||
* @author huise23
|
||||
* @date 2025/06/27 14:21
|
||||
|
@ -60,11 +52,11 @@ public class ProjectTaskImportReq implements Serializable {
|
|||
@ExcelProperty(value = "实际结束时间")
|
||||
private LocalDate actualEndDate;
|
||||
|
||||
@ExcelProperty(value = "任务状态,0未开始,1进行中,2已结束")
|
||||
private Integer status;
|
||||
@ExcelProperty(value = "任务状态(未开始,进行中,已结束)")
|
||||
private String status;
|
||||
|
||||
@ExcelProperty(value = "是否逾期,默认未逾期")
|
||||
private Integer overdueStatus;
|
||||
@ExcelProperty(value = "是否逾期(已逾期,未逾期)")
|
||||
private String overdueStatus;
|
||||
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
|
|
@ -15,6 +15,7 @@ import java.util.List;
|
|||
public enum AttachBusinessTypeEnum {
|
||||
PROJECT_TASK("PROJECT_TASK", "项目任务"),
|
||||
INSURANCE_FILE("insurance", "保险文件"),
|
||||
MODEL_FILE("model", "模型文件"),
|
||||
;
|
||||
private final String code;
|
||||
private final String desc;
|
||||
|
|
|
@ -22,26 +22,37 @@ public enum FilePathEnum {
|
|||
private final String fileRelativePath;
|
||||
|
||||
/**
|
||||
* 功能描述:获取文件绝对路径
|
||||
* 功能描述:获取文件绝对路径前缀
|
||||
*
|
||||
* @return {@link String }
|
||||
* @author cuizhibin
|
||||
* @date 2025/06/23 14:46
|
||||
**/
|
||||
public String getFileAbsolutePath() {
|
||||
public String getFileAbsolutePathPrefix() {
|
||||
return SpringUtil.getBean(Environment.class).getProperty("upload.save-path") + fileRelativePath + FileUtil.FILE_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* 功能描述:获取图像下载路径
|
||||
* 功能描述:获取文件绝对路径全路径
|
||||
*
|
||||
* @return {@link String }
|
||||
* @author cuizhibin
|
||||
* @date 2025/06/23 14:46
|
||||
**/
|
||||
public String getFileAbsolutePath(String fileDownPath) {
|
||||
return FileUtil.normalize(getFileAbsolutePathPrefix() + StrUtil.removePrefix(fileDownPath, urlPath));
|
||||
}
|
||||
|
||||
/**
|
||||
* 功能描述:获取下载路径
|
||||
*
|
||||
* @param absolutePath
|
||||
* @return {@link String }
|
||||
* @author cuizhibin
|
||||
* @date 2025/06/06 09:07
|
||||
**/
|
||||
public String getImageDownPath(String absolutePath) {
|
||||
String relativePath = StrUtil.removePrefix(absolutePath, getFileAbsolutePath());
|
||||
public String getFileDownPath(String absolutePath) {
|
||||
String relativePath = StrUtil.removePrefix(absolutePath, getFileAbsolutePathPrefix());
|
||||
return StrUtil.replace(urlPath.concat(relativePath), FileUtil.FILE_SEPARATOR, StrUtil.SLASH);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package com.dite.znpt.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.dite.znpt.domain.entity.ModelConfigEntity;
|
||||
import com.dite.znpt.domain.vo.ModelConfigListReq;
|
||||
import com.dite.znpt.domain.vo.ModelConfigResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
* @Description: 模型配置表数据库访问层
|
||||
*/
|
||||
public interface ModelConfigMapper extends BaseMapper<ModelConfigEntity> {
|
||||
List<ModelConfigResp> queryBySelective(ModelConfigListReq modelConfigReq);
|
||||
}
|
||||
|
|
@ -4,15 +4,13 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|||
import com.dite.znpt.domain.entity.PartEntity;
|
||||
import com.dite.znpt.domain.vo.PartListReq;
|
||||
import com.dite.znpt.domain.vo.PartListResp;
|
||||
import com.dite.znpt.domain.vo.PartResp;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author huise23
|
||||
* @date 2025/04/11 23:17
|
||||
* @Description: 表数据库访问层
|
||||
* @Description: 部件表数据库访问层
|
||||
*/
|
||||
public interface PartMapper extends BaseMapper<PartEntity> {
|
||||
List<PartListResp> queryBySelective(PartListReq partReq);
|
||||
|
|
|
@ -7,7 +7,6 @@ import com.dite.znpt.enums.AttachBusinessTypeEnum;
|
|||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.rmi.ServerException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
package com.dite.znpt.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.dite.znpt.domain.entity.ModelConfigEntity;
|
||||
import com.dite.znpt.domain.vo.ModelConfigListReq;
|
||||
import com.dite.znpt.domain.vo.ModelConfigReq;
|
||||
import com.dite.znpt.domain.vo.ModelConfigResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
* @Description: 模型配置表服务接口
|
||||
*/
|
||||
public interface ModelConfigService extends IService<ModelConfigEntity> {
|
||||
|
||||
/**
|
||||
* 功能描述:查询列表
|
||||
*
|
||||
* @param modelConfigReq
|
||||
* @return {@link List }<{@link ModelConfigResp }>
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
**/
|
||||
List<ModelConfigResp> selectList(ModelConfigListReq modelConfigReq);
|
||||
|
||||
/**
|
||||
* 功能描述:查询单条
|
||||
*
|
||||
* @param modelId Id
|
||||
* @return {@link ModelConfigResp }
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
**/
|
||||
ModelConfigResp selectById(String modelId);
|
||||
|
||||
/**
|
||||
* 功能描述:新增
|
||||
*
|
||||
* @param modelConfigReq
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
**/
|
||||
void saveData(ModelConfigReq modelConfigReq);
|
||||
|
||||
/**
|
||||
* 功能描述:更新
|
||||
*
|
||||
* @param modelConfigReq
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
**/
|
||||
void updateData(ModelConfigReq modelConfigReq);
|
||||
|
||||
/**
|
||||
* 功能描述:删除
|
||||
*
|
||||
* @param modelId Id
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
**/
|
||||
void deleteById(String modelId);
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import java.util.List;
|
|||
/**
|
||||
* @author huise23
|
||||
* @date 2025/04/11 23:17
|
||||
* @Description: 表服务接口
|
||||
* @Description: 部件表服务接口
|
||||
*/
|
||||
public interface PartService extends IService<PartEntity> {
|
||||
|
||||
|
|
|
@ -10,17 +10,15 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|||
import com.dite.znpt.constant.Constants;
|
||||
import com.dite.znpt.constant.Message;
|
||||
import com.dite.znpt.domain.entity.AttachInfoEntity;
|
||||
import com.dite.znpt.domain.entity.InsuranceInfoEntity;
|
||||
import com.dite.znpt.domain.vo.AttachInfoReq;
|
||||
import com.dite.znpt.enums.AttachBusinessTypeEnum;
|
||||
import com.dite.znpt.enums.FilePathEnum;
|
||||
import com.dite.znpt.service.AttachInfoService;
|
||||
import com.dite.znpt.mapper.FileInfoMapper;
|
||||
import com.dite.znpt.service.AttachInfoService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Service;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.dite.znpt.util.PageUtil;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
|
@ -69,7 +67,7 @@ public class AttachInfoServiceImpl extends ServiceImpl<FileInfoMapper, AttachInf
|
|||
**/
|
||||
@Override
|
||||
public List<String> saveData(String businessType, AttachInfoReq infoReq, MultipartFile[] files) {
|
||||
String temPathPrefix = FilePathEnum.ATTACH.getFileAbsolutePath().concat(businessType).concat(FileUtil.FILE_SEPARATOR);
|
||||
String temPathPrefix = FilePathEnum.ATTACH.getFileAbsolutePathPrefix().concat(businessType).concat(FileUtil.FILE_SEPARATOR);
|
||||
if(StrUtil.isNotBlank(infoReq.getUserDefinedPath())){
|
||||
temPathPrefix = temPathPrefix.concat(infoReq.getUserDefinedPath()).concat(FileUtil.FILE_SEPARATOR);
|
||||
}
|
||||
|
@ -84,7 +82,7 @@ public class AttachInfoServiceImpl extends ServiceImpl<FileInfoMapper, AttachInf
|
|||
String path = temPathPrefix + file.getOriginalFilename();
|
||||
FileUtil.writeBytes(file.getBytes(),path);
|
||||
AttachInfoEntity attachInfo = AttachInfoEntity.builder()
|
||||
.attachPath(FilePathEnum.ATTACH.getImageDownPath(path))
|
||||
.attachPath(FilePathEnum.ATTACH.getFileDownPath(path))
|
||||
.businessType(businessType)
|
||||
.fileType(infoReq.getFileType())
|
||||
.remark(infoReq.getRemark())
|
||||
|
@ -105,7 +103,7 @@ public class AttachInfoServiceImpl extends ServiceImpl<FileInfoMapper, AttachInf
|
|||
if(null == attachInfo || !Constants.DEL_FLAG_0.equals(attachInfo.getDelFlag())){
|
||||
throw new ServerException(Message.ATTACH_INFO_IS_NOT_EXIST);
|
||||
}
|
||||
String filePath = FilePathEnum.ATTACH.getFileAbsolutePath().concat(StrUtil.removePrefix(attachInfo.getAttachPath(), FilePathEnum.ATTACH.getUrlPath()));
|
||||
String filePath = FilePathEnum.ATTACH.getFileAbsolutePathPrefix().concat(StrUtil.removePrefix(attachInfo.getAttachPath(), FilePathEnum.ATTACH.getUrlPath()));
|
||||
File file = new File(filePath);
|
||||
// 检查文件是否存在
|
||||
if (!file.exists()) {
|
||||
|
|
|
@ -104,7 +104,7 @@ public class AudioFileInfoServiceImpl extends ServiceImpl<AudioFileInfoMapper, A
|
|||
throw new ServiceException(Message.IMAGE_ID_IS_NOT_EXIST);
|
||||
}
|
||||
PartResp partResp = partService.detail(image.getPartId());
|
||||
String audioFilePrefix = FilePathEnum.AUDIO.getFileAbsolutePath() + partResp.getProjectName().concat(FileUtil.FILE_SEPARATOR).concat(partResp.getTurbineName()).concat(FileUtil.FILE_SEPARATOR);
|
||||
String audioFilePrefix = FilePathEnum.AUDIO.getFileAbsolutePathPrefix() + partResp.getProjectName().concat(FileUtil.FILE_SEPARATOR).concat(partResp.getTurbineName()).concat(FileUtil.FILE_SEPARATOR);
|
||||
List<AudioFileInfoEntity> list = new ArrayList<>();
|
||||
for (MultipartFile file : files) {
|
||||
AudioFileInfoEntity audio = new AudioFileInfoEntity();
|
||||
|
@ -113,7 +113,7 @@ public class AudioFileInfoServiceImpl extends ServiceImpl<AudioFileInfoMapper, A
|
|||
try {
|
||||
String path = audioFilePrefix + file.getOriginalFilename();
|
||||
FileUtil.writeBytes(file.getBytes(),path);
|
||||
audio.setFilePath(FilePathEnum.AUDIO.getImageDownPath(path));
|
||||
audio.setFilePath(FilePathEnum.AUDIO.getFileDownPath(path));
|
||||
list.add(audio);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -56,7 +56,7 @@ public class DictServiceImpl extends ServiceImpl<DictMapper, DictEntity> impleme
|
|||
dictReq.setDictId(dictId);
|
||||
|
||||
List<DictResp> list = selectList(dictReq);
|
||||
return list.isEmpty() ? CollUtil.getFirst(list) : new DictResp();
|
||||
return CollUtil.isNotEmpty(list) ? CollUtil.getFirst(list) : new DictResp();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -52,8 +52,8 @@ public class ImageCollectServiceImpl extends ServiceImpl<ImageCollectMapper, Ima
|
|||
this.save(imageCollect);
|
||||
String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||
List<ImageEntity> imageList = Converts.INSTANCE.toImageEntity(req.getImageList());
|
||||
String permPathPrefix = FilePathEnum.IMAGE.getFileAbsolutePath().concat(ImageSourceEnum.COLLECT.getCode()).concat(FileUtil.FILE_SEPARATOR).concat(partId).concat(FileUtil.FILE_SEPARATOR).concat(dateStr).concat(FileUtil.FILE_SEPARATOR);
|
||||
String temPathPrefix = FilePathEnum.IMAGE_TEMP.getFileAbsolutePath().concat(ImageSourceEnum.COLLECT.getCode()).concat(FileUtil.FILE_SEPARATOR).concat(partId).concat(FileUtil.FILE_SEPARATOR);
|
||||
String permPathPrefix = FilePathEnum.IMAGE.getFileAbsolutePathPrefix().concat(ImageSourceEnum.COLLECT.getCode()).concat(FileUtil.FILE_SEPARATOR).concat(partId).concat(FileUtil.FILE_SEPARATOR).concat(dateStr).concat(FileUtil.FILE_SEPARATOR);
|
||||
String temPathPrefix = FilePathEnum.IMAGE_TEMP.getFileAbsolutePathPrefix().concat(ImageSourceEnum.COLLECT.getCode()).concat(FileUtil.FILE_SEPARATOR).concat(partId).concat(FileUtil.FILE_SEPARATOR);
|
||||
imageList.forEach(image -> {
|
||||
image.setPartId(partId);
|
||||
image.setCollectId(imageCollect.getCollectId());
|
||||
|
@ -62,7 +62,7 @@ public class ImageCollectServiceImpl extends ServiceImpl<ImageCollectMapper, Ima
|
|||
if (file.exists()) {
|
||||
byte[] bytes = FileUtil.readBytes(file);
|
||||
FileUtil.writeBytes(bytes, path);
|
||||
String url = FilePathEnum.IMAGE.getUrlPath().concat(StrUtil.removePrefix(path,FilePathEnum.IMAGE.getFileAbsolutePath()).replace(FileUtil.FILE_SEPARATOR, StrUtil.SLASH));
|
||||
String url = FilePathEnum.IMAGE.getUrlPath().concat(StrUtil.removePrefix(path,FilePathEnum.IMAGE.getFileAbsolutePathPrefix()).replace(FileUtil.FILE_SEPARATOR, StrUtil.SLASH));
|
||||
image.setImagePath(url);
|
||||
FileUtil.del(file);
|
||||
}else {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
package com.dite.znpt.service.impl;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
|
@ -12,16 +11,16 @@ import cn.hutool.core.util.StrUtil;
|
|||
import cn.hutool.json.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.dite.znpt.constant.Constants;
|
||||
import com.dite.znpt.constant.Message;
|
||||
import com.dite.znpt.domain.bo.PartFullInfoBo;
|
||||
import com.dite.znpt.domain.entity.AudioFileInfoEntity;
|
||||
import com.dite.znpt.domain.entity.ImageCollectEntity;
|
||||
import com.dite.znpt.domain.entity.ImageEntity;
|
||||
import com.dite.znpt.domain.entity.PartEntity;
|
||||
import com.dite.znpt.domain.page.PageDomain;
|
||||
import com.dite.znpt.domain.vo.*;
|
||||
import com.dite.znpt.enums.*;
|
||||
import com.dite.znpt.enums.FilePathEnum;
|
||||
import com.dite.znpt.enums.ImageTypeEnum;
|
||||
import com.dite.znpt.enums.ShootingMethodEnum;
|
||||
import com.dite.znpt.enums.WeatherEnum;
|
||||
import com.dite.znpt.exception.ServiceException;
|
||||
import com.dite.znpt.mapper.ImageMapper;
|
||||
import com.dite.znpt.service.AudioFileInfoService;
|
||||
|
@ -32,7 +31,6 @@ import com.dite.znpt.util.EXIFUtil;
|
|||
import com.dite.znpt.util.PageUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
@ -42,9 +40,7 @@ import java.io.File;
|
|||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.FileVisitor;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
@ -103,8 +99,8 @@ public class ImageServiceImpl extends ServiceImpl<ImageMapper, ImageEntity> impl
|
|||
Map<String, PartEntity> partIdMap= partService.listByIds(partIds).stream().collect(Collectors.toMap(PartEntity::getPartId, Function.identity()));
|
||||
list.forEach(req -> {
|
||||
if(partIdMap.containsKey(req.getPartId())){
|
||||
String path_prefix = FilePathEnum.IMAGE.getFileAbsolutePath().concat(StrUtil.BACKSLASH).concat(req.getImageSource()).concat(StrUtil.BACKSLASH).concat(req.getPartId()).concat(StrUtil.BACKSLASH);
|
||||
String temp_path_prefix = FilePathEnum.IMAGE_TEMP.getFileAbsolutePath().concat(StrUtil.BACKSLASH).concat(req.getImageSource()).concat(StrUtil.BACKSLASH).concat(req.getPartId()).concat(StrUtil.BACKSLASH);
|
||||
String path_prefix = FilePathEnum.IMAGE.getFileAbsolutePathPrefix().concat(StrUtil.BACKSLASH).concat(req.getImageSource()).concat(StrUtil.BACKSLASH).concat(req.getPartId()).concat(StrUtil.BACKSLASH);
|
||||
String temp_path_prefix = FilePathEnum.IMAGE_TEMP.getFileAbsolutePathPrefix().concat(StrUtil.BACKSLASH).concat(req.getImageSource()).concat(StrUtil.BACKSLASH).concat(req.getPartId()).concat(StrUtil.BACKSLASH);
|
||||
File file = new File(req.getImagePath());
|
||||
if(file.exists() && req.getImagePath().contains(temp_path_prefix)){
|
||||
ImageEntity entity = new ImageEntity();
|
||||
|
@ -146,12 +142,12 @@ public class ImageServiceImpl extends ServiceImpl<ImageMapper, ImageEntity> impl
|
|||
throw new ServiceException(Message.IMAGE_IS_EMPTY);
|
||||
}
|
||||
List<ImageReq> list = new ArrayList<>(files.length);
|
||||
File temCategory = new File(FilePathEnum.IMAGE_TEMP.getFileAbsolutePath());
|
||||
File temCategory = new File(FilePathEnum.IMAGE_TEMP.getFileAbsolutePathPrefix());
|
||||
if (!temCategory.exists()) {
|
||||
// 创建完整的目录
|
||||
temCategory.mkdirs();
|
||||
}
|
||||
String temPathPrefix = FilePathEnum.IMAGE_TEMP.getFileAbsolutePath().concat(imageSource).concat(FileUtil.FILE_SEPARATOR).concat(partId).concat(FileUtil.FILE_SEPARATOR);
|
||||
String temPathPrefix = FilePathEnum.IMAGE_TEMP.getFileAbsolutePathPrefix().concat(imageSource).concat(FileUtil.FILE_SEPARATOR).concat(partId).concat(FileUtil.FILE_SEPARATOR);
|
||||
for (MultipartFile file : files) {
|
||||
if (!file.isEmpty()) {
|
||||
try {
|
||||
|
@ -173,7 +169,7 @@ public class ImageServiceImpl extends ServiceImpl<ImageMapper, ImageEntity> impl
|
|||
throw new ServiceException(Message.IMAGE_IS_EMPTY);
|
||||
}
|
||||
String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||
String path_prefix = FilePathEnum.IMAGE.getFileAbsolutePath().concat(imageSource).concat(FileUtil.FILE_SEPARATOR).concat(dateStr).concat(FileUtil.FILE_SEPARATOR);
|
||||
String path_prefix = FilePathEnum.IMAGE.getFileAbsolutePathPrefix().concat(imageSource).concat(FileUtil.FILE_SEPARATOR).concat(dateStr).concat(FileUtil.FILE_SEPARATOR);
|
||||
if (Objects.nonNull(imageWorkReq)) {
|
||||
path_prefix = path_prefix.concat(StrUtil.emptyToDefault(imageWorkReq.getUploadUser(), "默认用户")).concat(FileUtil.FILE_SEPARATOR)
|
||||
.concat(StrUtil.emptyToDefault(imageWorkReq.getLongitude(), "0"))
|
||||
|
@ -188,7 +184,7 @@ public class ImageServiceImpl extends ServiceImpl<ImageMapper, ImageEntity> impl
|
|||
for (MultipartFile multipartFile : files) {
|
||||
String path = path_prefix + multipartFile.getOriginalFilename();
|
||||
FileUtil.writeBytes(multipartFile.getBytes(),path);
|
||||
result.add(FilePathEnum.IMAGE.getImageDownPath(path));
|
||||
result.add(FilePathEnum.IMAGE.getFileDownPath(path));
|
||||
}
|
||||
String partId = imageWorkReq.getPartId();
|
||||
if (StrUtil.isNotEmpty(partId)) {
|
||||
|
@ -202,7 +198,7 @@ public class ImageServiceImpl extends ServiceImpl<ImageMapper, ImageEntity> impl
|
|||
List<ImageEntity> imageList = new ArrayList<>();
|
||||
result.forEach(path -> {
|
||||
ImageEntity imageEntity = new ImageEntity();
|
||||
String absolutePath = FilePathEnum.IMAGE.getFileAbsolutePath() + StrUtil.removePrefix(path, FilePathEnum.IMAGE.getUrlPath());
|
||||
String absolutePath = FilePathEnum.IMAGE.getFileAbsolutePathPrefix() + StrUtil.removePrefix(path, FilePathEnum.IMAGE.getUrlPath());
|
||||
try {
|
||||
ImageReq imageReq = imageRespBuilder(absolutePath);
|
||||
BeanUtil.copyProperties(imageReq, imageEntity);
|
||||
|
@ -251,7 +247,7 @@ public class ImageServiceImpl extends ServiceImpl<ImageMapper, ImageEntity> impl
|
|||
req.setCameraManufacturer(obj.getStr("Make"));
|
||||
req.setCameraModel(obj.getStr("Model"));
|
||||
req.setImageName(obj.getStr("File Name"));
|
||||
req.setImagePath(FilePathEnum.IMAGE_TEMP.getImageDownPath(path));
|
||||
req.setImagePath(FilePathEnum.IMAGE_TEMP.getFileDownPath(path));
|
||||
BigDecimal imageSize = new BigDecimal(extractDigit(obj.getStr("File Size"))).divide(new BigDecimal(1024*1024), 4, RoundingMode.HALF_UP);
|
||||
req.setImageSize(imageSize.toString().concat("M"));
|
||||
req.setImageWidth(extractDigit(obj.getStr("Image Width")));
|
||||
|
@ -308,11 +304,11 @@ public class ImageServiceImpl extends ServiceImpl<ImageMapper, ImageEntity> impl
|
|||
@Override
|
||||
public List<AppImageResp> listAppUploadImages() {
|
||||
List<String> filePaths = new ArrayList<>();
|
||||
PathUtil.walkFiles(Path.of(FilePathEnum.IMAGE.getFileAbsolutePath()), new SimpleFileVisitor<>() {
|
||||
PathUtil.walkFiles(Path.of(FilePathEnum.IMAGE.getFileAbsolutePathPrefix()), new SimpleFileVisitor<>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
|
||||
if (path.toFile().isFile()) {
|
||||
String imageDownPath = FilePathEnum.IMAGE.getImageDownPath(path.toFile().getAbsolutePath());
|
||||
String imageDownPath = FilePathEnum.IMAGE.getFileDownPath(path.toFile().getAbsolutePath());
|
||||
List<String> split = StrUtil.split(imageDownPath, StrUtil.SLASH, true, true);
|
||||
// /static/image/source/date
|
||||
try {
|
||||
|
@ -405,7 +401,7 @@ public class ImageServiceImpl extends ServiceImpl<ImageMapper, ImageEntity> impl
|
|||
List<ImageEntity> newImageList = new ArrayList<>();
|
||||
partReq.getImagePaths().forEach(path -> {
|
||||
ImageEntity imageEntity = new ImageEntity();
|
||||
String absolutePath = FilePathEnum.IMAGE.getFileAbsolutePath() + StrUtil.removePrefix(path, FilePathEnum.IMAGE.getUrlPath());
|
||||
String absolutePath = FilePathEnum.IMAGE.getFileAbsolutePathPrefix() + StrUtil.removePrefix(path, FilePathEnum.IMAGE.getUrlPath());
|
||||
try {
|
||||
ImageReq imageReq = imageRespBuilder(absolutePath);
|
||||
BeanUtil.copyProperties(imageReq, imageEntity);
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
package com.dite.znpt.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.dite.znpt.config.YoloModelRegistry;
|
||||
import com.dite.znpt.domain.entity.AttachInfoEntity;
|
||||
import com.dite.znpt.domain.entity.ModelConfigEntity;
|
||||
import com.dite.znpt.domain.vo.ModelConfigListReq;
|
||||
import com.dite.znpt.domain.vo.ModelConfigReq;
|
||||
import com.dite.znpt.domain.vo.ModelConfigResp;
|
||||
import com.dite.znpt.enums.AttachBusinessTypeEnum;
|
||||
import com.dite.znpt.mapper.ModelConfigMapper;
|
||||
import com.dite.znpt.service.AttachInfoService;
|
||||
import com.dite.znpt.service.ModelConfigService;
|
||||
import com.dite.znpt.util.PageUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
* @Description: 模型配置表服务实现类
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ModelConfigServiceImpl extends ServiceImpl<ModelConfigMapper, ModelConfigEntity> implements ModelConfigService {
|
||||
|
||||
private final YoloModelRegistry modelRegistry;
|
||||
private final AttachInfoService attachInfoService;
|
||||
|
||||
/**
|
||||
* 功能描述:查询列表
|
||||
*
|
||||
* @param modelConfigReq 信息
|
||||
* @return {@link List }<{@link ModelConfigResp }>
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
**/
|
||||
@Override
|
||||
public List<ModelConfigResp> selectList(ModelConfigListReq modelConfigReq) {
|
||||
PageUtil.startPage();
|
||||
List<ModelConfigResp> modelConfigList= this.baseMapper.queryBySelective(modelConfigReq);
|
||||
modelConfigList.forEach(resp -> {
|
||||
|
||||
});
|
||||
return modelConfigList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 功能描述:查询单条
|
||||
*
|
||||
* @param modelId Id
|
||||
* @return {@link ModelConfigResp }
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
**/
|
||||
@Override
|
||||
public ModelConfigResp selectById(String modelId) {
|
||||
ModelConfigListReq modelConfigReq = new ModelConfigListReq();
|
||||
modelConfigReq.setModelId(modelId);
|
||||
|
||||
List<ModelConfigResp> list = selectList(modelConfigReq);
|
||||
return CollUtil.isNotEmpty(list) ? CollUtil.getFirst(list) : new ModelConfigResp();
|
||||
}
|
||||
|
||||
/**
|
||||
* 功能描述:新增
|
||||
*
|
||||
* @param modelConfigReq
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
**/
|
||||
@SneakyThrows
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveData(ModelConfigReq modelConfigReq) {
|
||||
ModelConfigEntity entity = BeanUtil.copyProperties(modelConfigReq, ModelConfigEntity.class);
|
||||
AttachInfoEntity attachInfo = attachInfoService.getById(modelConfigReq.getAttachId());
|
||||
entity.setModelPath(attachInfo.getAttachPath());
|
||||
save(entity);
|
||||
attachInfoService.updateBusinessIdByAttachIds(entity.getModelId(), ListUtil.of(modelConfigReq.getAttachId()), AttachBusinessTypeEnum.MODEL_FILE);
|
||||
modelRegistry.loadModel(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 功能描述:更新
|
||||
*
|
||||
* @param modelConfigReq
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
**/
|
||||
@SneakyThrows
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateData(ModelConfigReq modelConfigReq) {
|
||||
ModelConfigEntity entity = BeanUtil.copyProperties(modelConfigReq, ModelConfigEntity.class);
|
||||
AttachInfoEntity attachInfo = attachInfoService.getById(modelConfigReq.getAttachId());
|
||||
entity.setModelPath(attachInfo.getAttachPath());
|
||||
attachInfoService.updateBusinessIdByAttachIds(entity.getModelId(), ListUtil.of(modelConfigReq.getAttachId()), AttachBusinessTypeEnum.MODEL_FILE);
|
||||
updateById(entity);
|
||||
modelRegistry.reloadModel(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 功能描述:删除
|
||||
*
|
||||
* @param modelId Id
|
||||
* @author huise23
|
||||
* @date 2025/07/02 20:57
|
||||
**/
|
||||
@Override
|
||||
public void deleteById(String modelId) {
|
||||
modelRegistry.unloadModel(modelId);
|
||||
removeById(modelId);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
package com.dite.znpt.service.impl;
|
||||
|
||||
import ai.onnxruntime.OnnxTensor;
|
||||
import ai.onnxruntime.OrtEnvironment;
|
||||
import ai.onnxruntime.OrtException;
|
||||
import ai.onnxruntime.OrtSession;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.dite.znpt.config.YoloModelRegistry;
|
||||
import com.dite.znpt.domain.bo.Detection;
|
||||
import com.dite.znpt.domain.bo.Letterbox;
|
||||
import com.dite.znpt.domain.bo.ODConfig;
|
||||
import com.dite.znpt.domain.entity.ModelConfigEntity;
|
||||
import com.dite.znpt.util.ModelUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.imgcodecs.Imgcodecs;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.*;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class MultiModelYoloService {
|
||||
|
||||
@Autowired
|
||||
private YoloModelRegistry registry;
|
||||
|
||||
public List<Detection> detect(String modelId, String inputFile, String outputFile, Float confThreshold) throws OrtException {
|
||||
OrtSession session = registry.getSession(modelId);
|
||||
YoloModelRegistry.ModelMetadata meta = registry.getMetadata(modelId);
|
||||
OrtEnvironment environment = registry.getEnvironment();
|
||||
ModelConfigEntity modelConfig = registry.getModelConfig(modelId);
|
||||
confThreshold = (Objects.isNull(confThreshold) ? modelConfig.getConfThreshold() : confThreshold) / 100;
|
||||
|
||||
Mat img = Imgcodecs.imread(inputFile);
|
||||
Mat image = img.clone();
|
||||
Imgproc.cvtColor(image, image, Imgproc.COLOR_BGR2RGB);
|
||||
|
||||
// 在这里先定义下框的粗细、字的大小、字的类型、字的颜色(按比例设置大小粗细比较好一些)
|
||||
int minDwDh = Math.min(img.width(), img.height());
|
||||
int thickness = minDwDh/ ODConfig.lineThicknessRatio;
|
||||
long start_time = System.currentTimeMillis();
|
||||
// 更改 image 尺寸
|
||||
Letterbox letterbox = new Letterbox();
|
||||
image = letterbox.letterbox(image);
|
||||
|
||||
double ratio = letterbox.getRatio();
|
||||
double dw = letterbox.getDw();
|
||||
double dh = letterbox.getDh();
|
||||
int rows = letterbox.getHeight();
|
||||
int cols = letterbox.getWidth();
|
||||
int channels = image.channels();
|
||||
|
||||
// 将Mat对象的像素值赋值给Float[]对象
|
||||
float[] pixels = new float[channels * rows * cols];
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < cols; j++) {
|
||||
double[] pixel = image.get(j,i);
|
||||
for (int k = 0; k < channels; k++) {
|
||||
// 这样设置相当于同时做了image.transpose((2, 0, 1))操作
|
||||
pixels[rows*cols*k+j*cols+i] = (float) pixel[k]/255.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建OnnxTensor对象
|
||||
long[] shape = { 1L, (long)channels, (long)rows, (long)cols };
|
||||
OnnxTensor tensor = OnnxTensor.createTensor(environment, FloatBuffer.wrap(pixels), shape);
|
||||
HashMap<String, OnnxTensor> stringOnnxTensorHashMap = new HashMap<>();
|
||||
stringOnnxTensorHashMap.put(session.getInputInfo().keySet().iterator().next(), tensor);
|
||||
|
||||
// 运行推理
|
||||
OrtSession.Result output = session.run(stringOnnxTensorHashMap);
|
||||
float[][] outputData = ((float[][][])output.get(0).getValue())[0];
|
||||
|
||||
outputData = ModelUtil.transposeMatrix(outputData);
|
||||
Map<Integer, List<float[]>> class2Bbox = new HashMap<>();
|
||||
|
||||
for (float[] bbox : outputData) {
|
||||
float[] conditionalProbabilities = Arrays.copyOfRange(bbox, 4, bbox.length);
|
||||
int label = ModelUtil.argmax(conditionalProbabilities);
|
||||
float conf = conditionalProbabilities[label];
|
||||
if (conf < confThreshold) continue;
|
||||
|
||||
bbox[4] = conf;
|
||||
|
||||
// xywh to (x1, y1, x2, y2)
|
||||
ModelUtil.xywh2xyxy(bbox);
|
||||
|
||||
// skip invalid predictions
|
||||
if (bbox[0] >= bbox[2] || bbox[1] >= bbox[3]) continue;
|
||||
|
||||
class2Bbox.putIfAbsent(label, new ArrayList<>());
|
||||
class2Bbox.get(label).add(bbox);
|
||||
}
|
||||
|
||||
List<Detection> detections = new ArrayList<>();
|
||||
for (Map.Entry<Integer, List<float[]>> entry : class2Bbox.entrySet()) {
|
||||
int label = entry.getKey();
|
||||
List<float[]> bboxes = entry.getValue();
|
||||
bboxes = ModelUtil.nonMaxSuppression(bboxes, modelConfig.getNmsThreshold());
|
||||
for (float[] bbox : bboxes) {
|
||||
String labelString = meta.getLabels()[label];
|
||||
detections.add(new Detection(labelString,entry.getKey(), Arrays.copyOfRange(bbox, 0, 4), bbox[4]));
|
||||
}
|
||||
}
|
||||
|
||||
// 打印检测结果并将图片写入指定目录
|
||||
for (Detection detection : detections) {
|
||||
float[] bbox = detection.getBbox();
|
||||
log.info(detection.toString());
|
||||
// 画框
|
||||
Point topLeft = new Point((bbox[0]-dw)/ratio, (bbox[1]-dh)/ratio);
|
||||
Point bottomRight = new Point((bbox[2]-dw)/ratio, (bbox[3]-dh)/ratio);
|
||||
Scalar color = new Scalar(meta.getColors().get(detection.getClsId()));
|
||||
Imgproc.rectangle(img, topLeft, bottomRight, color, thickness);
|
||||
// 框上写文字
|
||||
Point boxNameLoc = new Point((bbox[0]-dw)/ratio, (bbox[1]-dh-2)/ratio-3);
|
||||
|
||||
Imgproc.putText(img, detection.getLabel(), boxNameLoc, Imgproc.FONT_HERSHEY_SIMPLEX, 2.5, color, thickness);
|
||||
}
|
||||
log.info("检测{},发现{}处问题,耗时:{} ms.", inputFile, detections.size(), (System.currentTimeMillis() - start_time));
|
||||
|
||||
// 保存图像到输出目录
|
||||
Imgcodecs.imwrite(outputFile, img);
|
||||
return detections;
|
||||
}
|
||||
|
||||
public void runFolderDetection(String modelId, String inputFolder, String outputFolder, Float confThreshold) throws Exception {
|
||||
List<File> fileList = FileUtil.loopFiles(inputFolder, file -> {
|
||||
String extName = FileUtil.extName(file);
|
||||
return StrUtil.equalsAnyIgnoreCase(extName, "jpg", "png");
|
||||
});
|
||||
for (File file : fileList) {
|
||||
List<Detection> detections = detect(modelId, file.getAbsolutePath(), outputFolder+ FileUtil.FILE_SEPARATOR+FileUtil.getName(file), confThreshold);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -17,7 +17,6 @@ import com.dite.znpt.domain.vo.PartResp;
|
|||
import com.dite.znpt.enums.PartTypeEnum;
|
||||
import com.dite.znpt.exception.ServiceException;
|
||||
import com.dite.znpt.mapper.PartMapper;
|
||||
import com.dite.znpt.mapper.TurbineMapper;
|
||||
import com.dite.znpt.service.PartService;
|
||||
import com.dite.znpt.service.ProjectService;
|
||||
import com.dite.znpt.service.TurbineService;
|
||||
|
@ -35,7 +34,7 @@ import java.util.stream.Collectors;
|
|||
/**
|
||||
* @author huise23
|
||||
* @date 2025/04/11 23:17
|
||||
* @Description: 表服务实现类
|
||||
* @Description: 部件表服务实现类
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package com.dite.znpt.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.text.StrBuilder;
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
@ -10,20 +10,19 @@ import com.dite.znpt.constant.Message;
|
|||
import com.dite.znpt.domain.entity.AttachInfoEntity;
|
||||
import com.dite.znpt.domain.entity.ProjectTaskEntity;
|
||||
import com.dite.znpt.domain.vo.ProjectTaskListReq;
|
||||
import com.dite.znpt.domain.vo.ProjectTaskResp;
|
||||
import com.dite.znpt.domain.vo.ProjectTaskReq;
|
||||
import com.dite.znpt.domain.vo.ProjectTaskResp;
|
||||
import com.dite.znpt.domain.vo.ProjectTaskStartReq;
|
||||
import com.dite.znpt.enums.AttachBusinessTypeEnum;
|
||||
import com.dite.znpt.enums.ProjectTaskStateEnum;
|
||||
import com.dite.znpt.exception.ServiceException;
|
||||
import com.dite.znpt.mapper.ProjectTaskGroupMapper;
|
||||
import com.dite.znpt.mapper.ProjectTaskMapper;
|
||||
import com.dite.znpt.service.AttachInfoService;
|
||||
import com.dite.znpt.service.ProjectTaskService;
|
||||
import com.dite.znpt.mapper.ProjectTaskMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.dite.znpt.util.PageUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
@ -82,7 +81,7 @@ public class ProjectTaskServiceImpl extends ServiceImpl<ProjectTaskMapper, Proje
|
|||
projectTaskReq.setTaskId(taskId);
|
||||
|
||||
List<ProjectTaskResp> list = selectList(projectTaskReq);
|
||||
return list.isEmpty() ? CollUtil.getFirst(list) : new ProjectTaskResp();
|
||||
return CollUtil.isNotEmpty(list) ? CollUtil.getFirst(list) : new ProjectTaskResp();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package com.dite.znpt.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.dite.znpt.constant.Constants;
|
||||
import com.dite.znpt.constant.Message;
|
||||
import com.dite.znpt.domain.entity.VideoFileInfoEntity;
|
||||
import com.dite.znpt.domain.vo.VideoFileInfoListReq;
|
||||
|
@ -12,15 +12,13 @@ import com.dite.znpt.domain.vo.VideoFileInfoReq;
|
|||
import com.dite.znpt.domain.vo.VideoFileInfoResp;
|
||||
import com.dite.znpt.enums.FilePathEnum;
|
||||
import com.dite.znpt.exception.ServiceException;
|
||||
import com.dite.znpt.mapper.VideoFileInfoMapper;
|
||||
import com.dite.znpt.service.PartService;
|
||||
import com.dite.znpt.service.VideoFileInfoService;
|
||||
import com.dite.znpt.mapper.VideoFileInfoMapper;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.dite.znpt.util.PageUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
|
@ -120,7 +118,7 @@ public class VideoFileInfoServiceImpl extends ServiceImpl<VideoFileInfoMapper, V
|
|||
throw new ServiceException(Message.IMAGE_IS_EMPTY);
|
||||
}
|
||||
String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||
String path_prefix = FilePathEnum.VIDEO.getFileAbsolutePath().concat(dateStr).concat(FileUtil.FILE_SEPARATOR);
|
||||
String path_prefix = FilePathEnum.VIDEO.getFileAbsolutePathPrefix().concat(dateStr).concat(FileUtil.FILE_SEPARATOR);
|
||||
if (!FileUtil.exist(path_prefix)) {
|
||||
FileUtil.mkdir(path_prefix);
|
||||
}
|
||||
|
@ -129,7 +127,7 @@ public class VideoFileInfoServiceImpl extends ServiceImpl<VideoFileInfoMapper, V
|
|||
VideoFileInfoEntity info = BeanUtil.copyProperties(infoReq, VideoFileInfoEntity.class);
|
||||
String path = path_prefix + multipartFile.getOriginalFilename();
|
||||
FileUtil.writeBytes(multipartFile.getBytes(), path);
|
||||
info.setFilePath(FilePathEnum.VIDEO.getUrlPath() + StrUtil.removePrefix(path, FilePathEnum.VIDEO.getFileAbsolutePath()).replace(FileUtil.FILE_SEPARATOR, StrUtil.SLASH));
|
||||
info.setFilePath(FilePathEnum.VIDEO.getUrlPath() + StrUtil.removePrefix(path, FilePathEnum.VIDEO.getFileAbsolutePathPrefix()).replace(FileUtil.FILE_SEPARATOR, StrUtil.SLASH));
|
||||
result.add(info);
|
||||
}
|
||||
baseMapper.insert(result);
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
package com.dite.znpt.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ModelUtil {
|
||||
|
||||
public static void xywh2xyxy(float[] bbox) {
|
||||
float x = bbox[0];
|
||||
float y = bbox[1];
|
||||
float w = bbox[2];
|
||||
float h = bbox[3];
|
||||
|
||||
bbox[0] = x - w * 0.5f;
|
||||
bbox[1] = y - h * 0.5f;
|
||||
bbox[2] = x + w * 0.5f;
|
||||
bbox[3] = y + h * 0.5f;
|
||||
}
|
||||
|
||||
public static float[][] transposeMatrix(float[][] m) {
|
||||
float[][] temp = new float[m[0].length][m.length];
|
||||
for (int i = 0; i < m.length; i++)
|
||||
for (int j = 0; j < m[0].length; j++)
|
||||
temp[j][i] = m[i][j];
|
||||
return temp;
|
||||
}
|
||||
|
||||
//返回最大值的索引
|
||||
public static int argmax(float[] a) {
|
||||
float re = -Float.MAX_VALUE;
|
||||
int arg = -1;
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
if (a[i] >= re) {
|
||||
re = a[i];
|
||||
arg = i;
|
||||
}
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
public static List<float[]> nonMaxSuppression(List<float[]> bboxes, float iouThreshold) {
|
||||
|
||||
List<float[]> bestBboxes = new ArrayList<>();
|
||||
|
||||
bboxes.sort(Comparator.comparing(a -> a[4]));
|
||||
|
||||
while (!bboxes.isEmpty()) {
|
||||
float[] bestBbox = bboxes.remove(bboxes.size() - 1);
|
||||
bestBboxes.add(bestBbox);
|
||||
bboxes = bboxes.stream().filter(a -> computeIOU(a, bestBbox) < iouThreshold).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
return bestBboxes;
|
||||
}
|
||||
|
||||
public static float computeIOU(float[] box1, float[] box2) {
|
||||
|
||||
float area1 = (box1[2] - box1[0]) * (box1[3] - box1[1]);
|
||||
float area2 = (box2[2] - box2[0]) * (box2[3] - box2[1]);
|
||||
|
||||
float left = Math.max(box1[0], box2[0]);
|
||||
float top = Math.max(box1[1], box2[1]);
|
||||
float right = Math.min(box1[2], box2[2]);
|
||||
float bottom = Math.min(box1[3], box2[3]);
|
||||
|
||||
float interArea = Math.max(right - left, 0) * Math.max(bottom - top, 0);
|
||||
float unionArea = area1 + area2 - interArea;
|
||||
return Math.max(interArea / unionArea, 1e-8f);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.dite.znpt.mapper.ModelConfigMapper">
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
a.model_id, a.model_name, a.model_path, a.conf_threshold,
|
||||
a.nms_threshold, a.update_by, a.create_time, a.create_by,
|
||||
a.update_time
|
||||
</sql>
|
||||
|
||||
<select id="queryBySelective" resultType="com.dite.znpt.domain.vo.ModelConfigResp">
|
||||
select
|
||||
<include refid="Base_Column_List"/>
|
||||
from model_config a
|
||||
<where>
|
||||
<if test="modelId != null and modelId != ''">
|
||||
and a.model_id = #{modelId}
|
||||
</if>
|
||||
<if test="modelName != null and modelName != ''">
|
||||
and a.model_name like concat ('%', #{modelName}, '%')
|
||||
</if>
|
||||
<if test="modelPath != null and modelPath != ''">
|
||||
and a.model_path like concat ('%', #{modelPath}, '%')
|
||||
</if>
|
||||
<if test="confThreshold != null">
|
||||
and a.conf_threshold >= #{confThreshold}
|
||||
</if>
|
||||
<if test="nmsThreshold != null">
|
||||
and a.nms_threshold >= #{nmsThreshold}
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
package com.dite.znpt.web.controller;
|
||||
|
||||
|
||||
import com.dite.znpt.config.YoloModelRegistry;
|
||||
import com.dite.znpt.domain.PageResult;
|
||||
import com.dite.znpt.domain.Result;
|
||||
import com.dite.znpt.domain.vo.ModelConfigListReq;
|
||||
import com.dite.znpt.domain.vo.ModelConfigReq;
|
||||
import com.dite.znpt.domain.vo.ModelConfigResp;
|
||||
import com.dite.znpt.service.ModelConfigService;
|
||||
import com.dite.znpt.service.impl.MultiModelYoloService;
|
||||
import com.dite.znpt.util.ValidationGroup;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @author huise23
|
||||
* @date 2025/07/02 21:21
|
||||
*/
|
||||
@Api(tags = "模型配置")
|
||||
@RestController
|
||||
@RequestMapping("/model-config")
|
||||
public class ModelConfigController {
|
||||
@Resource
|
||||
private ModelConfigService modelConfigService;
|
||||
@Resource
|
||||
private YoloModelRegistry registry;
|
||||
@Autowired
|
||||
private MultiModelYoloService multiModelYoloService;
|
||||
|
||||
@ApiOperation(value = "获取列表", httpMethod = "GET")
|
||||
@GetMapping("/list")
|
||||
public PageResult<ModelConfigResp> list(ModelConfigListReq modelConfigReq) {
|
||||
return PageResult.ok(modelConfigService.selectList(modelConfigReq));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "根据Id获取详细信息", httpMethod = "GET")
|
||||
@GetMapping("/{modelId}")
|
||||
public Result<ModelConfigResp> getInfo(@PathVariable String modelId) {
|
||||
return Result.ok(modelConfigService.selectById(modelId));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "新增", httpMethod = "POST")
|
||||
@PostMapping
|
||||
public Result<Object> add(@Validated(ValidationGroup.Insert.class) @RequestBody ModelConfigReq modelConfigReq) {
|
||||
modelConfigService.saveData(modelConfigReq);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@ApiOperation(value = "修改", httpMethod = "PUT")
|
||||
@PutMapping
|
||||
public Result<Object> edit(@Validated(ValidationGroup.Update.class) @RequestBody ModelConfigReq modelConfigReq) {
|
||||
modelConfigService.updateData(modelConfigReq);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@ApiOperation(value = "删除", httpMethod = "DELETE")
|
||||
@DeleteMapping("/{modelId}")
|
||||
public Result<Object> remove(@PathVariable String modelId) {
|
||||
modelConfigService.deleteById(modelId);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@PostMapping("/run")
|
||||
public ResponseEntity<String> runBatch(@RequestParam("modelId") String modelId,
|
||||
@RequestParam("inputDir") String inputDir,
|
||||
@RequestParam("outputDir") String outputDir,
|
||||
@RequestParam("confThreshold") Float confThreshold) {
|
||||
try {
|
||||
multiModelYoloService.runFolderDetection(modelId, inputDir, outputDir, confThreshold);
|
||||
return ResponseEntity.ok("批量推理完成");
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.status(500).body("处理失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue