Compare commits
10 Commits
6c55510809
...
7969a242ba
| Author | SHA1 | Date | |
|---|---|---|---|
| 7969a242ba | |||
| 1d649f9c01 | |||
| 916f2c7662 | |||
| 3aae9159ed | |||
| 9d304b19ac | |||
| 937e9c0d8a | |||
|
|
976f87b6ba | ||
| 2e92ddfab0 | |||
| 0d88858738 | |||
|
|
cced2a9646 |
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,4 +1,7 @@
|
||||
.claude
|
||||
nul
|
||||
build
|
||||
Algo/DetectHole/Export/
|
||||
Algo/DetectHole/Export
|
||||
Algo/DetectBarIntersection/build
|
||||
Algo/DetectBarIntersection/data
|
||||
Algo/DetectBarIntersection/Export
|
||||
@ -1,23 +1,32 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(DetectBarIntersection VERSION 1.0.0 LANGUAGES CXX)
|
||||
|
||||
# Set C++ standard
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(WIN32)
|
||||
if(MSVC)
|
||||
add_compile_options(
|
||||
/wd4267
|
||||
/wd4996
|
||||
)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
add_compile_options(/O2)
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
message(STATUS "Debug mode: Adding debug flags")
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(DetectBarIntersection VERSION 1.0.0 LANGUAGES CXX)
|
||||
|
||||
# Set C++ standard
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
string(REPLACE ";" ", " DETECTBARINTERSECTION_CONFIGURATION_LIST "${CMAKE_CONFIGURATION_TYPES}")
|
||||
set(DETECTBARINTERSECTION_BUILD_DESCRIPTION "Multi-config (${DETECTBARINTERSECTION_CONFIGURATION_LIST})")
|
||||
else()
|
||||
set(DETECTBARINTERSECTION_BUILD_DESCRIPTION "${CMAKE_BUILD_TYPE}")
|
||||
endif()
|
||||
|
||||
if(NOT DETECTBARINTERSECTION_BUILD_DESCRIPTION)
|
||||
set(DETECTBARINTERSECTION_BUILD_DESCRIPTION "Not specified")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
if(MSVC)
|
||||
add_compile_options(
|
||||
/wd4267
|
||||
/wd4996
|
||||
$<$<CONFIG:Release>:/O2>
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
message(STATUS "Debug mode: Adding debug flags")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0 -Wall -Wextra")
|
||||
add_definitions(-DDEBUG)
|
||||
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
@ -232,11 +241,11 @@ if(BUILD_EXAMPLES)
|
||||
endif()
|
||||
|
||||
# Print configuration summary
|
||||
message(STATUS "")
|
||||
message(STATUS "DetectBarIntersection Configuration Summary:")
|
||||
message(STATUS " C++ Standard: ${CMAKE_CXX_STANDARD}")
|
||||
message(STATUS " Build Type: ${CMAKE_BUILD_TYPE}")
|
||||
message(STATUS " Eigen3 Include: ${EIGEN3_INCLUDE_DIR}")
|
||||
message(STATUS " OpenMP Enabled: ${ENABLE_OPENMP}")
|
||||
message(STATUS " Build Examples: ${BUILD_EXAMPLES}")
|
||||
message(STATUS "")
|
||||
message(STATUS "")
|
||||
message(STATUS "DetectBarIntersection Configuration Summary:")
|
||||
message(STATUS " C++ Standard: ${CMAKE_CXX_STANDARD}")
|
||||
message(STATUS " Build Type: ${DETECTBARINTERSECTION_BUILD_DESCRIPTION}")
|
||||
message(STATUS " Eigen3 Include: ${EIGEN3_INCLUDE_DIR}")
|
||||
message(STATUS " OpenMP Enabled: ${ENABLE_OPENMP}")
|
||||
message(STATUS " Build Examples: ${BUILD_EXAMPLES}")
|
||||
message(STATUS "")
|
||||
|
||||
@ -1,26 +1,33 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
echo === Building DetectBarIntersection ===
|
||||
|
||||
if not exist build (
|
||||
mkdir build
|
||||
)
|
||||
|
||||
cd build
|
||||
|
||||
cmake .. -G "Visual Studio 17 2022" -A x64
|
||||
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo CMake configuration failed!
|
||||
exit /b %ERRORLEVEL%
|
||||
)
|
||||
|
||||
cmake --build . --config Debug
|
||||
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo Build failed!
|
||||
exit /b %ERRORLEVEL%
|
||||
)
|
||||
|
||||
echo === Build completed successfully ===
|
||||
@echo off
|
||||
setlocal EnableExtensions
|
||||
|
||||
set "BUILD_CONFIG=Debug"
|
||||
|
||||
if not "%~1"=="" (
|
||||
if /I "%~1"=="Debug" (
|
||||
set "BUILD_CONFIG=Debug"
|
||||
) else if /I "%~1"=="Release" (
|
||||
set "BUILD_CONFIG=Release"
|
||||
) else (
|
||||
echo Usage: %~nx0 [Debug^|Release]
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
echo === Building DetectBarIntersection [%BUILD_CONFIG%] ===
|
||||
|
||||
cmake -S . -B build -G "Visual Studio 17 2022" -A x64
|
||||
|
||||
if errorlevel 1 (
|
||||
echo CMake configuration failed!
|
||||
exit /b %ERRORLEVEL%
|
||||
)
|
||||
|
||||
cmake --build build --config %BUILD_CONFIG%
|
||||
|
||||
if errorlevel 1 (
|
||||
echo Build failed!
|
||||
exit /b %ERRORLEVEL%
|
||||
)
|
||||
|
||||
echo === Build completed successfully [%BUILD_CONFIG%] ===
|
||||
|
||||
@ -8,8 +8,8 @@ if(WIN32)
|
||||
add_subdirectory(visualization_demo)
|
||||
endif()
|
||||
|
||||
message(STATUS "")
|
||||
message(STATUS "Examples Configuration:")
|
||||
message(STATUS " Build Type: ${CMAKE_BUILD_TYPE}")
|
||||
message(STATUS " DetectBarIntersection Root: ${DETECTBARINTERSECTION_ROOT}")
|
||||
message(STATUS "")
|
||||
message(STATUS "")
|
||||
message(STATUS "Examples Configuration:")
|
||||
message(STATUS " Build Type: ${DETECTBARINTERSECTION_BUILD_DESCRIPTION}")
|
||||
message(STATUS " DetectBarIntersection Root: ${DETECTBARINTERSECTION_ROOT}")
|
||||
message(STATUS "")
|
||||
|
||||
@ -54,11 +54,11 @@ public:
|
||||
const std::string& title = "Detection Result"
|
||||
);
|
||||
|
||||
/** @brief Visualize best cluster highlighted (filtered aligned points) */
|
||||
void VisualizeBestCluster(
|
||||
const SBarIntersectionResult& result,
|
||||
const std::string& title = "Best Cluster"
|
||||
);
|
||||
/** @brief Visualize best cluster highlighted (filtered aligned points) */
|
||||
void VisualizeBestCluster(
|
||||
const SBarIntersectionResult& result,
|
||||
const std::string& title = "Best Cluster"
|
||||
);
|
||||
|
||||
void SetInteractive(bool interactive);
|
||||
void SetOutputDirectory(const std::string& dir);
|
||||
|
||||
@ -48,27 +48,38 @@ if(VTK_FOUND)
|
||||
${VTK_LIBRARIES}
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
add_custom_command(TARGET visualization_demo POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"$<TARGET_FILE:BarIntersectionLib>"
|
||||
"$<TARGET_FILE_DIR:visualization_demo>"
|
||||
if(WIN32)
|
||||
add_custom_command(TARGET visualization_demo POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"$<TARGET_FILE:BarIntersectionLib>"
|
||||
"$<TARGET_FILE_DIR:visualization_demo>"
|
||||
COMMENT "Copying BarIntersectionLib DLL to visualization_demo output directory"
|
||||
)
|
||||
|
||||
set(VTK_BIN_DIR "${DETECTBARINTERSECTION_ROOT}/../../3rdparty/VTK-8.2.0/bin")
|
||||
|
||||
# Copy VTK DLLs
|
||||
file(GLOB VTK_DLLS "${VTK_BIN_DIR}/*.dll")
|
||||
foreach(vtk_dll ${VTK_DLLS})
|
||||
add_custom_command(TARGET visualization_demo POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${vtk_dll}"
|
||||
"$<TARGET_FILE_DIR:visualization_demo>"
|
||||
COMMENT "Copying VTK DLL: ${vtk_dll}"
|
||||
)
|
||||
endforeach()
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "VTK not found. visualization_demo will not be built.")
|
||||
endif()
|
||||
set(VTK_BIN_DIR "${DETECTBARINTERSECTION_ROOT}/../../3rdparty/VTK-8.2.0/bin")
|
||||
|
||||
# Copy VTK DLLs
|
||||
file(GLOB VTK_DLLS "${VTK_BIN_DIR}/*.dll")
|
||||
set(VTK_DEBUG_DLLS)
|
||||
set(VTK_RELEASE_DLLS)
|
||||
foreach(vtk_dll ${VTK_DLLS})
|
||||
get_filename_component(vtk_dll_name "${vtk_dll}" NAME)
|
||||
if(vtk_dll_name MATCHES "d\\.dll$")
|
||||
list(APPEND VTK_DEBUG_DLLS "${vtk_dll}")
|
||||
else()
|
||||
list(APPEND VTK_RELEASE_DLLS "${vtk_dll}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_custom_command(TARGET visualization_demo POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"$<$<CONFIG:Debug>:${VTK_DEBUG_DLLS}>"
|
||||
"$<$<NOT:$<CONFIG:Debug>>:${VTK_RELEASE_DLLS}>"
|
||||
"$<TARGET_FILE_DIR:visualization_demo>"
|
||||
COMMAND_EXPAND_LISTS
|
||||
COMMENT "Copying configuration-matched VTK DLLs to visualization_demo output directory"
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "VTK not found. visualization_demo will not be built.")
|
||||
endif()
|
||||
|
||||
@ -224,7 +224,7 @@ int ProcessSingleFile(
|
||||
debugCallbacks.onPlaneSegmented = nullptr;// OnPlaneSegmented;
|
||||
debugCallbacks.onPointsAligned = nullptr;// OnPointsAligned;
|
||||
debugCallbacks.onPlaneFiltered = nullptr;// OnPlaneFiltered;
|
||||
debugCallbacks.onClustersDetected = OnClustersDetected;
|
||||
debugCallbacks.onClustersDetected = nullptr;// OnClustersDetected;
|
||||
debugCallbacks.userData = &callbackData;
|
||||
|
||||
// Set parameters
|
||||
|
||||
@ -1,93 +1,109 @@
|
||||
#ifndef BAR_INTERSECTION_PARAMS_H
|
||||
#define BAR_INTERSECTION_PARAMS_H
|
||||
|
||||
#include "VZNL_Types.h"
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @brief RANSAC 平面分割参数
|
||||
*/
|
||||
struct SPlaneSegmentationParams {
|
||||
float distanceThreshold; // 点到平面距离阈值 (mm)
|
||||
int maxIterations; // RANSAC 最大迭代次数
|
||||
int minPlanePoints; // 最小平面点数
|
||||
float minPlaneRatio; // 平面最小点数占比
|
||||
float heightThreshold; // 高于平面的最小高度,用于过滤平面点 (mm)
|
||||
|
||||
SPlaneSegmentationParams()
|
||||
: distanceThreshold(1.0f)
|
||||
, maxIterations(500)
|
||||
, minPlanePoints(1000)
|
||||
, minPlaneRatio(0.05f)
|
||||
, heightThreshold(10.0f)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 区域生长参数
|
||||
*/
|
||||
struct SGrowthParams {
|
||||
float thresholdX; // 跨行合并阈值:相邻行 segment 质心 x 的最大允许差 (mm)
|
||||
float thresholdY; // 行内分段阈值:同行相邻点 y 的最大允许差 (mm)
|
||||
float thresholdZ; // 行内分段阈值:同行相邻点 z 的最大允许差 (mm)
|
||||
int minClusterSize; // 最小簇点数
|
||||
|
||||
SGrowthParams()
|
||||
: thresholdX(5.0f)
|
||||
, thresholdY(5.0f)
|
||||
, thresholdZ(5.0f)
|
||||
, minClusterSize(20)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 生长结果:一个连通簇
|
||||
*/
|
||||
struct SGrowthCluster {
|
||||
std::vector<int> pointIndices; // 簇内点在原始 rows*cols 网格中的线性索引
|
||||
SVzNL3DPointF centroid; // 簇质心
|
||||
SVzNL3DPointF minBound; // 包围盒最小角
|
||||
SVzNL3DPointF maxBound; // 包围盒最大角
|
||||
int pointCount;
|
||||
|
||||
SGrowthCluster()
|
||||
: centroid(), minBound(), maxBound(), pointCount(0)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 检测结果
|
||||
*/
|
||||
struct SBarIntersectionResult {
|
||||
// 平面信息
|
||||
SVzNL3DPointF planeNormal; // 平面法向量
|
||||
float planeD; // 平面方程 ax+by+cz+d=0 中的 d
|
||||
|
||||
// 簇(原始坐标系)
|
||||
int clusterCount;
|
||||
SGrowthCluster* clusters;
|
||||
|
||||
// 最优簇索引(-1表示无有效簇)
|
||||
int bestClusterIndex;
|
||||
|
||||
// 最优簇的过滤后点云(对齐坐标系,用于可视化)
|
||||
std::vector<SVzNLPointXYZ> bestClusterPoints;
|
||||
|
||||
SBarIntersectionResult()
|
||||
: planeNormal(), planeD(0.0f)
|
||||
, clusterCount(0), clusters(nullptr)
|
||||
, bestClusterIndex(-1)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 释放检测结果内存
|
||||
*/
|
||||
inline void FreeBarIntersectionResult(SBarIntersectionResult* result) {
|
||||
if (result) {
|
||||
if (result->clusters) { delete[] result->clusters; result->clusters = nullptr; }
|
||||
result->clusterCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BAR_INTERSECTION_PARAMS_H
|
||||
#ifndef BAR_INTERSECTION_PARAMS_H
|
||||
#define BAR_INTERSECTION_PARAMS_H
|
||||
|
||||
#include "VZNL_Types.h"
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @brief RANSAC 平面分割参数
|
||||
*/
|
||||
struct SPlaneSegmentationParams {
|
||||
float distanceThreshold; // 点到平面距离阈值 (mm)
|
||||
int maxIterations; // RANSAC 最大迭代次数
|
||||
int minPlanePoints; // 最小平面点数
|
||||
float minPlaneRatio; // 平面最小点数占比
|
||||
float heightThreshold; // 高于平面的最小高度,用于过滤平面点 (mm)
|
||||
|
||||
SPlaneSegmentationParams()
|
||||
: distanceThreshold(1.0f)
|
||||
, maxIterations(500)
|
||||
, minPlanePoints(1000)
|
||||
, minPlaneRatio(0.05f)
|
||||
, heightThreshold(10.0f)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 区域生长参数
|
||||
*/
|
||||
struct SGrowthParams {
|
||||
float thresholdX; // 跨行合并阈值:相邻行 segment 质心 x 的最大允许差 (mm)
|
||||
float thresholdY; // 行内分段阈值:同行相邻点 y 的最大允许差 (mm)
|
||||
float thresholdZ; // 行内分段阈值:同行相邻点 z 的最大允许差 (mm)
|
||||
int minClusterSize; // 最小簇点数
|
||||
float angleSearchDistance;
|
||||
int residualSmoothWindow;
|
||||
float maxAxisDeviationFromXYDeg; // Max allowed axis deviation from the XY plane (deg)
|
||||
float maxPerpendicularDeviationDeg; // Max deviation from 90 deg for centroid-connection test
|
||||
int minContinuousValidPointCount; // Min consecutive valid points kept on each laser line after plane filtering; <=1 disables
|
||||
float maxContinuousPointZTolerance; // Max z difference between adjacent points inside one valid run (mm)
|
||||
float minBarDiameter;
|
||||
float maxBarDiameter;
|
||||
|
||||
SGrowthParams()
|
||||
: thresholdX(5.0f)
|
||||
, thresholdY(5.0f)
|
||||
, thresholdZ(5.0f)
|
||||
, minClusterSize(20)
|
||||
, angleSearchDistance(2.f)
|
||||
, residualSmoothWindow(5)
|
||||
, maxAxisDeviationFromXYDeg(50.0f)
|
||||
, maxPerpendicularDeviationDeg(50.0f)
|
||||
, minContinuousValidPointCount(0)
|
||||
, maxContinuousPointZTolerance(5.0f)
|
||||
, minBarDiameter(10.0f)
|
||||
, maxBarDiameter(30.0f)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 生长结果:一个连通簇
|
||||
*/
|
||||
struct SGrowthCluster {
|
||||
std::vector<int> pointIndices; // 簇内点在原始 rows*cols 网格中的线性索引
|
||||
SVzNL3DPointF centroid; // 簇质心
|
||||
SVzNL3DPointF minBound; // 包围盒最小角
|
||||
SVzNL3DPointF maxBound; // 包围盒最大角
|
||||
int pointCount;
|
||||
|
||||
SGrowthCluster()
|
||||
: centroid(), minBound(), maxBound(), pointCount(0)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 检测结果
|
||||
*/
|
||||
struct SBarIntersectionResult {
|
||||
// 平面信息
|
||||
SVzNL3DPointF planeNormal; // 平面法向量
|
||||
float planeD; // 平面方程 ax+by+cz+d=0 中的 d
|
||||
|
||||
// 簇(原始坐标系)
|
||||
int clusterCount;
|
||||
SGrowthCluster* clusters;
|
||||
|
||||
// 最优簇索引(-1表示无有效簇)
|
||||
int bestClusterIndex;
|
||||
|
||||
// 最优簇的过滤后点云(对齐坐标系,用于可视化)
|
||||
std::vector<SVzNLPointXYZ> bestClusterPoints;
|
||||
|
||||
SBarIntersectionResult()
|
||||
: planeNormal(), planeD(0.0f)
|
||||
, clusterCount(0), clusters(nullptr)
|
||||
, bestClusterIndex(-1)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 释放检测结果内存
|
||||
*/
|
||||
inline void FreeBarIntersectionResult(SBarIntersectionResult* result) {
|
||||
if (result) {
|
||||
if (result->clusters) { delete[] result->clusters; result->clusters = nullptr; }
|
||||
result->clusterCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BAR_INTERSECTION_PARAMS_H
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include "BarIntersection.h"
|
||||
#include "PlaneAlignment.h"
|
||||
#include "RegionGrowing.h"
|
||||
#include <Eigen/Dense>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
@ -9,7 +10,7 @@
|
||||
#include <numeric>
|
||||
#include <limits>
|
||||
|
||||
static const char* s_algorithmVersion = "2.0.0";
|
||||
static const char* s_algorithmVersion = "1.0.0";
|
||||
static const char* s_algorithmName = "BarIntersectionDetection";
|
||||
|
||||
static bool IsValidPoint(const SVzNLPointXYZ& pt) {
|
||||
@ -17,7 +18,107 @@ static bool IsValidPoint(const SVzNLPointXYZ& pt) {
|
||||
return !(std::abs(pt.x) < eps && std::abs(pt.y) < eps && std::abs(pt.z) < eps);
|
||||
}
|
||||
|
||||
BAR_INTERSECTION_API int DetectBarIntersections(
|
||||
static void ClearPoint(SVzNLPointXYZ* pt) {
|
||||
if (!pt) {
|
||||
return;
|
||||
}
|
||||
|
||||
pt->x = 0.0f;
|
||||
pt->y = 0.0f;
|
||||
pt->z = 0.0f;
|
||||
}
|
||||
|
||||
static void ClearShortContinuousSegment(
|
||||
SVzNLPointXYZ* rowPoints,
|
||||
int startCol,
|
||||
int segmentLength,
|
||||
int minContinuousValidPointCount
|
||||
) {
|
||||
if (!rowPoints || startCol < 0 || segmentLength <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (segmentLength >= minContinuousValidPointCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int offset = 0; offset < segmentLength; ++offset) {
|
||||
ClearPoint(&rowPoints[startCol + offset]);
|
||||
}
|
||||
}
|
||||
|
||||
static void FilterLaserLineNoiseInPlace(
|
||||
SVzNLPointXYZ* alignedPoints,
|
||||
int rows,
|
||||
int cols,
|
||||
int minContinuousValidPointCount,
|
||||
float maxContinuousPointZTolerance
|
||||
) {
|
||||
if (!alignedPoints || rows <= 0 || cols <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (minContinuousValidPointCount <= 1 || maxContinuousPointZTolerance < 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int row = 0; row < rows; ++row) {
|
||||
SVzNLPointXYZ* rowPoints = alignedPoints + row * cols;
|
||||
int segmentStartCol = -1;
|
||||
int segmentLength = 0;
|
||||
float prevZ = 0.0f;
|
||||
|
||||
for (int col = 0; col < cols; ++col) {
|
||||
const SVzNLPointXYZ& pt = rowPoints[col];
|
||||
if (!IsValidPoint(pt)) {
|
||||
ClearShortContinuousSegment(
|
||||
rowPoints,
|
||||
segmentStartCol,
|
||||
segmentLength,
|
||||
minContinuousValidPointCount
|
||||
);
|
||||
segmentStartCol = -1;
|
||||
segmentLength = 0;
|
||||
prevZ = 0.0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (segmentLength <= 0) {
|
||||
segmentStartCol = col;
|
||||
segmentLength = 1;
|
||||
prevZ = pt.z;
|
||||
continue;
|
||||
}
|
||||
|
||||
const float zDiff = std::abs(pt.z - prevZ);
|
||||
if (zDiff <= maxContinuousPointZTolerance) {
|
||||
++segmentLength;
|
||||
prevZ = pt.z;
|
||||
continue;
|
||||
}
|
||||
|
||||
ClearShortContinuousSegment(
|
||||
rowPoints,
|
||||
segmentStartCol,
|
||||
segmentLength,
|
||||
minContinuousValidPointCount
|
||||
);
|
||||
|
||||
segmentStartCol = col;
|
||||
segmentLength = 1;
|
||||
prevZ = pt.z;
|
||||
}
|
||||
|
||||
ClearShortContinuousSegment(
|
||||
rowPoints,
|
||||
segmentStartCol,
|
||||
segmentLength,
|
||||
minContinuousValidPointCount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
int DetectBarIntersections(
|
||||
const SVzNLPointXYZ* points,
|
||||
int rows,
|
||||
int cols,
|
||||
@ -107,6 +208,17 @@ BAR_INTERSECTION_API int DetectBarIntersections(
|
||||
alignedPoints, totalPoints, planeZ, planeParams.heightThreshold
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// Step 2b: 按激光线过滤短连续段噪点
|
||||
// ============================================
|
||||
FilterLaserLineNoiseInPlace(
|
||||
alignedPoints,
|
||||
rows,
|
||||
cols,
|
||||
growthParams.minContinuousValidPointCount,
|
||||
growthParams.maxContinuousPointZTolerance
|
||||
);
|
||||
|
||||
// Debug callback: plane filtered
|
||||
if (debugCallbacks && debugCallbacks->onPlaneFiltered) {
|
||||
// 收集非零点用于回调显示
|
||||
@ -137,7 +249,10 @@ BAR_INTERSECTION_API int DetectBarIntersections(
|
||||
// ============================================
|
||||
std::vector<SGrowthCluster> clusters;
|
||||
bar_intersection::RegionGrowClusters(
|
||||
alignedPoints, rows, cols, growthParams, clusters
|
||||
alignedPoints, rows, cols, true, growthParams, clusters
|
||||
);
|
||||
bar_intersection::RegionGrowClusters(
|
||||
alignedPoints, rows, cols, false, growthParams, clusters
|
||||
);
|
||||
|
||||
// ============================================
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
#ifndef REGION_GROWING_H
|
||||
#ifndef REGION_GROWING_H
|
||||
#define REGION_GROWING_H
|
||||
|
||||
#include "VZNL_Types.h"
|
||||
@ -28,6 +28,7 @@ int RegionGrowClusters(
|
||||
const SVzNLPointXYZ* points,
|
||||
int rows,
|
||||
int cols,
|
||||
bool bHorizontalScan,
|
||||
const SGrowthParams& params,
|
||||
std::vector<SGrowthCluster>& outClusters
|
||||
);
|
||||
|
||||
@ -16,6 +16,8 @@ struct RansacPlaneSegmentationParams {
|
||||
float minPlaneRatio; // 平面最小点数占比 (相对最大平面), 建议 0.05-0.2
|
||||
float maxNormalAngleDeg; // 平面法向量与Z轴最大夹角 (度), 超过则直接丢弃; <=0 表示不过滤
|
||||
|
||||
float maxDistFromPlane; // 点到平面的最大允许距离;超出则从 pointIndices 中移除;<=0 表示不过滤
|
||||
|
||||
RansacPlaneSegmentationParams()
|
||||
: distanceThreshold(0.5f)
|
||||
, maxIterations(500)
|
||||
@ -24,6 +26,7 @@ struct RansacPlaneSegmentationParams {
|
||||
, growthZThreshold(1.0f)
|
||||
, minPlaneRatio(0.1f)
|
||||
, maxNormalAngleDeg(30.0f)
|
||||
, maxDistFromPlane(1.f)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
namespace {
|
||||
|
||||
const static char* g_algo_name = "DetectHole";
|
||||
const static char* g_algo_ver = "1.0.2";
|
||||
const static char* g_algo_ver = "1.0.3";
|
||||
|
||||
|
||||
void PrintHoleResult(const SHoleResult& hole, int index) {
|
||||
@ -196,6 +196,7 @@ int DetectMultipleHoles(
|
||||
|
||||
// ============ Step 2: 法向量过滤 ============
|
||||
NormalFilterParams normalParams;
|
||||
normalParams.maxDistFromPlane = ransacParams.maxDistFromPlane;
|
||||
FilterPlanesByNormal(planes, normalParams, points, totalPointCount);
|
||||
|
||||
// 如果没有找到有效平面,回退到处理整个点云
|
||||
|
||||
@ -298,7 +298,7 @@ struct NormalFilterParams {
|
||||
, refNx(0.0f)
|
||||
, refNy(0.0f)
|
||||
, refNz(1.0f)
|
||||
, maxDistFromPlane(2.0f)
|
||||
, maxDistFromPlane(0.0f)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user