Compare commits

...

10 Commits

Author SHA1 Message Date
7969a242ba 修改算法,获取了单根钢筋 2026-04-11 23:24:16 +08:00
1d649f9c01 增加了单行特征的检测函数 2026-04-10 00:18:05 +08:00
916f2c7662 删除无用代码 2026-04-09 23:43:28 +08:00
3aae9159ed 恢复到我自己的生长算法 2026-04-09 23:39:51 +08:00
9d304b19ac 修改了编译选项 2026-04-09 22:52:30 +08:00
937e9c0d8a 增加注释 2026-04-09 00:22:23 +08:00
MaJunwei
976f87b6ba 增加了过滤 2026-04-08 19:45:15 +08:00
2e92ddfab0 修改了生长规则 2026-04-08 00:19:01 +08:00
0d88858738 1.0.3增加了点到平面的参数调整 2026-04-07 22:56:18 +08:00
MaJunwei
cced2a9646 改为欧式距离 2026-04-07 19:34:48 +08:00
14 changed files with 1182 additions and 546 deletions

5
.gitignore vendored
View File

@ -1,4 +1,7 @@
.claude .claude
nul nul
build build
Algo/DetectHole/Export/ Algo/DetectHole/Export
Algo/DetectBarIntersection/build
Algo/DetectBarIntersection/data
Algo/DetectBarIntersection/Export

View File

@ -1,23 +1,32 @@
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.10)
project(DetectBarIntersection VERSION 1.0.0 LANGUAGES CXX) project(DetectBarIntersection VERSION 1.0.0 LANGUAGES CXX)
# Set C++ standard # Set C++ standard
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(WIN32) if(CMAKE_CONFIGURATION_TYPES)
if(MSVC) string(REPLACE ";" ", " DETECTBARINTERSECTION_CONFIGURATION_LIST "${CMAKE_CONFIGURATION_TYPES}")
add_compile_options( set(DETECTBARINTERSECTION_BUILD_DESCRIPTION "Multi-config (${DETECTBARINTERSECTION_CONFIGURATION_LIST})")
/wd4267 else()
/wd4996 set(DETECTBARINTERSECTION_BUILD_DESCRIPTION "${CMAKE_BUILD_TYPE}")
) endif()
if(CMAKE_BUILD_TYPE STREQUAL "Release")
add_compile_options(/O2) if(NOT DETECTBARINTERSECTION_BUILD_DESCRIPTION)
endif() set(DETECTBARINTERSECTION_BUILD_DESCRIPTION "Not specified")
endif() endif()
else()
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(WIN32)
message(STATUS "Debug mode: Adding debug flags") 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") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0 -Wall -Wextra")
add_definitions(-DDEBUG) add_definitions(-DDEBUG)
elseif(CMAKE_BUILD_TYPE STREQUAL "Release") elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
@ -232,11 +241,11 @@ if(BUILD_EXAMPLES)
endif() endif()
# Print configuration summary # Print configuration summary
message(STATUS "") message(STATUS "")
message(STATUS "DetectBarIntersection Configuration Summary:") message(STATUS "DetectBarIntersection Configuration Summary:")
message(STATUS " C++ Standard: ${CMAKE_CXX_STANDARD}") message(STATUS " C++ Standard: ${CMAKE_CXX_STANDARD}")
message(STATUS " Build Type: ${CMAKE_BUILD_TYPE}") message(STATUS " Build Type: ${DETECTBARINTERSECTION_BUILD_DESCRIPTION}")
message(STATUS " Eigen3 Include: ${EIGEN3_INCLUDE_DIR}") message(STATUS " Eigen3 Include: ${EIGEN3_INCLUDE_DIR}")
message(STATUS " OpenMP Enabled: ${ENABLE_OPENMP}") message(STATUS " OpenMP Enabled: ${ENABLE_OPENMP}")
message(STATUS " Build Examples: ${BUILD_EXAMPLES}") message(STATUS " Build Examples: ${BUILD_EXAMPLES}")
message(STATUS "") message(STATUS "")

View File

