HoleDetect 小孔检测算法更新
This commit is contained in:
parent
2b86078d0c
commit
b1ecdd6ab6
@ -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
|
||||
|
||||
// 构建日期
|
||||
|
||||
@ -1,3 +1,9 @@
|
||||
# 1.1.0 2026-03-125
|
||||
## build_1
|
||||
1. 算法优化
|
||||
2. 配置结构修改
|
||||
3. 手眼标定,网络配置公用
|
||||
|
||||
# 1.0.0 2026-03-11
|
||||
## build_4
|
||||
1. 修复矩阵配置
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>780</width>
|
||||
<height>656</height>
|
||||
<height>541</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -323,6 +323,12 @@ QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px;
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_calibMatrix">
|
||||
<attribute name="title">
|
||||
<string>手眼标定</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_handEyeCalibHost"/>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_network">
|
||||
<attribute name="title">
|
||||
<string>网络配置</string>
|
||||
@ -390,12 +396,6 @@ QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px;
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_calibMatrix">
|
||||
<attribute name="title">
|
||||
<string>手眼标定</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_handEyeCalibHost"/>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@ -435,6 +435,19 @@ QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px;
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_camer_cancel">
|
||||
<property name="minimumSize">
|
||||
|
||||
@ -4,6 +4,11 @@ TEMPLATE = lib
|
||||
CONFIG += staticlib
|
||||
CONFIG += c++11
|
||||
|
||||
# 编码设置
|
||||
win32-msvc {
|
||||
QMAKE_CXXFLAGS += /utf-8
|
||||
}
|
||||
|
||||
# Output directory configuration
|
||||
TARGET = HoleDetectionConfig
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -7,7 +7,6 @@ namespace AlgoParamConverter
|
||||
SHoleDetectionParams ToAlgoParam(const VrHoleDetectionParam& param)
|
||||
{
|
||||
SHoleDetectionParams algo;
|
||||
algo.neighborCount = param.neighborCount;
|
||||
algo.angleThresholdPos = static_cast<float>(param.angleThresholdPos);
|
||||
algo.angleThresholdNeg = static_cast<float>(param.angleThresholdNeg);
|
||||
algo.minPitDepth = static_cast<float>(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,
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -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
|
||||
*/
|
||||
|
||||
@ -2,26 +2,16 @@
|
||||
#define HOLE_DETECTION_PARAMS_H
|
||||
|
||||
#include <cmath>
|
||||
#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; // 线段起点
|
||||
|
||||
285
AppAlgo/holeDetection/include/PlaneSegmentation.h
Normal file
285
AppAlgo/holeDetection/include/PlaneSegmentation.h
Normal file
@ -0,0 +1,285 @@
|
||||
#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
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user