diff --git a/src/main/java/com/example/lxcameraapi/controller/YoloController.java b/src/main/java/com/example/lxcameraapi/controller/YoloController.java new file mode 100644 index 0000000..2b75c8c --- /dev/null +++ b/src/main/java/com/example/lxcameraapi/controller/YoloController.java @@ -0,0 +1,205 @@ +package com.example.lxcameraapi.controller; + +import ai.onnxruntime.OrtException; +import com.example.lxcameraapi.conf.AppConfig; +import com.example.lxcameraapi.service.IndustrialCamera.algorithm.ONNXServiceNew; +import com.example.lxcameraapi.service.IndustrialCamera.camera.lx.LxPointCloudSaveImage; +import com.example.lxcameraapi.service.IndustrialCamera.algorithm.BoxPositionConf; +import com.example.lxcameraapi.service.IndustrialCamera.algorithm.PcdPojo; +import com.example.lxcameraapi.service.IndustrialCamera.algorithm.PointCloudProcessor; +import com.example.lxcameraapi.service.IndustrialCamera.pojo.Pojo; +import com.example.lxcameraapi.yolo.BoundingBox; +import com.example.lxcameraapi.yolo.ClassifyEntity; +import io.swagger.models.auth.In; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.io.IOException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; + +import static com.example.lxcameraapi.controller.HikController.DATE_FORMATTER; +import static com.example.lxcameraapi.controller.HikController.TIME_FORMATTER; + +@Slf4j +@RestController +@RequestMapping("/yolo") +public class YoloController { + @Resource + AppConfig appConfig; + + @Resource + ONNXServiceNew onnxServiceNew; + + @GetMapping("/detect") + public Pojo detect(String pic,String type) throws IOException { + Pojo pojo = new Pojo(); + try { + List list = onnxServiceNew.detect(pic,type); + Integer index = ONNXServiceNew.getMaxClassIndex(list); + if (appConfig.getYoloModelConfig().getModelMap().containsKey(type)){ + + pojo.setCode(appConfig.getYoloModelConfig().getModelMap().get(type).getNames()[index]); + }else { + pojo.setCode(appConfig.getYoloModelConfig().getNames()[index]); + } + } catch (OrtException e) { + throw new RuntimeException(e); + } + + + return pojo; + } + + @GetMapping("/detect") + public ClassifyEntity classifyOne(String pic,String type) throws IOException { + ClassifyEntity classifyEntity = null; + try { + classifyEntity = onnxServiceNew.classifyOne(pic,type); + } catch (OrtException e) { + throw new RuntimeException(e); + } + + + return classifyEntity; + } + + @GetMapping("/getBoxCountByCategory") + public int getBoxCountByCategory(String streetId,String category) throws IOException { + + if(category.equals("20")){ + return 1; + } + + String path =streetId+"\\" + + LocalDate.now().format(DATE_FORMATTER) + +"\\"+category+"_"+ LocalDateTime.now().format(TIME_FORMATTER) +"_"; + List cameras = appConfig.getLxCamera(); + int i = 0; + Map map = new HashMap<>(); + System.out.println(appConfig.getSpecialBox().toString()); + for (AppConfig.SpecialBox specialBox:appConfig.getSpecialBox()){ + System.out.println(category.equals(specialBox.getCategory())); + if (category.equals(specialBox.getCategory())){ + map.put(specialBox.getCameraId(),specialBox.getComputeConfPath()); + System.out.println(specialBox.getCameraId()+" "+specialBox.getComputeConfPath()); + } + } + if (!map.isEmpty()){ + log.info("map: {}", map); + System.out.println("map: "+map); + for (Integer cameraId:map.keySet()) { + for (AppConfig.Camera c : cameras) { + if (Objects.equals(c.getId(), cameraId)) { + + log.info("cameraId: {}, path: {}", cameraId, path +"_"+c.getId()+ ".pcd"); + LxPointCloudSaveImage.saveImage(c.getIp(), path +"_"+c.getId()+ ".pcd"); + PcdPojo pojo = new PcdPojo(); + pojo.setPcd1(path + "_"+c.getId()+ ".pcd"); + pojo.setConfigPath(c.getConvertConfPath()); + try { + pojo.setPCDInfo(pojo); + } catch (IOException e) { + throw new RuntimeException(e); + } + PointCloudProcessor pointCloudProcessor = new PointCloudProcessor(); + List confs = pointCloudProcessor.getBoxPositionConf(map.get(c.getId())); + i += pointCloudProcessor.slicing(pojo, confs); + } + } + } + }else { + for (AppConfig.Camera c : cameras) { + if (streetId.equals(c.getStreetId())) { + + log.info("cameraId: {}, path: {}", c.getId(), path +"_"+c.getId()+ ".pcd"); + LxPointCloudSaveImage.saveImage(c.getIp(), path +"_"+c.getId()+ ".pcd"); + PcdPojo pojo = new PcdPojo(); + pojo.setPcd1(path + "_"+c.getId()+ ".pcd"); + pojo.setConfigPath(c.getConvertConfPath()); + try { + pojo.setPCDInfo(pojo); + } catch (IOException e) { + throw new RuntimeException(e); + } + PointCloudProcessor pointCloudProcessor = new PointCloudProcessor(); + List confs = pointCloudProcessor.getBoxPositionConf(c.getComputeConfPath()); + i += pointCloudProcessor.slicing(pojo, confs); + } + } + } + + return i; + } + + + @GetMapping("/getBoxCountByCategoryTest") + public int getBoxCountByCategoryTest(String streetId,String category,String path1,String path2) throws IOException { + if(category.equals("20")){ + return 1; + } + + List cameras = appConfig.getLxCamera(); + int i = 0; + Map map = new HashMap(); + for (AppConfig.SpecialBox specialBox:appConfig.getSpecialBox()){ + if (category.equals(specialBox.getCategory())){ + map.put(specialBox.getCameraId(),specialBox.getComputeConfPath()); + } + } + if (!map.isEmpty()){ + for (Integer cameraId:map.keySet()) { + for (AppConfig.Camera c : cameras) { + if (Objects.equals(c.getId(), cameraId)) { +// LxPointCloudSaveImage.saveImage(c.getIp(), path1); + PcdPojo pojo = new PcdPojo(); + if (c.getId()==1) { + pojo.setPcd1(path1); + }else { + pojo.setPcd1(path2); + } + pojo.setConfigPath(c.getConvertConfPath()); + try { + pojo.setPCDInfo(pojo); + } catch (IOException e) { + throw new RuntimeException(e); + } + PointCloudProcessor pointCloudProcessor = new PointCloudProcessor(); + List confs = pointCloudProcessor.getBoxPositionConf(map.get(c.getId())); + i += pointCloudProcessor.slicing(pojo, confs); + } + } + } + }else { + for (AppConfig.Camera c : cameras) { + if (streetId.equals(c.getStreetId())) { + String sn = UUID.randomUUID().toString(); + + PcdPojo pojo = new PcdPojo(); + if (c.getId()==1) { + pojo.setPcd1(path1); + }else { + pojo.setPcd1(path2); + } + pojo.setConfigPath(c.getConvertConfPath()); + try { + pojo.setPCDInfo(pojo); + } catch (IOException e) { + throw new RuntimeException(e); + } + PointCloudProcessor pointCloudProcessor = new PointCloudProcessor(); + List confs = pointCloudProcessor.getBoxPositionConf(c.getComputeConfPath()); + i += pointCloudProcessor.slicing(pojo, confs); + } + } + } + + return i; + } + +} diff --git a/src/main/java/com/example/lxcameraapi/service/IndustrialCamera/algorithm/PcdPojo.java b/src/main/java/com/example/lxcameraapi/service/IndustrialCamera/algorithm/PcdPojo.java index 93183fa..415b747 100644 --- a/src/main/java/com/example/lxcameraapi/service/IndustrialCamera/algorithm/PcdPojo.java +++ b/src/main/java/com/example/lxcameraapi/service/IndustrialCamera/algorithm/PcdPojo.java @@ -29,6 +29,9 @@ public class PcdPojo { //随行路径 configProperties.getSavePath().getMediaPath() + street.getLeft3D()+"000/"+ currentDate.format(formatter)+"/"+transmissionPojo.getRow()+".pcd"; private String pcd1; private String pcd2; + private Integer functionType = 1;//1 中位数 2 平均值 3 正态分布 + private Integer fluctuate= 80; + private String pcd4; private String cameraSn1; private String cameraSn2; diff --git a/src/main/java/com/example/lxcameraapi/service/IndustrialCamera/algorithm/PointCloudProcessor.java b/src/main/java/com/example/lxcameraapi/service/IndustrialCamera/algorithm/PointCloudProcessor.java index c0cb5aa..fac0ba7 100644 --- a/src/main/java/com/example/lxcameraapi/service/IndustrialCamera/algorithm/PointCloudProcessor.java +++ b/src/main/java/com/example/lxcameraapi/service/IndustrialCamera/algorithm/PointCloudProcessor.java @@ -3,6 +3,7 @@ package com.example.lxcameraapi.service.IndustrialCamera.algorithm; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; import org.opencv.core.Core; import org.opencv.core.CvType; import org.opencv.core.Mat; @@ -21,6 +22,7 @@ import java.util.*; import java.util.List; import java.util.stream.Collectors; +@Slf4j public class PointCloudProcessor { // @@ -235,6 +237,66 @@ public class PointCloudProcessor { return sum / (values.size() - 2 * trimCount); } + /** + * 根据 functionType 计算点云层高 + * + * @param zValues 层匹配范围内所有点的 z 坐标 + * @param functionType 1 中位数, 2 平均值, 3 正态分布(直方图峰值) + * @return 计算得到的层高,无数据时返回 NaN + */ + private static double calculateLayerHeight(List zValues, Integer functionType) { + if (zValues == null || zValues.isEmpty()) { + return Double.NaN; + } + int type = functionType == null ? 1 : functionType; + List sorted = new ArrayList<>(zValues); + sorted.sort(Comparator.naturalOrder()); + switch (type) { + case 2: // 平均值 + return sorted.stream().mapToDouble(Double::doubleValue).average().orElse(Double.NaN); + case 3: // 正态分布:直方图峰值 + return histogramPeak(sorted); + default: // 中位数 + int size = sorted.size(); + if (size % 2 == 1) { + return sorted.get(size / 2); + } + return (sorted.get(size / 2 - 1) + sorted.get(size / 2)) / 2.0; + } + } + + /** + * 正态分布:将数据分为多个区间,返回点数最多的区间中心值(近似峰值) + */ + private static double histogramPeak(List values) { + double min = values.get(0); + double max = values.get(values.size() - 1); + if (max - min < 1e-9) { + return min; + } + int bins = 100; // 直方图区间数 + double binWidth = (max - min) / bins; + int[] counts = new int[bins]; + double[] binCenter = new double[bins]; + for (int i = 0; i < bins; i++) { + binCenter[i] = min + (i + 0.5) * binWidth; + } + for (double v : values) { + int idx = (int) ((v - min) / binWidth); + if (idx >= bins) { + idx = bins - 1; + } + counts[idx]++; + } + int maxIdx = 0; + for (int i = 1; i < bins; i++) { + if (counts[i] > counts[maxIdx]) { + maxIdx = i; + } + } + return binCenter[maxIdx]; + } + public static List readPCD(String filePath) { try { if (isBinaryFormat(filePath)) { @@ -439,9 +501,9 @@ public class PointCloudProcessor { // pojo.setPcd1("D:\\data\\test\\1巷道\\F83C51123126\\3766_173016547__2.pcd"); // pojo.setConfigPath("D:\\data\\test\\1巷道\\F83C51123126\\cj.json"); // String pz = "D:\\data\\test\\1巷道\\F83C51123126\\pz.json"; - pojo.setPcd1("D:\\xwechat_files\\wxid_ttkf0xgmyihv22_2388\\msg\\file\\2026-07\\3766_173056141__2.pcd"); - pojo.setConfigPath("D:\\xwechat_files\\wxid_ttkf0xgmyihv22_2388\\msg\\file\\2026-07\\cj.json"); - String pz = "D:\\xwechat_files\\wxid_ttkf0xgmyihv22_2388\\msg\\file\\2026-07\\pz.json"; + pojo.setPcd1("D:\\desktop\\新建文件夹\\673\\0184_082322214__1.pcd"); + pojo.setConfigPath("D:\\desktop\\新建文件夹\\670\\cj.json"); + String pz = "D:\\desktop\\新建文件夹\\670\\pz.json"; try { pojo.setPCDInfo(pojo); @@ -616,7 +678,15 @@ public class PointCloudProcessor { System.out.println(" 第" + i + "层: height=" + conf.getHeight() + ", 盒子数=" + conf.getPosition().size()); } - // 计算每层的 Z 轴匹配范围(相邻层取中间值,首尾层留±300边距) + // 计算pcd1 + List points = readPCD(pojo.getPcd1()); + if (points == null || points.isEmpty()) { + System.out.println("点云数据为空!"); + return 0; + } + System.out.println("点云总点数: " + points.size()); + + // 1. 计算每层的初始 Z 轴匹配范围(相邻层取中间值,首尾层留±300边距) double[][] zRanges = new double[boxPositionConfs.size()][2]; for (int i = 0; i < boxPositionConfs.size(); i++) { double currentHeight = boxPositionConfs.get(i).getHeight(); @@ -633,16 +703,32 @@ public class PointCloudProcessor { zRanges[i][0] = (boxPositionConfs.get(i - 1).getHeight() + currentHeight) / 2.0; zRanges[i][1] = (currentHeight + boxPositionConfs.get(i + 1).getHeight()) / 2.0; } - System.out.println(" 第" + i + "层 Z范围: [" + zRanges[i][0] + ", " + zRanges[i][1] + "]"); + System.out.println(" 第" + i + "层 初始Z范围: [" + zRanges[i][0] + ", " + zRanges[i][1] + "]"); } - // 计算pcd1 - List points = readPCD(pojo.getPcd1()); - if (points == null || points.isEmpty()) { - System.out.println("点云数据为空!"); - return 0; + // 2. 根据每层初始匹配范围内的所有点,按 functionType 计算每层实际高度(1 中位数 / 2 平均值 / 3 正态分布) + // 3. 用计算得到的值 ± fluctuate 构成新的 Z 轴匹配范围 + int fluctuate = pojo.getFluctuate() == null ? 80 : pojo.getFluctuate(); + for (int i = 0; i < boxPositionConfs.size(); i++) { + List zValues = new ArrayList<>(); + for (double[] point : points) { + double[] rotated = rotatePoints(point, pojo.getRotationMatrix()); + if (rotated[2] >= zRanges[i][0] && rotated[2] <= zRanges[i][1]) { + zValues.add(rotated[2]); + } + } + double layerHeight = calculateLayerHeight(zValues, pojo.getFunctionType()); + if (Double.isNaN(layerHeight)) { + // 该层初始范围内没有点,沿用配置高度 + layerHeight = boxPositionConfs.get(i).getHeight(); + log.info(" 第" + i + "层 匹配范围内无点,沿用配置高度: " + layerHeight); + } else { + log.info(" 第" + i + "层 匹配点数=" + zValues.size() + ", 计算实际高度=" + layerHeight); + } + zRanges[i][0] = layerHeight - fluctuate; + zRanges[i][1] = layerHeight + fluctuate; + log.info(" 第" + i + "层 新Z范围(±" + fluctuate + "): [" + zRanges[i][0] + ", " + zRanges[i][1] + "]"); } - System.out.println("点云总点数: " + points.size()); Map map = new HashMap <>(); Map listMap = new HashMap<>(); @@ -697,7 +783,7 @@ public class PointCloudProcessor { count = baseCount; int currentLayerCount = 0; - System.out.println(">>> 检查第" +i + "层 (height=" + boxPositionConfs.get(i).getHeight() + log.info(">>> 检查第" +i + "层 (height=" + boxPositionConfs.get(i).getHeight() + ", Z范围=[" + zRanges[i][0] + "," + zRanges[i][1] + "], 盒子数=" + boxPositionConfs.get(i).getPosition().size() + "), baseCount=" + baseCount); @@ -709,11 +795,11 @@ public class PointCloudProcessor { count += 1; currentLayerCount++; } - System.out.println(" 盒子[" + (j+1 )+ "] position=" + position + ", 点数=" + pointCount + log.info(" 盒子[" + (j+1 )+ "] position=" + position + ", 点数=" + pointCount + (hasData ? " [有货]" : " [空]")); } - System.out.println(" 第" + i + "层有货盒子数: " + currentLayerCount + ", 累计count=" + count); + log.info(" 第" + i + "层有货盒子数: " + currentLayerCount + ", 累计count=" + count); if (count > baseCount) { System.out.println(">>> 在第" + i + "层发现货物,停止向上查找 <<<"); diff --git a/src/main/java/com/example/lxcameraapi/service/IndustrialCamera/pojo/Pojo.java b/src/main/java/com/example/lxcameraapi/service/IndustrialCamera/pojo/Pojo.java index ab5087f..18d4ddb 100644 --- a/src/main/java/com/example/lxcameraapi/service/IndustrialCamera/pojo/Pojo.java +++ b/src/main/java/com/example/lxcameraapi/service/IndustrialCamera/pojo/Pojo.java @@ -1,7 +1,10 @@ package com.example.lxcameraapi.service.IndustrialCamera.pojo; +import com.example.lxcameraapi.yolo.BoundingBox; import lombok.Data; +import java.util.List; + @Data public class Pojo { //旋转路径 @@ -10,4 +13,11 @@ public class Pojo { private String determinePath; //结果 private Boolean result; + private String code; + + private String type; + private List detects; + private String path; + private String streetId; + private Integer direction; }