@ -1,26 +1,33 @@
@echo off @echo off
setlocal setlocal EnableExtensions
echo === Building DetectBarIntersection === set "BUILD_CONFIG=Debug"
if not exist build ( if not "%~1"=="" (
mkdir build if /I "%~1"=="Debug" (
) set "BUILD_CONFIG=Debug"
) else if /I "%~1"=="Release" (
cd build set "BUILD_CONFIG=Release"
) else (
cmake .. -G "Visual Studio 17 2022" -A x64 echo Usage: %~nx0 [Debug^|Release]
exit /b 1
if %ERRORLEVEL% NEQ 0 ( )
echo CMake configuration failed! )
exit /b %ERRORLEVEL%
) echo === Building DetectBarIntersection [%BUILD_CONFIG%] ===
cmake --build . --config Debug cmake -S . -B build -G "Visual Studio 17 2022" -A x64
if %ERRORLEVEL% NEQ 0 ( if errorlevel 1 (
echo Build failed! echo CMake configuration failed!
exit /b %ERRORLEVEL% exit /b %ERRORLEVEL%
) )
echo === Build completed successfully === cmake --build build --config %BUILD_CONFIG%
if errorlevel 1 (
echo Build failed!
exit /b %ERRORLEVEL%
)
echo === Build completed successfully [%BUILD_CONFIG%] ===

View File

@ -8,8 +8,8 @@ if(WIN32)
add_subdirectory(visualization_demo) add_subdirectory(visualization_demo)
endif() endif()
message(STATUS "") message(STATUS "")
message(STATUS "Examples Configuration:") message(STATUS "Examples Configuration:")
message(STATUS " Build Type: ${CMAKE_BUILD_TYPE}") message(STATUS " Build Type: ${DETECTBARINTERSECTION_BUILD_DESCRIPTION}")
message(STATUS " DetectBarIntersection Root: ${DETECTBARINTERSECTION_ROOT}") message(STATUS " DetectBarIntersection Root: ${DETECTBARINTERSECTION_ROOT}")
message(STATUS "") message(STATUS "")

View File

@ -54,11 +54,11 @@ public:
const std::string& title = "Detection Result" const std::string& title = "Detection Result"
); );
/** @brief Visualize best cluster highlighted (filtered aligned points) */ /** @brief Visualize best cluster highlighted (filtered aligned points) */
void VisualizeBestCluster( void VisualizeBestCluster(
const SBarIntersectionResult& result, const SBarIntersectionResult& result,
const std::string& title = "Best Cluster" const std::string& title = "Best Cluster"
); );
void SetInteractive(bool interactive); void SetInteractive(bool interactive);
void SetOutputDirectory(const std::string& dir); void SetOutputDirectory(const std::string& dir);

View File

@ -48,27 +48,38 @@ if(VTK_FOUND)
${VTK_LIBRARIES} ${VTK_LIBRARIES}
) )
if(WIN32) if(WIN32)
add_custom_command(TARGET visualization_demo POST_BUILD add_custom_command(TARGET visualization_demo POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<TARGET_FILE:BarIntersectionLib>" "$<TARGET_FILE:BarIntersectionLib>"
"$<TARGET_FILE_DIR:visualization_demo>" "$<TARGET_FILE_DIR:visualization_demo>"
COMMENT "Copying BarIntersectionLib DLL to visualization_demo output directory" COMMENT "Copying BarIntersectionLib DLL to visualization_demo output directory"
) )
set(VTK_BIN_DIR "${DETECTBARINTERSECTION_ROOT}/../../3rdparty/VTK-8.2.0/bin") set(VTK_BIN_DIR "${DETECTBARINTERSECTION_ROOT}/../../3rdparty/VTK-8.2.0/bin")
# Copy VTK DLLs # Copy VTK DLLs
file(GLOB VTK_DLLS "${VTK_BIN_DIR}/*.dll") file(GLOB VTK_DLLS "${VTK_BIN_DIR}/*.dll")
foreach(vtk_dll ${VTK_DLLS}) set(VTK_DEBUG_DLLS)
add_custom_command(TARGET visualization_demo POST_BUILD set(VTK_RELEASE_DLLS)
COMMAND ${CMAKE_COMMAND} -E copy_if_different foreach(vtk_dll ${VTK_DLLS})
"${vtk_dll}" get_filename_component(vtk_dll_name "${vtk_dll}" NAME)
"$<TARGET_FILE_DIR:visualization_demo>" if(vtk_dll_name MATCHES "d\\.dll$")
COMMENT "Copying VTK DLL: ${vtk_dll}" list(APPEND VTK_DEBUG_DLLS "${vtk_dll}")
) else()
endforeach() list(APPEND VTK_RELEASE_DLLS "${vtk_dll}")
endif() endif()
else() endforeach()
message(WARNING "VTK not found. visualization_demo will not be built.")
endif() 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()

