diff --git a/App/HoleDetection/HoleDetectionApp/Version.h b/App/HoleDetection/HoleDetectionApp/Version.h index 8c758e2..a768be7 100644 --- a/App/HoleDetection/HoleDetectionApp/Version.h +++ b/App/HoleDetection/HoleDetectionApp/Version.h @@ -5,8 +5,8 @@ #define HOLEDETECTION_APP_NAME "孔洞检测" // 版本字符串 -#define HOLEDETECTION_VERSION_STRING "1.0.1" -#define HOLEDETECTION_BUILD_STRING "0" +#define HOLEDETECTION_VERSION_STRING "1.1.0" +#define HOLEDETECTION_BUILD_STRING "1" #define HOLEDETECTION_FULL_VERSION_STRING "V" HOLEDETECTION_VERSION_STRING "_" HOLEDETECTION_BUILD_STRING // 构建日期 diff --git a/App/HoleDetection/HoleDetectionApp/Version.md b/App/HoleDetection/HoleDetectionApp/Version.md index 3175a18..96c7494 100644 --- a/App/HoleDetection/HoleDetectionApp/Version.md +++ b/App/HoleDetection/HoleDetectionApp/Version.md @@ -1,3 +1,9 @@ +# 1.1.0 2026-03-125 +## build_1 +1. 算法优化 +2. 配置结构修改 +3. 手眼标定,网络配置公用 + # 1.0.0 2026-03-11 ## build_4 1. 修复矩阵配置 diff --git a/App/HoleDetection/HoleDetectionApp/dialogalgoarg.ui b/App/HoleDetection/HoleDetectionApp/dialogalgoarg.ui index 868b93a..8b7d916 100644 --- a/App/HoleDetection/HoleDetectionApp/dialogalgoarg.ui +++ b/App/HoleDetection/HoleDetectionApp/dialogalgoarg.ui @@ -7,7 +7,7 @@ 0 0 780 - 656 + 541 @@ -323,6 +323,12 @@ QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px; + + + 手眼标定 + + + 网络配置 @@ -390,12 +396,6 @@ QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px; - - - 手眼标定 - - - @@ -435,6 +435,19 @@ QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px; + + + + Qt::Horizontal + + + + 40 + 20 + + + + diff --git a/App/HoleDetection/HoleDetectionConfig/HoleDetectionConfig.pro b/App/HoleDetection/HoleDetectionConfig/HoleDetectionConfig.pro index 12883fd..5e5daa5 100644 --- a/App/HoleDetection/HoleDetectionConfig/HoleDetectionConfig.pro +++ b/App/HoleDetection/HoleDetectionConfig/HoleDetectionConfig.pro @@ -4,6 +4,11 @@ TEMPLATE = lib CONFIG += staticlib CONFIG += c++11 +# 编码设置 +win32-msvc { + QMAKE_CXXFLAGS += /utf-8 +} + # Output directory configuration TARGET = HoleDetectionConfig diff --git a/App/HoleDetection/HoleDetectionConfig/Inc/IVrConfig.h b/App/HoleDetection/HoleDetectionConfig/Inc/IVrConfig.h index 9b60a2a..c25ae4f 100644 --- a/App/HoleDetection/HoleDetectionConfig/Inc/IVrConfig.h +++ b/App/HoleDetection/HoleDetectionConfig/Inc/IVrConfig.h @@ -18,8 +18,8 @@ struct VrHoleDetectionParam { int neighborCount = 3; // 相邻点连接数 - double angleThresholdPos = 10.0; // 正角度阈值(度) - double angleThresholdNeg = -10.0; // 负角度阈值(度) + double angleThresholdPos = 30.0; // 正角度阈值(度) + double angleThresholdNeg = -30.0; // 负角度阈值(度) double minPitDepth = 1.0; // 最小凹坑深度(mm) double minRadius = 2.0; // 最小孔半径(mm) double maxRadius = 50.0; // 最大孔半径(mm) diff --git a/App/HoleDetection/HoleDetectionConfig/Src/AlgoParamConverter.cpp b/App/HoleDetection/HoleDetectionConfig/Src/AlgoParamConverter.cpp index 0302cd5..7eec5ef 100644 --- a/App/HoleDetection/HoleDetectionConfig/Src/AlgoParamConverter.cpp +++ b/App/HoleDetection/HoleDetectionConfig/Src/AlgoParamConverter.cpp @@ -7,7 +7,6 @@ namespace AlgoParamConverter SHoleDetectionParams ToAlgoParam(const VrHoleDetectionParam& param) { SHoleDetectionParams algo; - algo.neighborCount = param.neighborCount; algo.angleThresholdPos = static_cast(param.angleThresholdPos); algo.angleThresholdNeg = static_cast(param.angleThresholdNeg); algo.minPitDepth = static_cast(param.minPitDepth); @@ -44,8 +43,8 @@ void LogAlgoParams(const std::string& logTag, clibMatrix[8], clibMatrix[9], clibMatrix[10], clibMatrix[11], clibMatrix[12], clibMatrix[13], clibMatrix[14], clibMatrix[15]); - LOG_INFO("%s DetectionParams: neighborCount=%d, angleThresholdPos=%.1f, angleThresholdNeg=%.1f, minPitDepth=%.1f\n", - logTag.c_str(), detectionParams.neighborCount, detectionParams.angleThresholdPos, + LOG_INFO("%s DetectionParams: angleThresholdPos=%.1f, angleThresholdNeg=%.1f, minPitDepth=%.1f\n", + logTag.c_str(), detectionParams.angleThresholdPos, detectionParams.angleThresholdNeg, detectionParams.minPitDepth); LOG_INFO("%s DetectionParams: minRadius=%.1f, maxRadius=%.1f, expansionSize1=%d, expansionSize2=%d, minVTransitionPoints=%d\n", logTag.c_str(), detectionParams.minRadius, detectionParams.maxRadius, diff --git a/AppAlgo/holeDetection/arm/debug/libHoleDetectionLib.so.1.0.0 b/AppAlgo/holeDetection/arm/debug/libHoleDetectionLib.so.1.0.0 index 9c68401..f0de25c 100644 Binary files a/AppAlgo/holeDetection/arm/debug/libHoleDetectionLib.so.1.0.0 and b/AppAlgo/holeDetection/arm/debug/libHoleDetectionLib.so.1.0.0 differ diff --git a/AppAlgo/holeDetection/arm/release/libHoleDetectionLib.so.1.0.0 b/AppAlgo/holeDetection/arm/release/libHoleDetectionLib.so.1.0.0 index c92f37b..3ea6675 100644 Binary files a/AppAlgo/holeDetection/arm/release/libHoleDetectionLib.so.1.0.0 and b/AppAlgo/holeDetection/arm/release/libHoleDetectionLib.so.1.0.0 differ diff --git a/AppAlgo/holeDetection/include/HoleDetection.h b/AppAlgo/holeDetection/include/HoleDetection.h index 5a5d75f..a354f44 100644 --- a/AppAlgo/holeDetection/include/HoleDetection.h +++ b/AppAlgo/holeDetection/include/HoleDetection.h @@ -12,6 +12,8 @@ #else #define HOLE_DETECTION_API __declspec(dllimport) #endif +#elif defined(__GNUC__) || defined(__clang__) + #define HOLE_DETECTION_API __attribute__((visibility("default"))) #else #define HOLE_DETECTION_API #endif @@ -31,6 +33,47 @@ struct SHoleBoundaryPoint { : point(p), row(r), col(c) {} }; +/** + * @brief Per-point signed angle state along one scanned line + */ +enum ELineAngleTrend { + keLineAngleTrend_Invalid = 0, + keLineAngleTrend_Flat = 1, + keLineAngleTrend_PositiveJump = 2, + keLineAngleTrend_NegativeJump = 3 +}; + +/** + * @brief Angle profile sample for one valid point on a scanned line + */ +struct SLineAngleSample { + SVzNLPointXYZ point; // Current point + int row; // Grid row + int col; // Grid column + int linePos; // Position inside the scanned line + float signedAngleDeg; // Signed turning angle in degrees + float beforeMeanZ; // Mean Z of points found within A before current point + float afterMeanZ; // Mean Z of points found within A after current point + float beforeCoord; // Projected coord of the furthest point before current point + float afterCoord; // Projected coord of the furthest point after current point + ELineAngleTrend trend; // Flat / positive jump / negative jump + unsigned char hasAngle; // 1 if both sides have enough points to form an angle + + SLineAngleSample() + : point() + , row(-1) + , col(-1) + , linePos(-1) + , signedAngleDeg(0.0f) + , beforeMeanZ(0.0f) + , afterMeanZ(0.0f) + , beforeCoord(0.0f) + , afterCoord(0.0f) + , trend(keLineAngleTrend_Invalid) + , hasAngle(0U) + {} +}; + /** * @brief Cluster information for debug callbacks */ @@ -90,6 +133,22 @@ struct SHoleDetectionDebugCallbacks { */ void (*onSegmentPairsDetected)(const SSegmentPair* segmentPairs, int count, void* userData); + /** + * @brief Called when one scanned line's signed angle profile is available + * @param samples Array of valid-point angle samples in line order + * @param count Number of samples + * @param lineType "Row" or "Column" + * @param lineIndex Row/column index + * @param userData User-provided context pointer + */ + void (*onLineAngleProfileDetected)( + const SLineAngleSample* samples, + int count, + const char* lineType, + int lineIndex, + void* userData + ); + /** * @brief User-provided context pointer, passed to all callbacks */ diff --git a/AppAlgo/holeDetection/include/HoleDetectionParams.h b/AppAlgo/holeDetection/include/HoleDetectionParams.h index 9dfafe1..2591142 100644 --- a/AppAlgo/holeDetection/include/HoleDetectionParams.h +++ b/AppAlgo/holeDetection/include/HoleDetectionParams.h @@ -2,26 +2,16 @@ #define HOLE_DETECTION_PARAMS_H #include -#include "../include/VZNL_Types.h" // 使用 VZNL_Types.h 中的类型 - -/** - * @brief 检测到的孔洞排序模式 - */ -enum ESortMode { - keSortMode_None = 0, // 不排序 - keSortMode_ByRadius = 1, // 按半径排序(最大的在前) - keSortMode_ByDepth = 2, // 按深度排序(最深的在前) - keSortMode_ByQuality = 3 // 按质量分数排序(最高的在前) -}; +#include "VZNL_Types.h" // 使用 VZNL_Types.h 中定义的类型 /** * @brief 孔洞检测算法的检测参数 */ struct SHoleDetectionParams { // 凹坑检测参数 - int neighborCount; // 线连接的相邻点数(默认值:3) - float angleThresholdPos; // 正角度阈值,单位:度(默认值:10.0) - float angleThresholdNeg; // 负角度阈值,单位:度(默认值:-10.0) + float angleThresholdPos; // 正角度阈值,单位:度(默认值:30.0) + float angleThresholdNeg; // 负角度阈值,单位:度(默认值:-30.0) + float angleSearchDistance; // Method1 前后搜索距离 A,单位:mm float minPitDepth; // 最小凹坑深度,单位:mm(默认值:1.0) // 椭圆拟合参数 @@ -29,23 +19,38 @@ struct SHoleDetectionParams { float maxRadius; // 最大孔洞半径,单位:mm(默认值:50.0) // 平面拟合参数 - int expansionSize1; // 第一环扩展大小,单位:mm(默认值:5) - int expansionSize2; // 第二环扩展大小,单位:mm(默认值:10) + int expansionSize1; // 第一圈扩展大小(默认值:5) + int expansionSize2; // 第二圈扩展大小(默认值:10) - // V型检测参数 - int minVTransitionPoints; // V型端点之间的最小有效过渡点数(默认值:1) + // V 型检测参数 + int minVTransitionPoints; // V 型端点之间的最小有效过渡点数(默认值:1) + float jumpThresholdResidual; // 相邻有效点的残差跳变阈值,<=0 表示自适应 + float gapJumpThresholdResidual; // 跨无效点间隙的残差跳变阈值,<=0 表示自适应 + int maxGapPointsInLine; // 允许跨越的最大无效点数 + float minFeatureSpan; // 特征点对最小弧长跨度(mm) + int residualSmoothWindow; // 残差平滑窗口(奇数,建议 3~7) + float slopeAngleThreshold; // 坡度补充判断阈值,单位:度(默认值:3.0) + // 当曲率角未超过 angleThreshold 时,若前后参考点间的 + // 净 Z 坡度角超过此阈值,则将该点判定为下降或上升趋势。 + // 设置为 0 可禁用坡度补充判断。 // 构造函数,设置默认值 SHoleDetectionParams() - : neighborCount(3) - , angleThresholdPos(10.0f) - , angleThresholdNeg(-10.0f) + : angleThresholdPos(30.0f) + , angleThresholdNeg(-30.0f) + , angleSearchDistance(2.0f) , minPitDepth(1.0f) , minRadius(2.0f) , maxRadius(50.0f) , expansionSize1(5) , expansionSize2(10) , minVTransitionPoints(1) + , jumpThresholdResidual(0.0f) + , gapJumpThresholdResidual(0.0f) + , maxGapPointsInLine(12) + , minFeatureSpan(2.0f) + , residualSmoothWindow(5) + , slopeAngleThreshold(3.0f) {} }; @@ -60,18 +65,18 @@ struct SHoleFilterParams { // 形状过滤(拟合前) float minAngularCoverage; // 最小角度覆盖范围,单位:度(默认值:10.0) // 用于过滤非闭合边界。设置为 0 可禁用。 - float maxRadiusFitRatio; // 最大半径拟合比率 radiusVariance/radius(默认值:1.0) - // 衡量点与圆的拟合程度。设置为 1.0 可禁用。 + float maxRadiusFitRatio; // 最大半径拟合比率 radiusVariance / radius(默认值:1.0) + // 衡量边界点与圆的拟合程度。设置为 1.0 可禁用。 float minQualityScore; // 最小整体质量分数(默认值:0.0) // 形状指标的加权组合。设置为 0 可禁用。 - // 平面性过滤(投影前) + // 平面一致性过滤(投影前) float maxPlaneResidual; // 最大点到平面残差,单位:mm(默认值:10.0) - // 拒绝非平面簇(例如悬崖、台阶边缘)。 + // 用于拒绝非平面簇,例如悬崖、台阶边缘。 float maxAngularGap; // 最大角度间隙,单位:度(默认值:90.0) - // 拒绝 L 型或非闭合边界。 - float minInlierRatio; // 椭圆拟合的最小内点比率(默认值:0.0) - // 在拟合椭圆容差范围内的点的比例。 + // 用于拒绝 L 型或非闭合边界。 + float minInlierRatio; // 圆拟合的最小内点比率(默认值:0.0) + // 表示落在拟合圆容差范围内的点所占比例。 // 构造函数,设置默认值 SHoleFilterParams() @@ -88,17 +93,17 @@ struct SHoleFilterParams { /** * @brief 单个孔洞检测结果 * - * 注意:SVzNL3DPointF 和 SVzNL2DPointF 在 VZNL_Types.h 中定义 + * 注意:SVzNL3DPointF 和 SVzNL2DPointF 在 VZNL_Types.h 中定义。 */ struct SHoleResult { SVzNL3DPointF center; // 孔洞中心点 (x, y, z) - SVzNL3DPointF normal; // 平面法向量(单位长度) + SVzNL3DPointF normal; // 拟合平面法向量(单位长度) float radius; // 孔洞半径,单位:mm float depth; // 凹坑深度,单位:mm - float eccentricity; // 离心率(0 = 完美圆形) - float radiusVariance; // 半径方差,单位:mm + float eccentricity; // 离心率(0 表示完美圆形) + float radiusVariance; // 半径离散度,单位:mm float angularSpan; // 角度覆盖范围,单位:度 - float qualityScore; // 质量分数(0-1,越高越好) + float qualityScore; // 质量分数(0~1,越高越好) SHoleResult() : center() @@ -146,11 +151,10 @@ inline void FreeMultiHoleResult(SMultiHoleResult* result) { } /** - * @brief 线段端点对结构 + * @brief 线段端点对结果 * - * 表示在线扫描中检测到的线段,包含起点和终点。 - * 注意:尽管名称为"PeakValley",但此结构存储的是线段端点, - * 不一定是峰值/谷值点。保留此命名是为了兼容性。 + * 表示在线扫描中检测到的一段特征,包含起点和终点。 + * 可用于描述凹坑边界、空洞间隙等一维特征。 */ struct SSegmentPair { SVzNLPointXYZ startPoint; // 线段起点 diff --git a/AppAlgo/holeDetection/include/PlaneSegmentation.h b/AppAlgo/holeDetection/include/PlaneSegmentation.h new file mode 100644 index 0000000..56aa8e0 --- /dev/null +++ b/AppAlgo/holeDetection/include/PlaneSegmentation.h @@ -0,0 +1,285 @@ +#ifndef PLANE_SEGMENTATION_H +#define PLANE_SEGMENTATION_H + +#include "../include/VZNL_Types.h" +#include "ErrorCodes.h" +#include + +/** + * @brief Z值直方图峰值信息 + */ +struct ZHistogramPeak { + float zValue; // 峰值对应的Z坐标 + int pointCount; // 该峰值区域的点数 + float zMin; // 峰值区域的Z最小值 + float zMax; // 峰值区域的Z最大值 + std::vector 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& 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& 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 diff --git a/AppAlgo/holeDetection/windows/x64/Debug/HoleDetectionLib.dll b/AppAlgo/holeDetection/windows/x64/Debug/HoleDetectionLib.dll index 87b1bef..217e114 100644 Binary files a/AppAlgo/holeDetection/windows/x64/Debug/HoleDetectionLib.dll and b/AppAlgo/holeDetection/windows/x64/Debug/HoleDetectionLib.dll differ diff --git a/AppAlgo/holeDetection/windows/x64/Debug/HoleDetectionLib.pdb b/AppAlgo/holeDetection/windows/x64/Debug/HoleDetectionLib.pdb index 5d03022..3aab682 100644 Binary files a/AppAlgo/holeDetection/windows/x64/Debug/HoleDetectionLib.pdb and b/AppAlgo/holeDetection/windows/x64/Debug/HoleDetectionLib.pdb differ diff --git a/AppAlgo/holeDetection/windows/x64/Release/HoleDetectionLib.dll b/AppAlgo/holeDetection/windows/x64/Release/HoleDetectionLib.dll index bd89b6b..3d512ab 100644 Binary files a/AppAlgo/holeDetection/windows/x64/Release/HoleDetectionLib.dll and b/AppAlgo/holeDetection/windows/x64/Release/HoleDetectionLib.dll differ