feat(可视化): 添加线段端点对可视化功能
refactor(参数): 简化孔洞检测和过滤参数结构 新增线段端点对检测回调函数和可视化方法,用于显示检测到的线段对。同时简化了孔洞检测参数结构,移除了不常用的聚类参数和半径过滤参数,使接口更加简洁。 修改了线段端点对结构体名称从SPeakValleyPair改为更准确的SSegmentPair,并更新了相关代码。添加了.gitignore文件忽略.ace-tool目录。
This commit is contained in:
parent
ceb02b935f
commit
e9ef8d2cc9
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
.claude
|
||||
nul
|
||||
Algo\DetectHole\Export
|
||||
build
|
||||
build
|
||||
Algo/DetectHole/Export/
|
||||
|
||||
1
Algo/DetectHole/.gitignore
vendored
Normal file
1
Algo/DetectHole/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
.ace-tool/
|
||||
@ -169,13 +169,9 @@ int main(int argc, char* argv[]) {
|
||||
detectionParams.minRadius = 5.0f; // 最小半径 5mm
|
||||
detectionParams.maxRadius = 50.0f; // 最大半径 50mm
|
||||
detectionParams.minPitDepth = 1.0f; // 最小深度 1mm
|
||||
detectionParams.clusterEps = 5.0f; // 聚类距离 5mm
|
||||
detectionParams.clusterMinPoints = 5; // 最小聚类点数
|
||||
|
||||
// 设置过滤参数
|
||||
SHoleFilterParams filterParams;
|
||||
filterParams.minHoleRadius = 3.0f; // 最小孔洞半径 3mm
|
||||
filterParams.maxHoleRadius = 100.0f; // 最大孔洞半径 100mm
|
||||
filterParams.maxEccentricity = 0.9f; // 最大离心率
|
||||
filterParams.minQualityScore = 0.3f; // 最小质量分数
|
||||
|
||||
@ -183,7 +179,6 @@ int main(int argc, char* argv[]) {
|
||||
std::cout << " 半径范围: " << detectionParams.minRadius << " - "
|
||||
<< detectionParams.maxRadius << " mm" << std::endl;
|
||||
std::cout << " 最小深度: " << detectionParams.minPitDepth << " mm" << std::endl;
|
||||
std::cout << " 聚类距离: " << detectionParams.clusterEps << " mm" << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
// 执行孔洞检测
|
||||
|
||||
@ -244,6 +244,151 @@ void HoleDetectionVisualizer::VisualizeBoundaryPoints(
|
||||
}
|
||||
}
|
||||
|
||||
void HoleDetectionVisualizer::VisualizeSegmentPairs(
|
||||
const SVzNLPointXYZ* points,
|
||||
int rows,
|
||||
int cols,
|
||||
const std::vector<SSegmentPair>& segmentPairs,
|
||||
const std::string& title)
|
||||
{
|
||||
int totalPoints = rows * cols;
|
||||
|
||||
// Create original point cloud (gray)
|
||||
vtkSmartPointer<vtkPoints> vtkPointsOrig = vtkPoints::New();
|
||||
for (int i = 0; i < totalPoints; i++) {
|
||||
if (std::isfinite(points[i].x) && std::isfinite(points[i].y) && std::isfinite(points[i].z)) {
|
||||
vtkPointsOrig->InsertNextPoint(points[i].x, points[i].y, points[i].z);
|
||||
}
|
||||
}
|
||||
|
||||
vtkSmartPointer<vtkPolyData> polyDataOrig = vtkPolyData::New();
|
||||
polyDataOrig->SetPoints(vtkPointsOrig);
|
||||
|
||||
vtkSmartPointer<vtkVertexGlyphFilter> vertexFilterOrig = vtkVertexGlyphFilter::New();
|
||||
vertexFilterOrig->SetInputData(polyDataOrig);
|
||||
vertexFilterOrig->Update();
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapperOrig = vtkPolyDataMapper::New();
|
||||
mapperOrig->SetInputConnection(vertexFilterOrig->GetOutputPort());
|
||||
|
||||
vtkSmartPointer<vtkActor> actorOrig = vtkActor::New();
|
||||
actorOrig->SetMapper(mapperOrig);
|
||||
actorOrig->GetProperty()->SetColor(0.8, 0.8, 0.8); // Gray
|
||||
actorOrig->GetProperty()->SetPointSize(2);
|
||||
|
||||
// Create renderer
|
||||
vtkSmartPointer<vtkRenderer> renderer = vtkRenderer::New();
|
||||
renderer->AddActor(actorOrig);
|
||||
renderer->SetBackground(0.1, 0.1, 0.1);
|
||||
|
||||
// Generate colors for each segment pair
|
||||
std::vector<double> colors = {
|
||||
1.0, 0.0, 0.0, // Red
|
||||
0.0, 1.0, 0.0, // Green
|
||||
0.0, 0.0, 1.0, // Blue
|
||||
1.0, 1.0, 0.0, // Yellow
|
||||
1.0, 0.0, 1.0, // Magenta
|
||||
0.0, 1.0, 1.0, // Cyan
|
||||
1.0, 0.5, 0.0, // Orange
|
||||
0.5, 0.0, 1.0, // Purple
|
||||
0.0, 1.0, 0.5, // Spring Green
|
||||
1.0, 0.0, 0.5 // Rose
|
||||
};
|
||||
|
||||
// Visualize each segment pair with different color
|
||||
for (size_t i = 0; i < segmentPairs.size(); i++) {
|
||||
const SSegmentPair& pair = segmentPairs[i];
|
||||
|
||||
// Choose color (cycle through colors)
|
||||
int colorIdx = (i % (colors.size() / 3)) * 3;
|
||||
double r = colors[colorIdx];
|
||||
double g = colors[colorIdx + 1];
|
||||
double b = colors[colorIdx + 2];
|
||||
|
||||
// Create start point sphere
|
||||
vtkSmartPointer<vtkSphereSource> startSphere = vtkSphereSource::New();
|
||||
startSphere->SetCenter(pair.startPoint.x, pair.startPoint.y, pair.startPoint.z);
|
||||
startSphere->SetRadius(0.5);
|
||||
startSphere->SetPhiResolution(10);
|
||||
startSphere->SetThetaResolution(10);
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> startMapper = vtkPolyDataMapper::New();
|
||||
startMapper->SetInputConnection(startSphere->GetOutputPort());
|
||||
|
||||
vtkSmartPointer<vtkActor> startActor = vtkActor::New();
|
||||
startActor->SetMapper(startMapper);
|
||||
startActor->GetProperty()->SetColor(r, g, b);
|
||||
|
||||
// Create end point sphere
|
||||
vtkSmartPointer<vtkSphereSource> endSphere = vtkSphereSource::New();
|
||||
endSphere->SetCenter(pair.endPoint.x, pair.endPoint.y, pair.endPoint.z);
|
||||
endSphere->SetRadius(0.5);
|
||||
endSphere->SetPhiResolution(10);
|
||||
endSphere->SetThetaResolution(10);
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> endMapper = vtkPolyDataMapper::New();
|
||||
endMapper->SetInputConnection(endSphere->GetOutputPort());
|
||||
|
||||
vtkSmartPointer<vtkActor> endActor = vtkActor::New();
|
||||
endActor->SetMapper(endMapper);
|
||||
endActor->GetProperty()->SetColor(r, g, b);
|
||||
|
||||
// Create line connecting start and end points
|
||||
vtkSmartPointer<vtkLineSource> line = vtkLineSource::New();
|
||||
line->SetPoint1(pair.startPoint.x, pair.startPoint.y, pair.startPoint.z);
|
||||
line->SetPoint2(pair.endPoint.x, pair.endPoint.y, pair.endPoint.z);
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> lineMapper = vtkPolyDataMapper::New();
|
||||
lineMapper->SetInputConnection(line->GetOutputPort());
|
||||
|
||||
vtkSmartPointer<vtkActor> lineActor = vtkActor::New();
|
||||
lineActor->SetMapper(lineMapper);
|
||||
lineActor->GetProperty()->SetColor(r, g, b);
|
||||
lineActor->GetProperty()->SetLineWidth(2);
|
||||
|
||||
// Add actors to renderer
|
||||
renderer->AddActor(startActor);
|
||||
renderer->AddActor(endActor);
|
||||
renderer->AddActor(lineActor);
|
||||
}
|
||||
|
||||
// Create text annotation
|
||||
vtkSmartPointer<vtkTextActor> textActor = vtkTextActor::New();
|
||||
std::ostringstream oss;
|
||||
oss << "Segment Pairs: " << segmentPairs.size();
|
||||
textActor->SetInput(oss.str().c_str());
|
||||
textActor->SetPosition(10, 10);
|
||||
textActor->GetTextProperty()->SetFontSize(20);
|
||||
textActor->GetTextProperty()->SetColor(1.0, 1.0, 1.0);
|
||||
renderer->AddActor2D(textActor);
|
||||
|
||||
renderer->ResetCamera();
|
||||
|
||||
// Create render window
|
||||
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkRenderWindow::New();
|
||||
renderWindow->AddRenderer(renderer);
|
||||
renderWindow->SetSize(1024, 768);
|
||||
renderWindow->SetWindowName(title.c_str());
|
||||
|
||||
if (m_interactive) {
|
||||
vtkSmartPointer<vtkRenderWindowInteractor> interactor =
|
||||
vtkSmartPointer<vtkRenderWindowInteractor>::New();
|
||||
interactor->SetRenderWindow(renderWindow);
|
||||
|
||||
// Set trackball camera interaction style
|
||||
vtkSmartPointer<vtkInteractorStyleTrackballCamera> style =
|
||||
vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
|
||||
interactor->SetInteractorStyle(style);
|
||||
|
||||
renderWindow->Render();
|
||||
interactor->Initialize();
|
||||
interactor->Start();
|
||||
} else {
|
||||
renderWindow->Render();
|
||||
SaveScreenshot(renderer, title + ".png");
|
||||
}
|
||||
}
|
||||
|
||||
void HoleDetectionVisualizer::VisualizeClusters(
|
||||
const SVzNLPointXYZ* points,
|
||||
int rows,
|
||||
|
||||
@ -54,6 +54,23 @@ public:
|
||||
const std::string& title = "Detected Boundary Points"
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Visualize segment endpoint pairs with different colors
|
||||
*
|
||||
* @param points Original point cloud
|
||||
* @param rows Number of rows
|
||||
* @param cols Number of columns
|
||||
* @param segmentPairs Detected segment pairs
|
||||
* @param title Window title
|
||||
*/
|
||||
void VisualizeSegmentPairs(
|
||||
const SVzNLPointXYZ* points,
|
||||
int rows,
|
||||
int cols,
|
||||
const std::vector<SSegmentPair>& segmentPairs,
|
||||
const std::string& title = "Detected Segment Pairs"
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Visualize clustered boundary points with different colors
|
||||
*
|
||||
|
||||
@ -270,6 +270,33 @@ void OnHoleFitted(const SHoleResult* hole, int holeIndex, void* userData) {
|
||||
delete[] tempResult.holes;
|
||||
}
|
||||
|
||||
// Callback: Segment pairs detected
|
||||
void OnSegmentPairsDetected(const SSegmentPair* segmentPairs, int count, void* userData) {
|
||||
CallbackUserData* data = static_cast<CallbackUserData*>(userData);
|
||||
if (!data || !data->enableVisualization || !data->visualizer) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "[DEBUG] Segment pairs detected: " << count << std::endl;
|
||||
|
||||
// Convert to vector for visualization
|
||||
std::vector<SSegmentPair> pairs;
|
||||
pairs.reserve(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
pairs.push_back(segmentPairs[i]);
|
||||
}
|
||||
|
||||
// Visualize segment endpoint pairs
|
||||
data->visualizer->VisualizeSegmentPairs(
|
||||
data->points,
|
||||
data->rows,
|
||||
data->cols,
|
||||
pairs,
|
||||
"Step 0: Detected Segment Endpoint Pairs"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Process a single file
|
||||
int ProcessSingleFile(const std::string& inputFile,
|
||||
bool interactive,
|
||||
@ -328,10 +355,11 @@ int ProcessSingleFile(const std::string& inputFile,
|
||||
callbackData.enableVisualization = interactive; // Only enable visualization in interactive mode
|
||||
|
||||
SHoleDetectionDebugCallbacks debugCallbacks;
|
||||
debugCallbacks.onBoundaryDetected = OnBoundaryDetected;
|
||||
debugCallbacks.onClustersFound = OnClustersFound;
|
||||
debugCallbacks.onExpandedRegion = OnExpandedRegion;
|
||||
debugCallbacks.onHoleFitted = OnHoleFitted;
|
||||
debugCallbacks.onBoundaryDetected = nullptr;// OnBoundaryDetected;
|
||||
debugCallbacks.onClustersFound = nullptr;// OnClustersFound;
|
||||
debugCallbacks.onExpandedRegion = nullptr;// OnExpandedRegion;
|
||||
debugCallbacks.onHoleFitted = nullptr;// OnHoleFitted;
|
||||
debugCallbacks.onSegmentPairsDetected = nullptr;//OnSegmentPairsDetected;
|
||||
debugCallbacks.userData = &callbackData;
|
||||
|
||||
SMultiHoleResult result;
|
||||
@ -495,12 +523,8 @@ int main(int argc, char* argv[]) {
|
||||
std::cout << " angleThresholdPos: " << detectionParams.angleThresholdPos << "°" << std::endl;
|
||||
std::cout << " angleThresholdNeg: " << detectionParams.angleThresholdNeg << "°" << std::endl;
|
||||
std::cout << " minPitDepth: " << detectionParams.minPitDepth << " mm" << std::endl;
|
||||
std::cout << " clusterEps: " << detectionParams.clusterEps << " mm" << std::endl;
|
||||
std::cout << " clusterMinPoints: " << detectionParams.clusterMinPoints << std::endl;
|
||||
|
||||
std::cout << "\nFilter Parameters:" << std::endl;
|
||||
std::cout << " minHoleRadius: " << filterParams.minHoleRadius << " mm" << std::endl;
|
||||
std::cout << " maxHoleRadius: " << filterParams.maxHoleRadius << " mm" << std::endl;
|
||||
std::cout << " maxEccentricity: " << filterParams.maxEccentricity << std::endl;
|
||||
|
||||
int result = ProcessSingleFile(inputPath, interactive, outputDir, showLines,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -82,6 +82,14 @@ struct SHoleDetectionDebugCallbacks {
|
||||
*/
|
||||
void (*onHoleFitted)(const SHoleResult* hole, int holeIndex, void* userData);
|
||||
|
||||
/**
|
||||
* @brief Called when segment endpoint pairs are detected
|
||||
* @param segmentPairs Array of segment pairs (each pair has start and end points)
|
||||
* @param count Number of segment pairs
|
||||
* @param userData User-provided context pointer
|
||||
*/
|
||||
void (*onSegmentPairsDetected)(const SSegmentPair* segmentPairs, int count, void* userData);
|
||||
|
||||
/**
|
||||
* @brief User-provided context pointer, passed to all callbacks
|
||||
*/
|
||||
|
||||
@ -2,141 +2,103 @@
|
||||
#define HOLE_DETECTION_PARAMS_H
|
||||
|
||||
#include <cmath>
|
||||
#include "../include/VZNL_Types.h" // Use types from VZNL_Types.h
|
||||
#include "../include/VZNL_Types.h" // 使用 VZNL_Types.h 中的类型
|
||||
|
||||
/**
|
||||
* @brief Sorting mode for detected holes
|
||||
* @brief 检测到的孔洞排序模式
|
||||
*/
|
||||
enum ESortMode {
|
||||
keSortMode_None = 0, // No sorting
|
||||
keSortMode_ByRadius = 1, // Sort by radius (largest first)
|
||||
keSortMode_ByDepth = 2, // Sort by depth (deepest first)
|
||||
keSortMode_ByQuality = 3 // Sort by quality score (highest first)
|
||||
keSortMode_None = 0, // 不排序
|
||||
keSortMode_ByRadius = 1, // 按半径排序(最大的在前)
|
||||
keSortMode_ByDepth = 2, // 按深度排序(最深的在前)
|
||||
keSortMode_ByQuality = 3 // 按质量分数排序(最高的在前)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Detection parameters for hole detection algorithm
|
||||
* @brief 孔洞检测算法的检测参数
|
||||
*/
|
||||
struct SHoleDetectionParams {
|
||||
// Pit detection parameters
|
||||
int neighborCount; // Adjacent points for line connection (default: 3)
|
||||
float angleThresholdPos; // Positive angle threshold in degrees (default: 70.0)
|
||||
float angleThresholdNeg; // Negative angle threshold in degrees (default: -70.0)
|
||||
float minPitDepth; // Minimum pit depth in mm (default: 5.0)
|
||||
// 凹坑检测参数
|
||||
int neighborCount; // 线连接的相邻点数(默认值:3)
|
||||
float angleThresholdPos; // 正角度阈值,单位:度(默认值:10.0)
|
||||
float angleThresholdNeg; // 负角度阈值,单位:度(默认值:-10.0)
|
||||
float minPitDepth; // 最小凹坑深度,单位:mm(默认值:1.0)
|
||||
|
||||
// Radial scanning parameters
|
||||
float angleStep; // Angular step for radial scan in degrees (default: 1.0)
|
||||
float maxScanRadius; // Maximum scan radius in mm (default: 100.0)
|
||||
// 椭圆拟合参数
|
||||
float minRadius; // 最小孔洞半径,单位:mm(默认值:2.0)
|
||||
float maxRadius; // 最大孔洞半径,单位:mm(默认值:50.0)
|
||||
|
||||
// Clustering parameters (DBSCAN)
|
||||
float clusterEps; // DBSCAN epsilon in mm (default: 10.0)
|
||||
int clusterMinPoints; // DBSCAN min points (default: 5)
|
||||
// 平面拟合参数
|
||||
int expansionSize1; // 第一环扩展大小,单位:mm(默认值:5)
|
||||
int expansionSize2; // 第二环扩展大小,单位:mm(默认值:10)
|
||||
|
||||
// Ellipse fitting parameters
|
||||
float minRadius; // Minimum hole radius in mm (default: 5.0)
|
||||
float maxRadius; // Maximum hole radius in mm (default: 50.0)
|
||||
// V型检测参数
|
||||
int minVTransitionPoints; // V型端点之间的最小有效过渡点数(默认值:1)
|
||||
|
||||
// Plane fitting parameters
|
||||
int expansionSize1; // First ring expansion in mm (default: 10.0)
|
||||
int expansionSize2; // Second ring expansion in mm (default: 20.0)
|
||||
|
||||
// Validation parameters
|
||||
float validZThreshold; // Valid Z-value threshold (default: 1e-4)
|
||||
|
||||
// V-type detection parameters
|
||||
int minVTransitionPoints; // Minimum valid transition points between V-shape endpoints (default: 3)
|
||||
|
||||
// Corner-based angle detection parameters (similar to cornerMethod)
|
||||
float cornerScale; // Search distance for forward/backward points in mm (default: 5.0)
|
||||
float cornerAngleThreshold; // Minimum corner angle change in degrees (default: 15.0)
|
||||
float jumpCornerTh_1; // Small angle threshold for jump detection (default: 10.0)
|
||||
float jumpCornerTh_2; // Large angle threshold for jump detection (default: 30.0)
|
||||
float minEndingGap; // Y-direction distance threshold for jump pairing in mm (default: 5.0)
|
||||
float minEndingGap_z; // Z-direction height threshold for jump validation in mm (default: 1.0)
|
||||
|
||||
// Constructor with defaults
|
||||
// 构造函数,设置默认值
|
||||
SHoleDetectionParams()
|
||||
: neighborCount(3)
|
||||
, angleThresholdPos(10.0f)
|
||||
, angleThresholdNeg(-10.0f)
|
||||
, minPitDepth(1.0f)
|
||||
, angleStep(1.0f)
|
||||
, maxScanRadius(100.0f)
|
||||
, clusterEps(10.0f)
|
||||
, clusterMinPoints(3)
|
||||
, minRadius(2.0f)
|
||||
, maxRadius(50.0f)
|
||||
, expansionSize1(5)
|
||||
, expansionSize2(10)
|
||||
, validZThreshold(1e-4f)
|
||||
, minVTransitionPoints(1)
|
||||
, cornerScale(5.0f)
|
||||
, cornerAngleThreshold(45.0f)
|
||||
, jumpCornerTh_1(10.0f)
|
||||
, jumpCornerTh_2(30.0f)
|
||||
, minEndingGap(5.0f)
|
||||
, minEndingGap_z(1.0f)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Filter parameters for hole filtering
|
||||
* @brief 孔洞过滤参数
|
||||
*/
|
||||
struct SHoleFilterParams {
|
||||
// Size range filtering
|
||||
float minHoleRadius; // Minimum hole radius in mm (default: 5.0)
|
||||
float maxHoleRadius; // Maximum hole radius in mm (default: 50.0)
|
||||
|
||||
// Quality threshold filtering
|
||||
float maxEccentricity; // Maximum eccentricity (default: 0.5, standard e=sqrt(1-(b/a)^2))
|
||||
// 质量阈值过滤
|
||||
float maxEccentricity; // 最大离心率(默认值:0.99995,标准公式 e=sqrt(1-(b/a)^2))
|
||||
|
||||
// Shape filtering (pre-fitting)
|
||||
float maxCornerRatio; // Maximum corner ratio for rectangularity (default: 0.15)
|
||||
// Higher = more rectangular. Set to 1.0 to disable.
|
||||
float minAngularCoverage; // Minimum angular coverage in degrees (default: 300.0)
|
||||
// Used to filter non-closed boundaries. Set to 0 to disable.
|
||||
float maxRadiusFitRatio; // Maximum radiusVariance/radius ratio (default: 0.3)
|
||||
// Measures how well points fit the circle. Set to 1.0 to disable.
|
||||
float minQualityScore; // Minimum overall quality score (default: 0.3)
|
||||
// Weighted combination of shape metrics. Set to 0 to disable.
|
||||
// 形状过滤(拟合前)
|
||||
float minAngularCoverage; // 最小角度覆盖范围,单位:度(默认值:10.0)
|
||||
// 用于过滤非闭合边界。设置为 0 可禁用。
|
||||
float maxRadiusFitRatio; // 最大半径拟合比率 radiusVariance/radius(默认值:1.0)
|
||||
// 衡量点与圆的拟合程度。设置为 1.0 可禁用。
|
||||
float minQualityScore; // 最小整体质量分数(默认值:0.0)
|
||||
// 形状指标的加权组合。设置为 0 可禁用。
|
||||
|
||||
// Planarity filtering (pre-projection)
|
||||
float maxPlaneResidual; // Maximum point-to-plane residual in mm (default: 10.0)
|
||||
// Rejects non-planar clusters (e.g. cliffs, step edges).
|
||||
float maxAngularGap; // Maximum angular gap in degrees (default: 90.0)
|
||||
// Rejects L-shaped or non-closed boundaries.
|
||||
float minInlierRatio; // Minimum inlier ratio for ellipse fit (default: 0.7)
|
||||
// Fraction of points within tolerance of fitted ellipse.
|
||||
// 平面性过滤(投影前)
|
||||
float maxPlaneResidual; // 最大点到平面残差,单位:mm(默认值:10.0)
|
||||
// 拒绝非平面簇(例如悬崖、台阶边缘)。
|
||||
float maxAngularGap; // 最大角度间隙,单位:度(默认值:90.0)
|
||||
// 拒绝 L 型或非闭合边界。
|
||||
float minInlierRatio; // 椭圆拟合的最小内点比率(默认值:0.0)
|
||||
// 在拟合椭圆容差范围内的点的比例。
|
||||
|
||||
// Constructor with defaults
|
||||
// 构造函数,设置默认值
|
||||
SHoleFilterParams()
|
||||
: minHoleRadius(1.0f)
|
||||
, maxHoleRadius(10.0f)
|
||||
, maxEccentricity(0.99995f)
|
||||
, maxCornerRatio(0.15f)
|
||||
: maxEccentricity(0.99995f)
|
||||
, minAngularCoverage(10.f)
|
||||
, maxRadiusFitRatio(0.3f)
|
||||
, minQualityScore(0.3f)
|
||||
, maxRadiusFitRatio(1.f)
|
||||
, minQualityScore(0.f)
|
||||
, maxPlaneResidual(10.0f)
|
||||
, maxAngularGap(90.0f)
|
||||
, minInlierRatio(0.3f)
|
||||
, minInlierRatio(0.f)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Single hole detection result
|
||||
* @brief 单个孔洞检测结果
|
||||
*
|
||||
* Note: SVzNL3DPointF and SVzNL2DPointF are defined in VZNL_Types.h
|
||||
* 注意:SVzNL3DPointF 和 SVzNL2DPointF 在 VZNL_Types.h 中定义
|
||||
*/
|
||||
struct SHoleResult {
|
||||
SVzNL3DPointF center; // Hole center point (x, y, z)
|
||||
SVzNL3DPointF normal; // Plane normal vector (unit length)
|
||||
float radius; // Hole radius in mm
|
||||
float depth; // Pit depth in mm
|
||||
float eccentricity; // Eccentricity (0 = perfect circle)
|
||||
float radiusVariance; // Radius variance in mm
|
||||
float angularSpan; // Angular coverage in degrees
|
||||
float qualityScore; // Quality score (0-1, higher = better)
|
||||
SVzNL3DPointF center; // 孔洞中心点 (x, y, z)
|
||||
SVzNL3DPointF normal; // 平面法向量(单位长度)
|
||||
float radius; // 孔洞半径,单位:mm
|
||||
float depth; // 凹坑深度,单位:mm
|
||||
float eccentricity; // 离心率(0 = 完美圆形)
|
||||
float radiusVariance; // 半径方差,单位:mm
|
||||
float angularSpan; // 角度覆盖范围,单位:度
|
||||
float qualityScore; // 质量分数(0-1,越高越好)
|
||||
|
||||
SHoleResult()
|
||||
: center()
|
||||
@ -151,16 +113,16 @@ struct SHoleResult {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Multiple hole detection result
|
||||
* @brief 多孔洞检测结果
|
||||
*
|
||||
* @note Memory management: The holes array is NOT automatically freed.
|
||||
* Caller must call FreeMultiHoleResult() or manually delete[] holes.
|
||||
* @note 内存管理:holes 数组不会自动释放。
|
||||
* 调用者必须调用 FreeMultiHoleResult() 或手动 delete[] holes。
|
||||
*/
|
||||
struct SMultiHoleResult {
|
||||
int holeCount; // Number of detected holes
|
||||
SHoleResult* holes; // Array of hole results (caller must free)
|
||||
int totalCandidates; // Total candidate holes before filtering
|
||||
int filteredCount; // Number of holes filtered out
|
||||
int holeCount; // 检测到的孔洞数量
|
||||
SHoleResult* holes; // 孔洞结果数组(调用者必须释放)
|
||||
int totalCandidates; // 过滤前的候选孔洞总数
|
||||
int filteredCount; // 被过滤掉的孔洞数量
|
||||
|
||||
SMultiHoleResult()
|
||||
: holeCount(0)
|
||||
@ -171,9 +133,9 @@ struct SMultiHoleResult {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Free memory allocated by DetectMultipleHoles
|
||||
* @brief 释放 DetectMultipleHoles 分配的内存
|
||||
*
|
||||
* @param [in,out] result Result structure to free
|
||||
* @param [in,out] result 要释放的结果结构
|
||||
*/
|
||||
inline void FreeMultiHoleResult(SMultiHoleResult* result) {
|
||||
if (result != nullptr && result->holes != nullptr) {
|
||||
@ -184,28 +146,28 @@ inline void FreeMultiHoleResult(SMultiHoleResult* result) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Segment endpoints pair structure
|
||||
* @brief 线段端点对结构
|
||||
*
|
||||
* Represents a segment detected in a line scan, with start and end points.
|
||||
* Note: Despite the name "PeakValley", this structure stores segment endpoints,
|
||||
* not necessarily peak/valley points. The naming is kept for compatibility.
|
||||
* 表示在线扫描中检测到的线段,包含起点和终点。
|
||||
* 注意:尽管名称为"PeakValley",但此结构存储的是线段端点,
|
||||
* 不一定是峰值/谷值点。保留此命名是为了兼容性。
|
||||
*/
|
||||
struct SPeakValleyPair {
|
||||
SVzNLPointXYZ peakPoint; // Segment start point
|
||||
SVzNLPointXYZ valleyPoint; // Segment end point
|
||||
int peakRow; // Start point row index
|
||||
int peakCol; // Start point column index
|
||||
int valleyRow; // End point row index
|
||||
int valleyCol; // End point column index
|
||||
float depth; // Depth difference between start and end points
|
||||
struct SSegmentPair {
|
||||
SVzNLPointXYZ startPoint; // 线段起点
|
||||
SVzNLPointXYZ endPoint; // 线段终点
|
||||
int startRow; // 起点行索引
|
||||
int startCol; // 起点列索引
|
||||
int endRow; // 终点行索引
|
||||
int endCol; // 终点列索引
|
||||
float depth; // 起点和终点之间的深度差
|
||||
|
||||
SPeakValleyPair()
|
||||
: peakPoint()
|
||||
, valleyPoint()
|
||||
, peakRow(0)
|
||||
, peakCol(0)
|
||||
, valleyRow(0)
|
||||
, valleyCol(0)
|
||||
SSegmentPair()
|
||||
: startPoint()
|
||||
, endPoint()
|
||||
, startRow(0)
|
||||
, startCol(0)
|
||||
, endRow(0)
|
||||
, endCol(0)
|
||||
, depth(0.0f)
|
||||
{}
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user