286 lines
9.2 KiB
C++
286 lines
9.2 KiB
C++
#ifndef PLANE_SEGMENTATION_H
|
||
#define PLANE_SEGMENTATION_H
|
||
|
||
#include "../include/VZNL_Types.h"
|
||
#include "ErrorCodes.h"
|
||
#include <vector>
|
||
|
||
/**
|
||
* @brief Z值直方图峰值信息
|
||
*/
|
||
struct ZHistogramPeak {
|
||
float zValue; // 峰值对应的Z坐标
|
||
int pointCount; // 该峰值区域的点数
|
||
float zMin; // 峰值区域的Z最小值
|
||
float zMax; // 峰值区域的Z最大值
|
||
std::vector<int> pointIndices; // 属于该平面的点索引
|
||
};
|
||
|
||
/**
|
||
* @brief Z值直方图平面分割参数
|
||
*/
|
||
struct ZHistogramSegmentationParams {
|
||
float binSize; // 直方图bin大小 (mm), 建议 1.0-5.0
|
||
int minPeakPoints; // 最小峰值点数, 建议 50-100
|
||
float minPeakRatio; // 最小峰值点数占比, 建议 0.03 (3%)
|
||
float peakMergeThreshold; // 峰值合并阈值 (mm), 建议 5.0-10.0
|
||
int smoothingWindow; // 平滑窗口大小, 建议 3-5
|
||
};
|
||
|
||
/**
|
||
* @brief 使用Z值直方图分割平面
|
||
*
|
||
* 算法流程:
|
||
* 1. 计算Z值范围,创建直方图
|
||
* 2. 统计每个bin的点数
|
||
* 3. 对直方图进行平滑处理(可选)
|
||
* 4. 检测峰值(局部最大值)
|
||
* 5. 合并相邻的峰值
|
||
* 6. 为每个峰值收集对应的点
|
||
*
|
||
* 优点:
|
||
* - 计算速度快 O(n)
|
||
* - 适合水平或接近水平的平面
|
||
* - 对噪声有一定鲁棒性
|
||
*
|
||
* 局限:
|
||
* - 对倾斜平面效果较差(Z值会分散)
|
||
* - 只能检测Z方向分层明显的平面
|
||
*
|
||
* @param points 输入点云
|
||
* @param pointCount 点数
|
||
* @param params 分割参数
|
||
* @param outPeaks 输出峰值列表(按Z值排序)
|
||
* @param errCode 错误码
|
||
* @return 检测到的平面数量
|
||
*/
|
||
int SegmentPlanesByZHistogram(
|
||
const SVzNLPointXYZ* points,
|
||
int pointCount,
|
||
const ZHistogramSegmentationParams& params,
|
||
std::vector<ZHistogramPeak>& outPeaks,
|
||
int* errCode
|
||
);
|
||
|
||
/**
|
||
* @brief 改进版:自适应倾斜平面分割
|
||
*
|
||
* 针对倾斜平面的改进算法:
|
||
* 1. 先用Z直方图粗分割
|
||
* 2. 对每个Z层,在XY平面上再做一次分层
|
||
* 3. 或者:先估计主平面法向量,然后投影到该法向量方向再做直方图
|
||
*
|
||
* @param points 输入点云
|
||
* @param pointCount 点数
|
||
* @param params 分割参数
|
||
* @param outPeaks 输出峰值列表
|
||
* @param errCode 错误码
|
||
* @return 检测到的平面数量
|
||
*/
|
||
int SegmentTiltedPlanesByHistogram(
|
||
const SVzNLPointXYZ* points,
|
||
int pointCount,
|
||
const ZHistogramSegmentationParams& params,
|
||
std::vector<ZHistogramPeak>& outPeaks,
|
||
int* errCode
|
||
);
|
||
|
||
/**
|
||
* @brief Z值波动统计信息
|
||
*/
|
||
struct ZFluctuationStats {
|
||
float meanZ; // Z值均值
|
||
float stdDevZ; // Z值标准差(去除离群点后)
|
||
float minZ; // Z值最小值(去除离群点后)
|
||
float maxZ; // Z值最大值(去除离群点后)
|
||
float rangeZ; // Z值范围(maxZ - minZ)
|
||
int validPointCount; // 有效点数(去除离群点后)
|
||
int outlierCount; // 离群点数量
|
||
float outlierRatio; // 离群点占比
|
||
float medianZ; // Z值中位数
|
||
float iqrZ; // 四分位距(IQR)
|
||
};
|
||
|
||
/**
|
||
* @brief Z值波动分析参数
|
||
*/
|
||
struct ZFluctuationParams {
|
||
enum OutlierMethod {
|
||
SIGMA_3, // 3-sigma规则(适合正态分布)
|
||
IQR, // 四分位距方法(更鲁棒,推荐)
|
||
PERCENTILE // 百分位数方法
|
||
};
|
||
|
||
OutlierMethod method; // 离群点检测方法
|
||
float sigmaMultiplier; // sigma倍数,默认3.0
|
||
float iqrMultiplier; // IQR倍数,默认1.5
|
||
float percentileLow; // 下百分位数,默认5.0 (5%)
|
||
float percentileHigh; // 上百分位数,默认95.0 (95%)
|
||
|
||
// 默认构造函数
|
||
ZFluctuationParams()
|
||
: method(IQR)
|
||
, sigmaMultiplier(3.0f)
|
||
, iqrMultiplier(1.5f)
|
||
, percentileLow(5.0f)
|
||
, percentileHigh(95.0f)
|
||
{}
|
||
};
|
||
|
||
/**
|
||
* @brief 计算点云Z值波动统计(鲁棒版本,自动去除离群点)
|
||
*
|
||
* 算法流程:
|
||
* 1. 收集所有有效点的Z值
|
||
* 2. 根据选择的方法检测并去除离群点:
|
||
* - 3-sigma: 去除距离均值超过3倍标准差的点
|
||
* - IQR: 去除超出 [Q1-1.5*IQR, Q3+1.5*IQR] 范围的点(推荐)
|
||
* - Percentile: 只保留指定百分位数范围内的点
|
||
* 3. 用剩余点重新计算统计信息
|
||
*
|
||
* 使用场景:
|
||
* - 评估点云平整度
|
||
* - 检测是否存在多个平面
|
||
* - 质量控制(如木板平整度检测)
|
||
*
|
||
* 示例:
|
||
* ```cpp
|
||
* ZFluctuationParams params;
|
||
* params.method = ZFluctuationParams::IQR; // 使用IQR方法(推荐)
|
||
*
|
||
* ZFluctuationStats stats;
|
||
* int errCode = 0;
|
||
* ComputeZFluctuation(points, pointCount, params, &stats, &errCode);
|
||
*
|
||
* std::cout << "Z波动: " << stats.stdDevZ << " mm" << std::endl;
|
||
* std::cout << "Z范围: " << stats.rangeZ << " mm" << std::endl;
|
||
* std::cout << "离群点: " << stats.outlierCount << " ("
|
||
* << stats.outlierRatio * 100 << "%)" << std::endl;
|
||
* ```
|
||
*
|
||
* @param points 输入点云
|
||
* @param pointCount 点数
|
||
* @param params 波动分析参数
|
||
* @param outStats 输出统计信息
|
||
* @param errCode 错误码
|
||
* @return HD_SUCCESS 成功,其他值表示错误
|
||
*/
|
||
int ComputeZFluctuation(
|
||
const SVzNLPointXYZ* points,
|
||
int pointCount,
|
||
const ZFluctuationParams& params,
|
||
ZFluctuationStats* outStats,
|
||
int* errCode
|
||
);
|
||
|
||
/**
|
||
* @brief 简化版:使用默认参数计算Z值波动
|
||
*
|
||
* 使用IQR方法自动去除离群点,适合大多数场景。
|
||
*
|
||
* @param points 输入点云
|
||
* @param pointCount 点数
|
||
* @param outStats 输出统计信息
|
||
* @param errCode 错误码
|
||
* @return HD_SUCCESS 成功,其他值表示错误
|
||
*/
|
||
int ComputeZFluctuation(
|
||
const SVzNLPointXYZ* points,
|
||
int pointCount,
|
||
ZFluctuationStats* outStats,
|
||
int* errCode
|
||
);
|
||
|
||
/**
|
||
* @brief 点云采样间距统计信息
|
||
*/
|
||
struct PointSpacingStats {
|
||
// 主要结果:取两个方向的最大值
|
||
float typicalSpacing; // 典型间距(行内和列内中位数的最大值,推荐使用)
|
||
|
||
// 分方向统计
|
||
float rowSpacing; // 行内平均间距(同一激光线上相邻点,YZ平面距离)
|
||
float colSpacing; // 列内平均间距(相邻激光线间,XZ平面距离)
|
||
float rowSpacingMedian; // 行内间距中位数(更鲁棒)
|
||
float colSpacingMedian; // 列内间距中位数(更鲁棒)
|
||
float rowSpacingStdDev; // 行内间距标准差
|
||
float colSpacingStdDev; // 列内间距标准差
|
||
int rowSampleCount; // 行内采样数量
|
||
int colSampleCount; // 列内采样数量
|
||
float rowSpacingMin; // 行内最小间距
|
||
float rowSpacingMax; // 行内最大间距
|
||
float colSpacingMin; // 列内最小间距
|
||
float colSpacingMax; // 列内最大间距
|
||
};
|
||
|
||
/**
|
||
* @brief 计算点云相邻点间距(鲁棒版本,自动去除噪点)
|
||
*
|
||
* 算法流程:
|
||
* 1. 遍历所有相邻点对:
|
||
* - 行内相邻点(同一激光线):使用YZ平面距离 sqrt((y2-y1)² + (z2-z1)²)
|
||
* - 列内相邻点(相邻激光线):使用XZ平面距离 sqrt((x2-x1)² + (z2-z1)²)
|
||
* 2. 跳过无效点 (0,0,0)
|
||
* 3. 收集所有距离值
|
||
* 4. 使用中位数和IQR方法去除噪点
|
||
* 5. 计算统计信息(均值、中位数、标准差等)
|
||
*
|
||
* 使用场景:
|
||
* - 估计点云采样密度/分辨率
|
||
* - 验证扫描仪参数
|
||
* - 检测采样不均匀性
|
||
* - 为后续算法选择合适的邻域大小
|
||
*
|
||
* 注意事项:
|
||
* - 行内距离使用YZ平面:因为激光线沿Y方向扫描,Z是深度
|
||
* - 列内距离使用XZ平面:因为相邻激光线在X方向分布,Z是深度
|
||
* - 自动跳过无效点 (0,0,0)
|
||
* - 使用中位数避免噪点影响
|
||
*
|
||
* 示例:
|
||
* ```cpp
|
||
* PointSpacingStats stats;
|
||
* int errCode = 0;
|
||
* ComputePointSpacing(points, rows, cols, &stats, &errCode);
|
||
*
|
||
* std::cout << "行内间距: " << stats.rowSpacingMedian << " mm" << std::endl;
|
||
* std::cout << "列内间距: " << stats.colSpacingMedian << " mm" << std::endl;
|
||
* ```
|
||
*
|
||
* @param points 输入点云(栅格化数据,按行优先存储)
|
||
* @param rows 激光线数量(行数)
|
||
* @param cols 每条激光线上的点数(列数)
|
||
* @param outStats 输出统计信息
|
||
* @param errCode 错误码
|
||
* @return HD_SUCCESS 成功,其他值表示错误
|
||
*/
|
||
int ComputePointSpacing(
|
||
const SVzNLPointXYZ* points,
|
||
int rows,
|
||
int cols,
|
||
PointSpacingStats* outStats,
|
||
int* errCode
|
||
);
|
||
|
||
struct RowZDiffFluctuationStats {
|
||
float meanAbsDz; // |dz| 均值(去除异常值后)
|
||
float medianAbsDz; // |dz| 中位数(去除异常值后)
|
||
float stdDevAbsDz; // |dz| 标准差,作为Z波动值
|
||
float minAbsDz; // |dz| 最小值(去除异常值后)
|
||
float maxAbsDz; // |dz| 最大值(去除异常值后)
|
||
float rangeAbsDz; // |dz| 波动范围(maxAbsDz - minAbsDz)
|
||
int sampleCount; // 有效样本数(去除异常值后)
|
||
int outlierCount; // 被剔除的异常样本数
|
||
float outlierRatio; // 异常样本占比(outlierCount / 原始样本数)
|
||
};
|
||
|
||
int ComputeRowZDiffFluctuation(
|
||
const SVzNLPointXYZ* points,
|
||
int rows,
|
||
int cols,
|
||
RowZDiffFluctuationStats* outStats,
|
||
int* errCode
|
||
);
|
||
|
||
#endif // PLANE_SEGMENTATION_H
|