View File

@ -224,7 +224,7 @@ int ProcessSingleFile(
debugCallbacks.onPlaneSegmented = nullptr;// OnPlaneSegmented; debugCallbacks.onPlaneSegmented = nullptr;// OnPlaneSegmented;
debugCallbacks.onPointsAligned = nullptr;// OnPointsAligned; debugCallbacks.onPointsAligned = nullptr;// OnPointsAligned;
debugCallbacks.onPlaneFiltered = nullptr;// OnPlaneFiltered; debugCallbacks.onPlaneFiltered = nullptr;// OnPlaneFiltered;
debugCallbacks.onClustersDetected = OnClustersDetected; debugCallbacks.onClustersDetected = nullptr;// OnClustersDetected;
debugCallbacks.userData = &callbackData; debugCallbacks.userData = &callbackData;
// Set parameters // Set parameters

View File

@ -1,93 +1,109 @@
#ifndef BAR_INTERSECTION_PARAMS_H #ifndef BAR_INTERSECTION_PARAMS_H
#define BAR_INTERSECTION_PARAMS_H #define BAR_INTERSECTION_PARAMS_H
#include "VZNL_Types.h" #include "VZNL_Types.h"
#include <vector> #include <vector>
/** /**
* @brief RANSAC * @brief RANSAC
*/ */
struct SPlaneSegmentationParams { struct SPlaneSegmentationParams {
float distanceThreshold; // 点到平面距离阈值 (mm) float distanceThreshold; // 点到平面距离阈值 (mm)
int maxIterations; // RANSAC 最大迭代次数 int maxIterations; // RANSAC 最大迭代次数
int minPlanePoints; // 最小平面点数 int minPlanePoints; // 最小平面点数
float minPlaneRatio; // 平面最小点数占比 float minPlaneRatio; // 平面最小点数占比
float heightThreshold; // 高于平面的最小高度,用于过滤平面点 (mm) float heightThreshold; // 高于平面的最小高度,用于过滤平面点 (mm)
SPlaneSegmentationParams() SPlaneSegmentationParams()
: distanceThreshold(1.0f) : distanceThreshold(1.0f)
, maxIterations(500) , maxIterations(500)
, minPlanePoints(1000) , minPlanePoints(1000)
, minPlaneRatio(0.05f) , minPlaneRatio(0.05f)
, heightThreshold(10.0f) , heightThreshold(10.0f)
{} {}
}; };
/** /**
* @brief * @brief
*/ */
struct SGrowthParams { struct SGrowthParams {
float thresholdX; // 跨行合并阈值:相邻行 segment 质心 x 的最大允许差 (mm) float thresholdX; // 跨行合并阈值:相邻行 segment 质心 x 的最大允许差 (mm)
float thresholdY; // 行内分段阈值:同行相邻点 y 的最大允许差 (mm) float thresholdY; // 行内分段阈值:同行相邻点 y 的最大允许差 (mm)
float thresholdZ; // 行内分段阈值:同行相邻点 z 的最大允许差 (mm) float thresholdZ; // 行内分段阈值:同行相邻点 z 的最大允许差 (mm)
int minClusterSize; // 最小簇点数 int minClusterSize; // 最小簇点数
float angleSearchDistance;
SGrowthParams() int residualSmoothWindow;
: thresholdX(5.0f) float maxAxisDeviationFromXYDeg; // Max allowed axis deviation from the XY plane (deg)
, thresholdY(5.0f) float maxPerpendicularDeviationDeg; // Max deviation from 90 deg for centroid-connection test
, thresholdZ(5.0f) int minContinuousValidPointCount; // Min consecutive valid points kept on each laser line after plane filtering; <=1 disables
, minClusterSize(20) float maxContinuousPointZTolerance; // Max z difference between adjacent points inside one valid run (mm)
{} float minBarDiameter;
}; float maxBarDiameter;
/** SGrowthParams()
* @brief : thresholdX(5.0f)
*/ , thresholdY(5.0f)
struct SGrowthCluster { , thresholdZ(5.0f)
std::vector<int> pointIndices; // 簇内点在原始 rows*cols 网格中的线性索引 , minClusterSize(20)
SVzNL3DPointF centroid; // 簇质心 , angleSearchDistance(2.f)
SVzNL3DPointF minBound; // 包围盒最小角 , residualSmoothWindow(5)
SVzNL3DPointF maxBound; // 包围盒最大角 , maxAxisDeviationFromXYDeg(50.0f)
int pointCount; , maxPerpendicularDeviationDeg(50.0f)
, minContinuousValidPointCount(0)
SGrowthCluster() , maxContinuousPointZTolerance(5.0f)
: centroid(), minBound(), maxBound(), pointCount(0) , minBarDiameter(10.0f)
{} , maxBarDiameter(30.0f)
}; {}
};
/**
* @brief /**
*/ * @brief
struct SBarIntersectionResult { */
// 平面信息 struct SGrowthCluster {
SVzNL3DPointF planeNormal; // 平面法向量 std::vector<int> pointIndices; // 簇内点在原始 rows*cols 网格中的线性索引
float planeD; // 平面方程 ax+by+cz+d=0 中的 d SVzNL3DPointF centroid; // 簇质心
SVzNL3DPointF minBound; // 包围盒最小角
// 簇(原始坐标系) SVzNL3DPointF maxBound; // 包围盒最大角
int clusterCount; int pointCount;
SGrowthCluster* clusters;
SGrowthCluster()
// 最优簇索引(-1表示无有效簇 : centroid(), minBound(), maxBound(), pointCount(0)
int bestClusterIndex; {}
};
// 最优簇的过滤后点云(对齐坐标系,用于可视化)
std::vector<SVzNLPointXYZ> bestClusterPoints; /**
* @brief
SBarIntersectionResult() */
: planeNormal(), planeD(0.0f) struct SBarIntersectionResult {
, clusterCount(0), clusters(nullptr) // 平面信息
, bestClusterIndex(-1) SVzNL3DPointF planeNormal; // 平面法向量
{} float planeD; // 平面方程 ax+by+cz+d=0 中的 d
};
// 簇(原始坐标系)
/** int clusterCount;
* @brief SGrowthCluster* clusters;
*/
inline void FreeBarIntersectionResult(SBarIntersectionResult* result) { // 最优簇索引(-1表示无有效簇
if (result) { int bestClusterIndex;
if (result->clusters) { delete[] result->clusters; result->clusters = nullptr; }
result->clusterCount = 0; // 最优簇的过滤后点云(对齐坐标系,用于可视化)
} std::vector<SVzNLPointXYZ> bestClusterPoints;
}
SBarIntersectionResult()
#endif // BAR_INTERSECTION_PARAMS_H : 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

View File

@ -1,6 +1,7 @@
#include "BarIntersection.h" #include "BarIntersection.h"
#include "PlaneAlignment.h" #include "PlaneAlignment.h"
#include "RegionGrowing.h" #include "RegionGrowing.h"
#include <Eigen/Dense>
#include <vector> #include <vector>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
@ -9,7 +10,7 @@
#include <numeric> #include <numeric>
#include <limits> #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 const char* s_algorithmName = "BarIntersectionDetection";
static bool IsValidPoint(const SVzNLPointXYZ& pt) { 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); 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, const SVzNLPointXYZ* points,
int rows, int rows,
int cols, int cols,
@ -107,6 +208,17 @@ BAR_INTERSECTION_API int DetectBarIntersections(
alignedPoints, totalPoints, planeZ, planeParams.heightThreshold alignedPoints, totalPoints, planeZ, planeParams.heightThreshold
); );
// ============================================
// Step 2b: 按激光线过滤短连续段噪点
// ============================================
FilterLaserLineNoiseInPlace(
alignedPoints,
rows,
cols,
growthParams.minContinuousValidPointCount,
growthParams.maxContinuousPointZTolerance
);
// Debug callback: plane filtered // Debug callback: plane filtered
if (debugCallbacks && debugCallbacks->onPlaneFiltered) { if (debugCallbacks && debugCallbacks->onPlaneFiltered) {
// 收集非零点用于回调显示 // 收集非零点用于回调显示
@ -137,7 +249,10 @@ BAR_INTERSECTION_API int DetectBarIntersections(
// ============================================ // ============================================
std::vector<SGrowthCluster> clusters; std::vector<SGrowthCluster> clusters;
bar_intersection::RegionGrowClusters( 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

View File

@ -1,4 +1,4 @@
#ifndef REGION_GROWING_H #ifndef REGION_GROWING_H
#define REGION_GROWING_H #define REGION_GROWING_H
#include "VZNL_Types.h" #include "VZNL_Types.h"
@ -28,6 +28,7 @@ int RegionGrowClusters(
const SVzNLPointXYZ* points, const SVzNLPointXYZ* points,
int rows, int rows,
int cols, int cols,
bool bHorizontalScan,
const SGrowthParams& params, const SGrowthParams& params,
std::vector<SGrowthCluster>& outClusters std::vector<SGrowthCluster>& outClusters
); );

View File

@ -16,6 +16,8 @@ struct RansacPlaneSegmentationParams {
float minPlaneRatio; // 平面最小点数占比 (相对最大平面), 建议 0.05-0.2 float minPlaneRatio; // 平面最小点数占比 (相对最大平面), 建议 0.05-0.2
float maxNormalAngleDeg; // 平面法向量与Z轴最大夹角 (度), 超过则直接丢弃; <=0 表示不过滤 float maxNormalAngleDeg; // 平面法向量与Z轴最大夹角 (度), 超过则直接丢弃; <=0 表示不过滤
float maxDistFromPlane; // 点到平面的最大允许距离;超出则从 pointIndices 中移除;<=0 表示不过滤
RansacPlaneSegmentationParams() RansacPlaneSegmentationParams()
: distanceThreshold(0.5f) : distanceThreshold(0.5f)
, maxIterations(500) , maxIterations(500)
@ -24,6 +26,7 @@ struct RansacPlaneSegmentationParams {
, growthZThreshold(1.0f) , growthZThreshold(1.0f)
, minPlaneRatio(0.1f) , minPlaneRatio(0.1f)
, maxNormalAngleDeg(30.0f) , maxNormalAngleDeg(30.0f)
, maxDistFromPlane(1.f)
{ {
} }
}; };

View File

@ -12,7 +12,7 @@
namespace { namespace {
const static char* g_algo_name = "DetectHole"; 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) { void PrintHoleResult(const SHoleResult& hole, int index) {
@ -196,6 +196,7 @@ int DetectMultipleHoles(
// ============ Step 2: 法向量过滤 ============ // ============ Step 2: 法向量过滤 ============
NormalFilterParams normalParams; NormalFilterParams normalParams;
normalParams.maxDistFromPlane = ransacParams.maxDistFromPlane;
FilterPlanesByNormal(planes, normalParams, points, totalPointCount); FilterPlanesByNormal(planes, normalParams, points, totalPointCount);
// 如果没有找到有效平面,回退到处理整个点云 // 如果没有找到有效平面,回退到处理整个点云

View File

@ -298,7 +298,7 @@ struct NormalFilterParams {
, refNx(0.0f) , refNx(0.0f)
, refNy(0.0f) , refNy(0.0f)
, refNz(1.0f) , refNz(1.0f)
, maxDistFromPlane(2.0f) , maxDistFromPlane(0.0f)
{} {}
}; };