# 箱子数量计算接口使用说明 ## 概述 本系统提供了基于点云数据的箱子数量计算接口,可以根据PCD文件、地板高度、箱子尺寸和堆叠类型自动计算箱子数量。 ## 功能特点 - ✅ 支持PCD文件读取和解析 - ✅ 自动按高度分层点云 - ✅ 支持冗余配置(每层递增) - ✅ 基于凸包面积计算箱子数量 - ✅ 支持多种堆叠类型配置 - ✅ 返回详细的层信息 ## 计算原理 ### 1. 高度计算 ``` 高度 = 地板高度 - 点的Z轴坐标 ``` ### 2. 层判断 ``` 层数 = round(高度 / 箱子高度) ``` ### 3. 冗余范围 ``` 冗余 = 基础冗余(50mm) + 层数 × 每层增加冗余(20mm) 有效点判断: |高度 - 层数 × 箱子高度| ≤ 冗余 ``` ### 4. 面积计算 - 将每层的点投影到XY平面 - 计算凸包面积 - 凸包面积即为该层堆叠区域面积 ### 5. 箱子数量 ``` 每层箱子数 = min(round(凸包面积 / (箱子长 × 箱子宽)), 每层最大箱子数) 总箱子数 = Σ(每层箱子数) ``` ## API接口 ### 1. POST方式计算(推荐) **请求URL:** ``` POST /api/boxcount/calculate Content-Type: application/json ``` **请求体:** ```json { "pcdFilePath": "D:/output/20250325/pointCloud/192.168.1.100_pointcloud_20250325_143022.pcd", "floorHeight": 1000.0, "boxLength": 200.0, "boxWidth": 140.0, "boxHeight": 250.0, "stackType": "2w 3h", "maxBoxesPerLayer": 10, "baseTolerance": 50.0, "additionalTolerancePerLevel": 20.0, "minBounds": [-1000.0, -1000.0, -1000.0], "maxBounds": [1000.0, 1000.0, 1000.0] } ``` **参数说明:** | 参数名 | 类型 | 必填 | 默认值 | 说明 | |--------|------|------|--------|------| | pcdFilePath | String | 是 | - | PCD文件路径 | | floorHeight | Double | 否 | 0.0 | 地板高度(mm) | | boxLength | Double | 否 | 200.0 | 箱子长度(mm) | | boxWidth | Double | 否 | 140.0 | 箱子宽度(mm) | | boxHeight | Double | 否 | 250.0 | 箱子高度(mm) | | stackType | String | 否 | "1w" | 堆叠类型(如"2w 3h") | | maxBoxesPerLayer | Integer | 否 | 根据stackType计算 | 每层最大箱子数 | | baseTolerance | Double | 否 | 50.0 | 基础冗余(mm) | | additionalTolerancePerLevel | Double | 否 | 20.0 | 每层增加冗余(mm) | | minBounds | double[] | 否 | [-∞, -∞, -∞] | 裁剪最小边界 | | maxBounds | double[] | 否 | [+∞, +∞, +∞] | 裁剪最大边界 | **stackType格式说明:** - `1w`: 1层宽排列 - `2w`: 2层宽排列 - `1h`: 1层高排列 - `3h`: 3层高排列 - `2w 3h`: 宽排列2层,高排列3层 **响应示例:** ```json { "success": true, "totalBoxCount": 25, "boxesPerLayer": { "1": 10, "2": 8, "3": 7 }, "pointsPerLayer": { "1": 15678, "2": 12450, "3": 9876 }, "areaPerLayer": { "1": 280000.0, "2": 224000.0, "3": 196000.0 }, "layerCount": 3, "maxLayer": 3, "pcdFilePath": "D:/output/20250325/pointCloud/192.168.1.100_pointcloud_20250325_143022.pcd", "calculationTime": 1234, "floorHeight": 1000.0, "boxDimensions": [200.0, 140.0, 250.0], "stackType": "2w 3h" } ``` **响应字段说明:** | 字段 | 类型 | 说明 | |------|------|------| | success | Boolean | 是否成功 | | totalBoxCount | Integer | 总箱子数 | | boxesPerLayer | Map | 各层箱子数(key: 层数,value: 箱子数) | | pointsPerLayer | Map | 各层有效点数 | | areaPerLayer | Map | 各层凸包面积(mm²) | | layerCount | Integer | 有效层数 | | maxLayer | Integer | 最高层 | | pcdFilePath | String | PCD文件路径 | | calculationTime | Long | 计算用时(毫秒) | | floorHeight | Double | 地板高度 | | boxDimensions | Double[] | 箱子尺寸 [长, 宽, 高] | | stackType | String | 堆叠类型 | | errorMessage | String | 错误消息(失败时) | ### 2. GET方式计算 **请求URL:** ``` GET /api/boxcount/calculate?pcdFilePath=xxx&floorHeight=xxx&boxLength=xxx&boxWidth=xxx&boxHeight=xxx&stackType=xxx ``` **示例:** ```bash curl "http://localhost:8080/api/boxcount/calculate?pcdFilePath=D:/output/test.pcd&floorHeight=1000&boxLength=200&boxWidth=140&boxHeight=250&stackType=2w" ``` ### 3. 获取默认配置 **请求URL:** ``` GET /api/boxcount/default ``` **响应示例:** ```json { "floorHeight": 0.0, "boxLength": 200.0, "boxWidth": 140.0, "boxHeight": 250.0, "stackType": "1w", "maxBoxesPerLayer": 10, "baseTolerance": 50.0, "additionalTolerancePerLevel": 20.0 } ``` ## Java调用示例 ### 示例1: 基本调用 ```java @Autowired private LxCameraService lxCameraService; public void calculateBoxes() { BoxCountRequest request = new BoxCountRequest(); request.setPcdFilePath("D:/output/test.pcd"); request.setFloorHeight(1000.0); request.setBoxLength(200.0); request.setBoxWidth(140.0); request.setBoxHeight(250.0); request.setStackType("1w"); BoxCountResult result = lxCameraService.countBoxes(request); if (result.isSuccess()) { System.out.println("总箱子数: " + result.getTotalBoxCount()); System.out.println("层数: " + result.getLayerCount()); System.out.println("最高层: " + result.getMaxLayer()); System.out.println("用时: " + result.getCalculationTime() + "ms"); } else { System.out.println("计算失败: " + result.getErrorMessage()); } } ``` ### 示例2: 使用默认配置 ```java public void calculateBoxesDefault() { BoxCountRequest request = BoxCountRequest.createDefault(); request.setPcdFilePath("D:/output/test.pcd"); BoxCountResult result = lxCameraService.countBoxes(request); System.out.println(result.getSummary()); } ``` ### 示例3: 自定义冗余和边界 ```java public void calculateBoxesCustom() { BoxCountRequest request = BoxCountRequest.createDefault(); request.setPcdFilePath("D:/output/test.pcd"); request.setFloorHeight(1000.0); // 设置冗余 request.setBaseTolerance(60.0); // 基础冗余60mm request.setAdditionalTolerancePerLevel(25.0); // 每层增加25mm // 设置裁剪边界 request.setMinBounds(new double[]{-500.0, -500.0, -200.0}); request.setMaxBounds(new double[]{500.0, 500.0, 100.0}); BoxCountResult result = lxCameraService.countBoxes(request); if (result.isSuccess()) { result.getBoxesPerLayer().forEach((layer, count) -> { int points = result.getPointsPerLayer().get(layer); double area = result.getAreaPerLayer().get(layer); System.out.printf("第%d层: %d个箱子, %d个点, 面积%.2f mm²%n", layer, count, points, area); }); } } ``` ## 使用场景 ### 场景1: 拍照后立即计算 ```java // 1. 拍照 CaptureConfig config = CaptureConfig.createDefault(); CaptureResult captureResult = lxCameraService.capture("192.168.1.100", "D:/output", config); // 2. 计算箱子数量 if (captureResult.isSuccess()) { String pcdPath = captureResult.getFilePath("pointCloud"); BoxCountRequest request = new BoxCountRequest(); request.setPcdFilePath(pcdPath); request.setFloorHeight(1000.0); request.setBoxLength(200.0); request.setBoxWidth(140.0); request.setBoxHeight(250.0); request.setStackType("2w 3h"); BoxCountResult boxResult = lxCameraService.countBoxes(request); System.out.println("箱子总数: " + boxResult.getTotalBoxCount()); } ``` ### 场景2: 批量处理历史数据 ```java public void processHistoricalData(String directory) { File dir = new File(directory); File[] pcdFiles = dir.listFiles((d, name) -> name.endsWith(".pcd")); for (File pcdFile : pcdFiles) { BoxCountRequest request = BoxCountRequest.createDefault(); request.setPcdFilePath(pcdFile.getAbsolutePath()); BoxCountResult result = lxCameraService.countBoxes(request); if (result.isSuccess()) { System.out.printf("%s: %d个箱子%n", pcdFile.getName(), result.getTotalBoxCount()); } } } ``` ### 场景3: 定时任务自动计算 ```java @Component public class BoxCountScheduler { @Autowired private LxCameraService lxCameraService; @Scheduled(fixedRate = 60000) // 每分钟执行一次 public void autoCalculateBoxes() { // 获取最新的PCD文件 String latestPcd = getLatestPcdFile("D:/output/20250325/pointCloud"); if (latestPcd != null) { BoxCountRequest request = BoxCountRequest.createDefault(); request.setPcdFilePath(latestPcd); BoxCountResult result = lxCameraService.countBoxes(request); // 保存结果到数据库或日志 log.info("自动计算完成: {}", result.getSummary()); } } } ``` ## 参数调优建议 ### 1. 冗余参数 - **基础冗余**: 建议设置为箱子高度的10%-20%(25-50mm) - **每层增加冗余**: 建议设置为每层2%-8%(5-20mm) ### 2. 边界裁剪 设置合理的边界可以: - 提高计算速度 - 排除噪声点 - 提高计算准确性 示例: ```java // 根据相机视野设置边界 request.setMinBounds(new double[]{-600, -600, -300}); request.setMaxBounds(new double[]{600, 600, 200}); ``` ### 3. 最小点数阈值 默认值:1000点 如果点云密度较低或箱面较小,可以调小此值: ```java // 在BoxCountCalculator.java中修改 private static final int MIN_POINTS_PER_LAYER = 500; // 调小到500 ``` ## 常见问题 ### Q1: 计算结果不准确? **可能原因:** 1. 地板高度设置错误 2. 箱子尺寸与实际不符 3. 冗余参数设置不合理 4. 点云质量差(点数少) **解决方法:** 1. 检查floorHeight是否正确 2. 测量实际箱子尺寸并更新参数 3. 调整baseTolerance和additionalTolerancePerLevel 4. 提高点云拍摄质量 ### Q2: 某层没有被识别? **可能原因:** 1. 该层点数少于阈值(默认1000) 2. 高度计算偏差超出冗余范围 **解决方法:** 1. 降低最小点数阈值 2. 增加冗余参数 3. 检查该层点云质量 ### Q3: 计算速度慢? **优化方法:** 1. 使用边界裁剪减少点数 2. 提高PCD文件读取效率 3. 优化凸包计算算法 ### Q4: 如何处理多个堆叠区域? **方法1:** 设置多个边界,分别计算 ```java // 区域1 request.setMinBounds(new double[]{-600, -600, -300}); request.setMaxBounds(new double[]{0, 600, 200}); BoxCountResult result1 = lxCameraService.countBoxes(request); // 区域2 request.setMinBounds(new double[]{0, -600, -300}); request.setMaxBounds(new double[]{600, 600, 200}); BoxCountResult result2 = lxCameraService.countBoxes(request); // 总计 int total = result1.getTotalBoxCount() + result2.getTotalBoxCount(); ``` **方法2:** 修改代码支持多区域计算 ## 注意事项 1. **PCD文件格式**: 确保PCD文件包含XYZ坐标 2. **单位统一**: 所有参数使用毫米(mm)作为单位 3. **路径格式**: Windows路径使用正斜杠或双反斜杠 4. **内存管理**: 处理大文件时注意内存使用 5. **并发安全**: 本实现是线程安全的,可以并发调用 ## 性能指标 基于测试数据: | PCD文件大小 | 点云点数 | 计算用时 | |------------|---------|---------| | ~10MB | ~100,000 | ~500ms | | ~20MB | ~200,000 | ~1000ms | | ~30MB | ~300,000 | ~1500ms | ## 相关文档 - `PATH_STRUCTURE.md` - 文件保存路径说明 - `LX_CAMERA_USAGE.md` - 相机服务使用说明