GrabBag/AppAlgo/holeDetection/include/PlaneSegmentation.h
2026-03-25 11:07:14 +08:00

286 lines
9.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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