diff --git a/libs/plc/LxCameraApi.lib b/libs/plc/LxCameraApi.lib new file mode 100644 index 0000000..5945191 Binary files /dev/null and b/libs/plc/LxCameraApi.lib differ diff --git a/libs/plc/LxCameraApiL.dll b/libs/plc/LxCameraApiL.dll new file mode 100644 index 0000000..4ea38c4 Binary files /dev/null and b/libs/plc/LxCameraApiL.dll differ diff --git a/libs/plc/LxCameraApiR.dll b/libs/plc/LxCameraApiR.dll new file mode 100644 index 0000000..4ea38c4 Binary files /dev/null and b/libs/plc/LxCameraApiR.dll differ diff --git a/libs/plc/LxDataProcess.dll b/libs/plc/LxDataProcess.dll new file mode 100644 index 0000000..923c8f5 Binary files /dev/null and b/libs/plc/LxDataProcess.dll differ diff --git a/libs/plc/Project1.exe b/libs/plc/Project1.exe new file mode 100644 index 0000000..698cf56 Binary files /dev/null and b/libs/plc/Project1.exe differ diff --git a/libs/plc/cameraapi.lib b/libs/plc/cameraapi.lib new file mode 100644 index 0000000..2eaa74d Binary files /dev/null and b/libs/plc/cameraapi.lib differ diff --git a/libs/plc/cameraapiR.dll b/libs/plc/cameraapiR.dll new file mode 100644 index 0000000..d94389d Binary files /dev/null and b/libs/plc/cameraapiR.dll differ diff --git a/libs/plc/opencv_world341.dll b/libs/plc/opencv_world341.dll new file mode 100644 index 0000000..293e9f3 Binary files /dev/null and b/libs/plc/opencv_world341.dll differ diff --git a/libs/plc/opencv_world341.lib b/libs/plc/opencv_world341.lib new file mode 100644 index 0000000..bad3632 Binary files /dev/null and b/libs/plc/opencv_world341.lib differ diff --git a/libs/plc/opencv_world341d.dll b/libs/plc/opencv_world341d.dll new file mode 100644 index 0000000..ace42c5 Binary files /dev/null and b/libs/plc/opencv_world341d.dll differ diff --git a/libs/plc/opencv_world341d.lib b/libs/plc/opencv_world341d.lib new file mode 100644 index 0000000..a5efe4b Binary files /dev/null and b/libs/plc/opencv_world341d.lib differ diff --git a/web/src/main/java/com/zhehekeji/web/controller/CategoryController.java b/web/src/main/java/com/zhehekeji/web/controller/CategoryController.java index db68c7a..ba8934b 100644 --- a/web/src/main/java/com/zhehekeji/web/controller/CategoryController.java +++ b/web/src/main/java/com/zhehekeji/web/controller/CategoryController.java @@ -5,6 +5,10 @@ import com.zhehekeji.core.pojo.Result; import com.zhehekeji.web.entity.Category; import com.zhehekeji.web.pojo.category.PageSearch; import com.zhehekeji.web.service.CategoryService; +import com.zhehekeji.web.service.IndustrialCamera.LxPointCloudSaveImage; +import com.zhehekeji.web.service.IndustrialCamera.algorithm.BoxPositionConf; +import com.zhehekeji.web.service.IndustrialCamera.algorithm.PcdPojo; +import com.zhehekeji.web.service.IndustrialCamera.algorithm.PointCloudProcessor; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.core.io.ClassPathResource; @@ -89,4 +93,25 @@ public class CategoryController { response.flushBuffer(); } + + + @GetMapping("/getBoxCount") + @ApiOperation(value = "个数获取") + public void getBoxCount(HttpServletResponse response) throws IOException { + LxPointCloudSaveImage.saveImage("192.168.1.82","E:\\1.pcd",1); + PcdPojo pojo = new PcdPojo(); + pojo.setPcd1("E:/1.pcd"); + pojo.setConfigPath("E:\\pe.json"); + try { + pojo.setPCDInfo(pojo); + } catch (IOException e) { + throw new RuntimeException(e); + } + PointCloudProcessor pointCloudProcessor = new PointCloudProcessor(); + List confs = pointCloudProcessor.getBoxPositionConf("E:\\peconf.json"); + int i = pointCloudProcessor.slicing(pojo,confs); + System.out.println(pojo.toString()); + System.out.println(i); + + } } diff --git a/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/CameraSaveUtil.java b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/CameraSaveUtil.java new file mode 100644 index 0000000..ef67264 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/CameraSaveUtil.java @@ -0,0 +1,12 @@ +package com.zhehekeji.web.service.IndustrialCamera; + +public interface CameraSaveUtil { + /** + * + * @param sn sn + * @param path 图片路径 + * @param type 暂时默认sn 后续可以添加ip等 + * @return + */ + boolean saveImage(String sn,String path,String type); +} diff --git a/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/DcLibrary.java b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/DcLibrary.java new file mode 100644 index 0000000..1d0af86 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/DcLibrary.java @@ -0,0 +1,50 @@ +package com.zhehekeji.web.service.IndustrialCamera; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.Structure; +import com.sun.jna.ptr.PointerByReference; + +import java.util.Arrays; +import java.util.List; +public interface DcLibrary extends Library { + DcLibrary INSTANCE = (DcLibrary) Native.load((System.getProperty("user.dir"))+"\\libs\\plc\\LxCameraApiR.dll", DcLibrary.class); + // 创建一个新的实例 + + // 设备详细信息结构体 + class LxDeviceInfo extends Structure { + public long handle; // 使用 long 类型表示 DcHandle + public short dev_type; + public byte[] id = new byte[32]; + public byte[] ip = new byte[32]; + public byte[] sn = new byte[32]; + public byte[] mac = new byte[32]; + public byte[] firmware_ver = new byte[32]; + public byte[] algor_ver = new byte[32]; + public byte[] name = new byte[32]; + public byte[] reserve = new byte[32]; + public byte[] reserve2 = new byte[32]; + public byte[] reserve3 = new byte[64]; + public byte[] reserve4 = new byte[128]; + + @Override + protected List getFieldOrder() { + return Arrays.asList("handle", "dev_type", "id", "ip", "sn", "mac", "firmware_ver", "algor_ver", "name", "reserve", "reserve2", "reserve3", "reserve4"); + } + } + + // 设备打开函数 + int DcOpenDevice(int open_mode, String param, PointerByReference handle, LxDeviceInfo info); + + String DcGetDeviceList(PointerByReference devlist, int devnum); + int DcCloseDevice(Pointer handle); + + int DcStartStream(Pointer handle); + + int DcStopStream(Pointer handle); + + int DcSaveXYZ(Pointer handle, String filename); + int DcSetCmd(Pointer handle, int cmd); +} +// Define LX_OPEN_MODE as an enum or int based on your C definition diff --git a/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/LxPointCloudSaveImage.java b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/LxPointCloudSaveImage.java new file mode 100644 index 0000000..825f695 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/LxPointCloudSaveImage.java @@ -0,0 +1,111 @@ +package com.zhehekeji.web.service.IndustrialCamera; + +import com.sun.jna.Native; +import com.sun.jna.ptr.PointerByReference; +import lombok.extern.slf4j.Slf4j; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Slf4j +public class LxPointCloudSaveImage { + + static DcLibrary INSTANCER = (DcLibrary) Native.loadLibrary((System.getProperty("user.dir"))+"\\libs\\plc\\LxCameraApiR.dll", DcLibrary.class); + static DcLibrary INSTANCEL = (DcLibrary) Native.loadLibrary((System.getProperty("user.dir"))+"\\libs\\plc\\LxCameraApiL.dll", DcLibrary.class); + + static Map handleMap = new ConcurrentHashMap<>(); + public static PointerByReference getHandle(String sn,int type ,DcLibrary INSTANCE){ + if(handleMap.get(sn)!=null){ + return handleMap.get(sn); + }else { + // 创建 Pointer 的引用 + PointerByReference handleRef = new PointerByReference(); + + + // 创建 PointerByReference 的实例用于接收设备列表 + // PointerByReference devlistRef = new PointerByReference(); + // 创建 LxDeviceInfo 实例 + DcLibrary.LxDeviceInfo info = new DcLibrary.LxDeviceInfo(); + + //library.DcGetDeviceList( devlistRef,0); + + // 调用 DcOpenDevice 函数 + System.out.println(sn+" "+handleRef+" "+info); + int result = INSTANCE.DcOpenDevice(1, sn, handleRef, info); + int i = 0; + if(result ==0) { + handleMap.put(sn, handleRef); + }else { + for (int ii=0;i<50;i++ ) { + result = INSTANCE.DcOpenDevice(1, sn, handleRef, info); + System.out.println(i + "次尝试"); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + // 输出结果 + System.out.println("Result: " + result); + System.out.println("Handle: " + handleRef.getValue()); // 获取 DcHandle 的值 + System.out.println("Device Type: " + info.dev_type); + System.out.println("ID: " + new String(info.id).trim()); + System.out.println("IP: " + new String(info.ip).trim()); + System.out.println("SN: " + new String(info.sn).trim()); + System.out.println("MAC: " + new String(info.mac).trim()); + System.out.println("Firmware Version: " + new String(info.firmware_ver).trim()); + System.out.println("Algorithm Version: " + new String(info.algor_ver).trim()); + System.out.println("Name: " + new String(info.name).trim()); + System.out.println("Reserve: " + new String(info.reserve).trim()); + System.out.println("Reserve2: " + new String(info.reserve2).trim()); + System.out.println("Reserve3: " + new String(info.reserve3).trim()); + System.out.println("Reserve4: " + new String(info.reserve4).trim());//lxPointCloudApi.DcCloseDevice(handle); + + + return handleRef; + } + + } + public static boolean saveImage(String sn, String path,int type) { + DcLibrary INSTANCE; + if (type==1){ + INSTANCE = INSTANCER; + }else { + INSTANCE = INSTANCEL; + } + int result = 0; + PointerByReference handleRef = getHandle(sn,type,INSTANCE); + result = INSTANCE.DcStartStream(handleRef.getValue()); + System.out.println("Result: " + result); + result = INSTANCE.DcSetCmd(handleRef.getValue(),5001); + + + System.out.println("Result: " + result); + Path path1 = Paths.get(path); + + try { + // 如果路径不存在,则创建目录 + Files.createDirectories(path1.getParent()); + }catch (Exception e){ + log.info("路径失败"); + } + int i = INSTANCE.DcSaveXYZ(handleRef.getValue(), path); + log.info(sn+" 3dCamera get pcd :"+path +";rest:"+i); + System.out.println(sn+" 3dCamera get pcd :"+path +";rest:"+i); + result = INSTANCE.DcStopStream(handleRef.getValue()); + + System.out.println("stop Stream Result: " + result); + + return true; + } + + public static void main(String[] args) { + saveImage("1","E:\\1-8-2-R.pcd",1); + + saveImage("2","E:\\12-R.pcd",2); + } +} diff --git a/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/algorithm/BoxPositionConf.java b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/algorithm/BoxPositionConf.java new file mode 100644 index 0000000..bcfb1c4 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/algorithm/BoxPositionConf.java @@ -0,0 +1,11 @@ +package com.zhehekeji.web.service.IndustrialCamera.algorithm; + +import lombok.Data; + +import java.util.List; + +@Data +public class BoxPositionConf { + Double height; + List position; +} diff --git a/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/algorithm/PCDReader.java b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/algorithm/PCDReader.java new file mode 100644 index 0000000..2f6ee3f --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/algorithm/PCDReader.java @@ -0,0 +1,77 @@ +package com.zhehekeji.web.service.IndustrialCamera.algorithm; + + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class PCDReader { + + public static void main(String[] args) { + String filePath = "path/to/your/file.pcd"; + try { + if (isBinaryFormat(filePath)) { + readBinaryPCD(filePath); + } else { + readAsciiPCD(filePath); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static boolean isBinaryFormat(String filePath) throws IOException { + try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { + String line; + while ((line = reader.readLine()) != null) { + if (line.startsWith("DATA")) { + return line.contains("binary"); + } + } + } + return false; + } + + private static void readAsciiPCD(String filePath) throws IOException { + try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { + String line; + while ((line = reader.readLine()) != null) { + if (!line.startsWith("#") && !line.startsWith("FIELDS") && !line.startsWith("SIZE") && + !line.startsWith("TYPE") && !line.startsWith("COUNT") && !line.startsWith("WIDTH") && + !line.startsWith("HEIGHT") && !line.startsWith("VIEWPOINT") && !line.startsWith("POINTS") && + !line.startsWith("DATA")) { + String[] values = line.split(" "); + for (String value : values) { + System.out.println(value); + } + } + } + } + } + + private static void readBinaryPCD(String filePath) throws IOException { + try (FileInputStream fis = new FileInputStream(filePath)) { + ByteBuffer buffer = ByteBuffer.wrap(fis.readAllBytes()); + buffer.order(ByteOrder.LITTLE_ENDIAN); + // Skip header (assuming 11 lines of header; adjust if needed) + for (int i = 0; i < 11; i++) { + while (buffer.get() != '\n') { + // Skip header lines + } + } + // Read binary data (assuming float x, y, z and int rgb) + while (buffer.hasRemaining()) { + float x = buffer.getFloat(); + float y = buffer.getFloat(); + float z = buffer.getFloat(); + int rgb = buffer.getInt(); // Read 4 bytes for RGB + System.out.printf("x: %f, y: %f, z: %f, rgb: %d%n", x, y, z, rgb); + } + } + } + + +} diff --git a/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/algorithm/PcdPojo.java b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/algorithm/PcdPojo.java new file mode 100644 index 0000000..bc64b12 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/algorithm/PcdPojo.java @@ -0,0 +1,53 @@ +package com.zhehekeji.web.service.IndustrialCamera.algorithm; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Data; + +import java.io.File; +import java.io.IOException; + +@Data +public class PcdPojo { + + double[][] rotationMatrix = { + {0.9982215762138367, 0.057795289903879166, 0.014606773853302002}, + {-0.0510917492210865, 0.7032182216644287, 0.7091360092163086}, + {0.030712969601154327, -0.7086211442947388, 0.7049204111099243} + }; // 这里使用给定的旋转矩阵 + double[] minBounds = {-905.5771484375, 174.71572875976562, 69.14165496826172}; // 裁剪最小值 + double[] maxBounds = {321.80609130859375, 1170.4776611328125, 1199.3507080078125}; // 裁剪最大值 + + + private double floorHeight; + + private double[] max_pt; + private double[] min_pt; + private double[] rotation; + //路径D://config//3DConfig/"+相机sn+".json" + private String configPath; + //盘点路径 configProperties.getSavePath().getMediaPath() + street.getLeft3D()+ currentDate.format(formatter)+"/"+transmissionPojo.getCheckId()+".pcd"; + //随行路径 configProperties.getSavePath().getMediaPath() + street.getLeft3D()+"000/"+ currentDate.format(formatter)+"/"+transmissionPojo.getRow()+".pcd"; + private String pcd1; + private String pcd2; + + private String cameraSn1; + private String cameraSn2; + private Integer count; + public PcdPojo setPCDInfo(PcdPojo pojo) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + + // 读取 JSON 文件并转换为 配置信息 + PcdPojo pojoIn = mapper.readValue(new File(pojo.getConfigPath()), mapper.getTypeFactory().constructType(PcdPojo.class)); + + this.setMinBounds(pojoIn.getMin_pt()); + this.setMaxBounds(pojoIn.getMax_pt()); + double[] x = {pojoIn.getRotation()[0], pojoIn.getRotation()[1], pojoIn.getRotation()[2]}; + double[] y = {pojoIn.getRotation()[3], pojoIn.getRotation()[4], pojoIn.getRotation()[5]}; + double[] z = {pojoIn.getRotation()[6], pojoIn.getRotation()[7], pojoIn.getRotation()[8]}; + this.setRotationMatrix(new double[][]{x, y, z}); + return this; + } + +} diff --git a/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/algorithm/PointCloudProcessor.java b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/algorithm/PointCloudProcessor.java new file mode 100644 index 0000000..4879d4c --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/algorithm/PointCloudProcessor.java @@ -0,0 +1,501 @@ +package com.zhehekeji.web.service.IndustrialCamera.algorithm; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.zhehekeji.web.service.IndustrialCamera.LxPointCloudSaveImage; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.text.DecimalFormat; +import java.util.*; +import java.util.stream.Collectors; + +public class PointCloudProcessor { + +// +// public static void main(String[] args) { +// PcdPojo pojo = new PcdPojo(); +// pojo.setPcd1("D:\\WeChet\\WeChat Files\\wxid_ttkf0xgmyihv22\\FileStorage\\File\\2024-09\\8-6-2-L.pcd"); +// pojo.setPcd2("D:\\WeChet\\WeChat Files\\wxid_ttkf0xgmyihv22\\FileStorage\\File\\2024-09\\369.pcd"); +// pojo.setConfigPath("E:\\D91FCF1FAB3568DB.json"); +// double i = similarity(pojo,10); +// System.out.println("111 "+i); +// } + + /** + * 计算两个pcd的相似性 + * + * @param pojo 必须有两个pcd文件路径,和一个配置文件 + * @return + */ + //计算两个pcd的相似性 +// public static double similarity(PcdPojo pojo) { +// +// ObjectMapper mapper = new ObjectMapper(); +// +// try { +// // 读取 JSON 文件并转换为 配置信息 +// PcdPojo pojoIn = mapper.readValue(new File(pojo.getConfigPath()), mapper.getTypeFactory().constructType(PcdPojo.class)); +// +// +// // 打印转换后的实体类列表 +// pojo = pojo.setPCDInfo(pojoIn); +// +// //报错则认为没有配置文件,返回盘点失败 +// } catch (JsonMappingException e) { +// e.printStackTrace(); +// return 0; +// } catch (JsonProcessingException e) { +// e.printStackTrace(); +// return 0; +// } catch (IOException e) { +// e.printStackTrace(); +// return 0; +// } +// System.out.println(pojo.toString()); +// // 计算pcd1 +// List points = readPCD(pojo.getPcd1()); +// if (points == null || points.isEmpty()) { +// return 0; +// } +// +// // 创建一个DecimalFormat对象,指定格式 +// DecimalFormat df = new DecimalFormat("#.#"); +// //map xyz +// PcdPojo finalPojo = pojo; +// Map> clippedPoint = points.stream() +// .map(point -> { +// //旋转 +// return rotatePoints(point, finalPojo.getRotationMatrix()); +// +// }) +// .filter(point -> +// //截取 +// clipPoints(point, finalPojo.getMinBounds(), finalPojo.getMaxBounds()) +// )//z轴截取 +// .collect(Collectors.groupingBy(point -> point[0], Collectors.toMap(point -> point[1], point -> point[2], (a, b) -> { +// return a > b ? a : b; +// }))); +// //计算x,y轴平均值 +// Double xAge = clippedPoint.keySet().stream().collect(Collectors.averagingDouble(v -> v)); +// Double yAge = clippedPoint.values().stream().flatMap(map -> map.values().stream()).collect(Collectors.averagingDouble(v -> v)); +// +// //计算pcd2 +// List points2 = readPCD(pojo.getPcd2()); +// if (points2 == null || points2.isEmpty()) { +// return 0; +// } +// +// //map xyz +// Map> clippedPoint2 = points2.stream() +// .map(point -> { +// //旋转 +// return rotatePoints(point, finalPojo.getRotationMatrix()); +// +// }) +// .filter(point -> +// //截取 +// clipPoints(point, finalPojo.getMinBounds(), finalPojo.getMaxBounds()) +// )//z轴截取 +// .collect(Collectors.groupingBy(point -> point[0], Collectors.toMap(point -> point[1], point -> point[2], (a, b) -> { +// return a > b ? a : b; +// }))); +// +// //计算x,y轴平均值 +// Double xAge2 = clippedPoint2.keySet().stream().collect(Collectors.averagingDouble(v -> v)); +// Double yAge2 = clippedPoint2.values().stream().flatMap(map -> map.values().stream()).collect(Collectors.averagingDouble(v -> v)); +// //计算相似度 +// return (Math.abs(yAge) < Math.abs(yAge2) ? Math.abs(yAge) / Math.abs(yAge2) : Math.abs(yAge2) / Math.abs(yAge)); +// } + + public static double similarity(PcdPojo pojo,int i) { + ObjectMapper mapper = new ObjectMapper(); + try { + // 读取 JSON 文件并转换为 配置信息 + // PcdPojo pojoIn = mapper.readValue(new File(pojo.getConfigPath()), mapper.getTypeFactory().constructType(PcdPojo.class)); + // 打印转换后的实体类列表 + pojo = pojo.setPCDInfo(pojo); + //报错则认为没有配置文件,返回盘点失败 + } catch (JsonMappingException e) { + e.printStackTrace(); + return 0; + } catch (JsonProcessingException e) { + e.printStackTrace(); + return 0; + } catch (IOException e) { + e.printStackTrace(); + return 0; + } + System.out.println(pojo.toString()); + // 计算pcd1 + List points = readPCD(pojo.getPcd1()); + if (points == null || points.isEmpty()) { + return 0; + } + + //计算pcd2 + List points2 = readPCD(pojo.getPcd2()); + if (points2 == null || points2.isEmpty()) { + return 0; + } + + //计算相似度 + return calculateTruncatedMeans(points,points2,pojo,i,new ArrayList<>()); + } + + + /** + * 计算每个子区域内的 y 坐标的截断均值 + * + * @param pointCloud 点云列表 + * @param divisions 每边分割的数量 + * @return 一个列表,其中每个元素是一个长度为3的一维数组,表示每个子区域的左下角坐标、右上角坐标和该区域内的 y 坐标的截断均值 + */ + public static double calculateTruncatedMeans(List pointCloud, List pointCloud2,PcdPojo pojo, int divisions,List results) { + + double width = (pojo.getMaxBounds()[0] - pojo.getMinBounds()[0]) / divisions; // 每个小方块的宽度 + double depth = (pojo.getMaxBounds()[2] - pojo.getMinBounds()[2]) / divisions; // 每个小方块的深度 + int count = 0; + int countSum = 0; + for (int i = 0; i < divisions; i++) { + for (int j = 0; j < divisions; j++) { + double leftBottomX = pojo.getMinBounds()[0] + i * width; // 左下角 x 坐标 + double leftBottomZ = pojo.getMinBounds()[2] + j * depth; // 左下角 z 坐标 + double rightTopX = pojo.getMinBounds()[0] + (i + 1) * width; // 右上角 x 坐标 + double rightTopZ = pojo.getMinBounds()[2] + (j + 1) * depth; // 右上角 z 坐标 + + List yValues = new ArrayList<>(); + for (double[] point : pointCloud) { + point = rotatePoints(point, pojo.getRotationMatrix()); + if(clipPoints(point, pojo.getMinBounds(), pojo.getMaxBounds())) { + if (point[0] >= leftBottomX && point[0] < rightTopX && + point[2] >= leftBottomZ && point[2] < rightTopZ) { + yValues.add(point[1]); + } + } + } + + List yValues2 = new ArrayList<>(); + for (double[] point : pointCloud2) { + point = rotatePoints(point, pojo.getRotationMatrix()); + if(clipPoints(point, pojo.getMinBounds(), pojo.getMaxBounds())) { + if (point[0] >= leftBottomX && point[0] < rightTopX && + point[2] >= leftBottomZ && point[2] < rightTopZ) { + yValues2.add(point[1]); + } + } + } + double truncatedMean = calculateTruncatedMean(yValues, 0.1); // 截断比例为10% + double truncatedMean2 = calculateTruncatedMean(yValues2, 0.1); // 截断比例为10% + double similarity = (truncatedMean - pojo.getMinBounds()[1])/(pojo.getMaxBounds()[1] - pojo.getMinBounds()[1]); + double similarity2 = (truncatedMean2 - pojo.getMinBounds()[1])/(pojo.getMaxBounds()[1] - pojo.getMinBounds()[1]); + countSum++; + if(Double.isNaN(similarity) && Double.isNaN(similarity2)){ + break; + } + System.out.println("similarity:"+similarity+"similarity2:"+similarity2); + double max = Math.max(similarity, similarity2); // 获取较大数 + double min = Math.min(similarity, similarity2); // 获取较小数 + if(max-min<0.01){ + count++; + } + results.add(new double[]{leftBottomX, leftBottomZ, truncatedMean, truncatedMean2}); + } + } + System.out.println(count); + pojo.setCount(count); + return (double) count /countSum; + } + + + /** + * 计算截断均值 + * + * @param values 值列表 + * @param trimRatio 截断比例 + * @return 截断均值 + */ + private static double calculateTruncatedMean(List values, double trimRatio) { + int trimCount = (int) Math.ceil(values.size() * trimRatio); + values.sort(Comparator.naturalOrder()); + double sum = 0; + for (int i = trimCount; i < values.size() - trimCount; i++) { + sum += values.get(i); + } + return sum / (values.size() - 2 * trimCount); + } + + public static List readPCD(String filePath) { + try { + if (isBinaryFormat(filePath)) { + return readBinaryPCD(filePath); + } else { + return readAsciiPCD(filePath); + } + } catch (IOException e) { + e.printStackTrace(); + } + return null; + + } + + private static boolean isBinaryFormat(String filePath) throws IOException { + try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { + String line; + while ((line = reader.readLine()) != null) { + if (line.startsWith("DATA")) { + return line.contains("binary"); + } + } + } + return false; + } + + private static List readAsciiPCD(String filePath) throws IOException { + List points = new ArrayList<>(); + try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { + String line; + + while ((line = reader.readLine()) != null) { + if (line.startsWith("DATA")) { + break; + } + } + while ((line = reader.readLine()) != null) { + double[] point = new double[3]; + String[] values = line.split(" "); + point[0] = Double.parseDouble(values[0]); + point[1] = Double.parseDouble(values[1]); + point[2] = Double.parseDouble(values[2]); + points.add(point); + + } + } + return points; + } + + private static List readBinaryPCD(String filePath) throws IOException { + List points = new ArrayList<>(); + try (FileInputStream fis = new FileInputStream(filePath)) { + ByteBuffer buffer = ByteBuffer.wrap(fis.readAllBytes()); + buffer.order(ByteOrder.LITTLE_ENDIAN); + // Skip header (assuming header size is known, or read until DATA section) + // This example assumes 11 lines of header, which may vary + for (int i = 0; i < 11; i++) { + while (buffer.get() != '\n') { + // Skip header lines + } + } + // Read binary data + while (buffer.hasRemaining()) { + double x = buffer.getFloat(); + double y = buffer.getFloat(); + double z = buffer.getFloat(); + int rgb = buffer.getInt(); // Read 4 bytes for RGB + double[] point = {x, y, z}; + points.add(point); + } + } catch (Exception e) { + return null; + } + return points; + } + + static void getPCDArray(String filePath) { + + } + + static void getPCDArray(Map> clippedPoint, String filePath) { + + // 创建一个DecimalFormat对象,指定格式 + DecimalFormat df = new DecimalFormat("#.####"); + File file = new File(filePath + ".txt"); + file.delete(); + try (BufferedWriter bw = new BufferedWriter(new FileWriter(filePath + ".txt"))) { + bw.write("["); + for (Double x : clippedPoint.keySet()) { + for (Double y : clippedPoint.get(x).keySet()) { + double z = clippedPoint.get(x).get(y); + bw.write("[" + df.format(x) + ", " + df.format(y) + ", " + df.format(z) + "],\n"); + } + } + bw.write("]"); + } catch (IOException e) { + e.printStackTrace(); + } + // 读取点云数据 + + + } + + public static double[] rotatePoints(double[] point, double[][] rotationMatrix) { + + double x = point[0]; + double y = point[1]; + double z = point[2]; + + double[] rotatedPoint = new double[3]; + rotatedPoint[0] = rotationMatrix[0][0] * x + rotationMatrix[0][1] * y + rotationMatrix[0][2] * z; + rotatedPoint[1] = rotationMatrix[1][0] * x + rotationMatrix[1][1] * y + rotationMatrix[1][2] * z; + rotatedPoint[2] = rotationMatrix[2][0] * x + rotationMatrix[2][1] * y + rotationMatrix[2][2] * z; + + return rotatedPoint; + } +// +// public static List clipPoints(List points, double[] minBounds, double[] maxBounds) { +// List clippedPoints = new ArrayList<>(); +// for (double[] point : points) { +// if (point[0] >= minBounds[0] && point[0] <= maxBounds[0] && +// point[1] >= minBounds[1] && point[1] <= maxBounds[1] && +// point[2] >= minBounds[2] && point[2] <= maxBounds[2]) { +// clippedPoints.add(point); +// } +// } +// return clippedPoints; +// } + + public static boolean clipPoints(double[] point, double[] minBounds, double[] maxBounds) { + + return point[0] >= minBounds[0] && point[0] <= maxBounds[0] && //x轴截取 + point[1] >= minBounds[1] && point[1] <= maxBounds[1] && //y轴截取 + point[2] >= minBounds[2] && point[2] <= maxBounds[2]; + } + + public static void writePCD(List points, String filePath) { + try (BufferedWriter bw = new BufferedWriter(new FileWriter(filePath))) { + bw.write("# .PCD v0.7 - Point Cloud Data file format\n"); + bw.write("VERSION 0.7\n"); + bw.write("FIELDS x y z\n"); + bw.write("SIZE 4 4 4\n"); + bw.write("TYPE F F F\n"); + bw.write("COUNT 1 1 1\n"); + bw.write("WIDTH " + points.size() + "\n"); + bw.write("HEIGHT 1\n"); + bw.write("VIEWPOINT 0 0 0 1 0 0 0\n"); + bw.write("PIXEL_FORMAT ascii\n"); + bw.write("DATA ascii\n"); + for (double[] point : points) { + bw.write(point[0] + " " + point[1] + " " + point[2] + "\n"); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + + /** + * 切割外部所有其他 + * @param pojo + */ + List slicing(PcdPojo pojo){ + // 计算pcd1 + List points = readPCD(pojo.getPcd1()); + if (points == null || points.isEmpty()) { + return points; + } + //map xyz + List clippedPoint = points.stream() + .map(point -> { + //旋转 + return rotatePoints(point, pojo.getRotationMatrix()); + + }) + .filter(point -> + //截取 + clipPoints(point, pojo.getMinBounds(), pojo.getMaxBounds()) + ) + //z轴截取 + .collect(Collectors.toList()); + return clippedPoint; + } + + public static void main(String[] args) { + LxPointCloudSaveImage.saveImage("192.168.1.82","E:\\1.pcd",1); + PcdPojo pojo = new PcdPojo(); + pojo.setPcd1("E:/1.pcd"); + pojo.setConfigPath("E:\\pe.json"); + try { + pojo.setPCDInfo(pojo); + } catch (IOException e) { + throw new RuntimeException(e); + } + PointCloudProcessor pointCloudProcessor = new PointCloudProcessor(); + List confs = pointCloudProcessor.getBoxPositionConf("E:\\peconf.json"); + int i = pointCloudProcessor.slicing(pojo,confs); + System.out.println(pojo.toString()); + System.out.println(i); + + } + + /** + * 判断个数 + * @param pojo + */ + public int slicing(PcdPojo pojo, List boxPositionConfs){ + // 计算pcd1 + List points = readPCD(pojo.getPcd1()); + if (points == null || points.isEmpty()) { + + } + Map map = new HashMap<>(); + //map xyz + List clippedPoint = points.stream() + .map(point -> { + //旋转 + return rotatePoints(point, pojo.getRotationMatrix()); + + }) + .filter(point -> + //截取 + clipPoints(point, pojo.getMinBounds(), pojo.getMaxBounds()) + ) + .peek(v->{ + for (int i = 0; i < boxPositionConfs.size(); i++){ + if (boxPositionConfs.get(i).getHeight()>v[2]-50&&boxPositionConfs.get(i).getHeight()v[0] + &&boxPositionConfs.get(i).getPosition().get(j)[2]>v[1] + &&boxPositionConfs.get(i).getPosition().get(j)[3]200){ + count +=1; + } + } + return count; + } + public List getBoxPositionConf(String path){ + //读取点云位置 + ObjectMapper mapper = new ObjectMapper(); + List boxPositionConfs =null; + try { + // 读取 JSON 文件并转换为 配置信息 + boxPositionConfs = mapper.readValue(new File(path), mapper.getTypeFactory().constructCollectionType(List.class,BoxPositionConf.class)); + // 打印转换后的实体类列表 + //报错则认为没有配置文件,返回盘点失败 + } catch (JsonMappingException e) { + e.printStackTrace(); + + } catch (JsonProcessingException e) { + e.printStackTrace(); + + } catch (IOException e) { + e.printStackTrace(); + + } + return boxPositionConfs; + } +} diff --git a/web/src/main/java/com/zhehekeji/web/service/PlcService.java b/web/src/main/java/com/zhehekeji/web/service/PlcService.java index c29c3ff..f9c5ef0 100644 --- a/web/src/main/java/com/zhehekeji/web/service/PlcService.java +++ b/web/src/main/java/com/zhehekeji/web/service/PlcService.java @@ -23,9 +23,11 @@ import com.zhehekeji.web.service.ksec.KsecInfo; import io.swagger.models.auth.In; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; +import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; import java.nio.CharBuffer; @@ -385,10 +387,6 @@ public class PlcService { } } - public static void main(String[] args) { - System.out.println("330101".length() != 6); - } - /** * 收到告警异常信号 @@ -755,20 +753,21 @@ public class PlcService { public void visualCalculationResults(TransmissionPojo transmissionPojo) { + //获取个数 + int count = sendHttp(transmissionPojo.getStreetNumber()); CheckLog checkLog = checkLogMapper.selectById(transmissionPojo.getCheckId()); Stock stock = stockMapper.selectOne(new QueryWrapper().eq("check_Num", checkLog.getId())); Street street = streetService.getStreetByPlcId(transmissionPojo.getStreetNumber()); if( stock.getCategory() != null && "20".equals(stock.getCategory())) { checkLog.setStatus(StockStatus.OTHER.getStatus()); stock.setStatus(StockStatus.OTHER.getStatus()); - }else if (transmissionPojo.getResult() != null && transmissionPojo.getResult() == 1) { + }else if (!"0".equals(transmissionPojo.getCategory()) && stock.getCount() == count){ checkLog.setStatus(StockStatus.SUCCESS.getStatus()); stock.setStatus(StockStatus.SUCCESS.getStatus()); } else { checkLog.setStatus(StockStatus.ERROR.getStatus()); stock.setStatus(StockStatus.ERROR.getStatus()); - stock.setCount(transmissionPojo.getCount()); - stock.setCategory(transmissionPojo.getCategory()); + stock.setCount(count); } if (transmissionPojo.getPcd() != null && !"".equals(transmissionPojo.getPcd())) { @@ -786,6 +785,43 @@ public class PlcService { stockMapper.updateById(stock); } + public int sendHttp(String streetNumber){ + Street street = streetService.getStreetByPlcId(streetNumber); + // 创建 RestTemplate 实例 + RestTemplate restTemplate = new RestTemplate(); + + // 定义 URL + String url = "http://"+street.getPlcIp()+":8097/category/getBoxCount"; + + // 发起 GET 请求 + ResponseEntity response = restTemplate.getForEntity(url, Integer.class); + + // 输出响应状态码和响应体 + System.out.println("Status Code: " + response.getStatusCode()); + return response.getBody(); + } + + public int sendHttp(){ + + // 创建 RestTemplate 实例 + RestTemplate restTemplate = new RestTemplate(); + + // 定义 URL + String url = "http://"+"127.0.0.1"+":8097/category/getBoxCount"; + + // 发起 GET 请求 + ResponseEntity response = restTemplate.getForEntity(url, Integer.class); + + // 输出响应状态码和响应体 + System.out.println("Status Code: " + response.getStatusCode()); + return response.getBody(); + } + + public static void main(String[] args) { + PlcService plcService = new PlcService(); + System.out.println(plcService.sendHttp()); + } + public static String join(String[] array, String separator) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < array.length; i++) { diff --git a/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java b/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java index 95b013f..5b63aca 100644 --- a/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java +++ b/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java @@ -17,6 +17,8 @@ import io.netty.handler.codec.DelimiterBasedFrameDecoder; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; import java.nio.charset.Charset; import java.util.List; @@ -125,12 +127,14 @@ public class Decoder extends DelimiterBasedFrameDecoder { } //照片和结果保存,并发送给上位机 else if(RETURN_CHECK.equals(transmissionPojo.getHeader())){ - //保存数据 + + + //保存数据 plcService.visualCalculationResults(transmissionPojo); //发送给上位机 KsecInfo ksecInfo = plcService.getKsecDataInfo(transmissionPojo,"E"); ksecInfo.getData().setTypeNum(transmissionPojo.getCategory()); - ksecInfo.getData().setQuantity(transmissionPojo.getCount()); + //ksecInfo.getData().setQuantity(transmissionPojo.getCount()); ksecInfo.getData().setCheckRlt(transmissionPojo.getResult()); KsecNettyClient.write(ksecInfo); GetPhotoDelayExecutor.removeTask(transmissionPojo.getStreetNumber(), transmissionPojo);