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.

64 lines
3.9 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// count.h - 计数模式(count)核心算法与文件保存
#ifndef COUNT_H
#define COUNT_H
#include <string>
#include <vector>
#include <cstdint>
#include "common.h"
// 点云级稀疏拖影过滤:删除每圈边缘外脱离主体的稀疏外伸点(胡须状拖影),
// 使 pcd/图片/面积统计都基于干净点云。判据见 cfg.filter.sparse_cut。
// 原地修改 points;返回删除点数。应在 z_gap_interpolate 之前调用。
int sparse_density_filter(std::vector<CountPoint>& points);
// 点集 → X-Z平面白底图像(0=白,255=黑点) + 换算面积。
// 宽: cfg.filter.polygon 多边形X跨度(1mm=1px); 高: z最大值(1单位=1px);
// 点先按1x1网格标记再膨胀 cfg.count.point_dilate×cfg.count.point_dilate。
// area_out 返回换算实际面积(mm^2); out_w/out_h 返回实际图像尺寸。
std::vector<uint8_t> points_to_image(const std::vector<CountPoint>& points,
double* area_out = nullptr,
int* out_w = nullptr,
int* out_h = nullptr);
// z轴空隙插值:雷达断流/瞬间丢包导致的 z 空白带,仅在停止采集后调用一次。
// 原理:同一圈(scan包)点 z 相同,正常圈间隔≈normal_gap;
// gap>2×normal_gap 且相邻两圈 Y均值差≤30mm 且 X 在相邻圈范围内时,空隙内补行。
// cfg.count.z_interpolate_mode: none/CopyTranslation/AngleBucketInterpolation(最多补10行)。
// 会原地修改 points(新增点追加到末尾);返回新增点数。
int z_gap_interpolate(std::vector<CountPoint>& points);
// KDE 密度峰值:对一组高度值做高斯核密度估计,返回密度最大处(最密)的高度。
// bandwidth<=0 时按 Silverman 经验法则自动定带宽;step 为密度曲线扫描步长(mm)。
double kde_peak_height(const std::vector<double>& vals, double bandwidth, double step);
// 按层统计物品总数(参照Java):高度=cfg.count.floor_height-Y;层数算法由 cfg.count.layer_algorithm 决定:
// LevelTolerance(默认): level=round(高度/层高); 判定 |高度-level×层高| <= 容差
// HalfMax: 两步判定 ①粗筛[(level-0.5)层高,(level+0.5)层高] ②取①内最高点top, 有效区间=[top-容差, top]
// KdePeak: 两步判定 ①同HalfMax粗筛 ②①内高度做KDE取峰值peak, 有效区间=[peak-容差, peak+容差]
// 容差 = cfg.count.base_tolerance + layer号×cfg.count.per_level_tolerance
// 从最高层(5)往下找有效层,个数=min(round(面积/(行*宽)), maxPerLayer),
// 结果 = maxPerLayer*(层号-1)+该层个数。
// 返回总个数;不足一个完整箱时返回0。
int calc_item_count(const std::vector<CountPoint>& points, const CountParams& box,
std::string* detail = nullptr, // 每层点数/高度范围/面积详情
std::vector<uint8_t>* top_layer_img = nullptr, // 被计数层(最高有效层)图像
int* top_layer_img_w = nullptr,
int* top_layer_img_h = nullptr,
int* top_layer_level = nullptr,
double* top_layer_area = nullptr);
// 将一次 count 结果保存到任务目录 make_task_dir(task_id)(后台线程异步执行,不阻塞响应):
// count_data.pcd (Y已换成高度 = cfg.count.floor_height - y_mm)
// count_points.jpg (全部点 X-Z 平面图)
// count_layer.jpg (被计数层图像, 有有效层时)
// log.txt (cfg.log.enable 开启时)
void save_count_files_async(const std::vector<CountPoint>& points,
const std::vector<uint8_t>& top_layer_img,
int top_img_w, int top_img_h,
const CountParams& params,
const std::string& layer_detail,
int total, int top_lv, double top_area);
#endif // COUNT_H