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