You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lxCameraApi/BOX_COUNT_USAGE.md

11 KiB

箱子数量计算接口使用说明

概述

本系统提供了基于点云数据的箱子数量计算接口,可以根据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

请求体:

{
  "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层

响应示例:

{
  "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

示例:

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

响应示例:

{
  "floorHeight": 0.0,
  "boxLength": 200.0,
  "boxWidth": 140.0,
  "boxHeight": 250.0,
  "stackType": "1w",
  "maxBoxesPerLayer": 10,
  "baseTolerance": 50.0,
  "additionalTolerancePerLevel": 20.0
}

Java调用示例

示例1: 基本调用

@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: 使用默认配置

public void calculateBoxesDefault() {
    BoxCountRequest request = BoxCountRequest.createDefault();
    request.setPcdFilePath("D:/output/test.pcd");

    BoxCountResult result = lxCameraService.countBoxes(request);

    System.out.println(result.getSummary());
}

示例3: 自定义冗余和边界

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: 拍照后立即计算

// 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: 批量处理历史数据

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: 定时任务自动计算

@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. 边界裁剪

设置合理的边界可以:

  • 提高计算速度
  • 排除噪声点
  • 提高计算准确性

示例:

// 根据相机视野设置边界
request.setMinBounds(new double[]{-600, -600, -300});
request.setMaxBounds(new double[]{600, 600, 200});

3. 最小点数阈值

默认值:1000点

如果点云密度较低或箱面较小,可以调小此值:

// 在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: 设置多个边界,分别计算

// 区域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 - 相机服务使用说明