266 lines
8.8 KiB
C
266 lines
8.8 KiB
C
#ifndef HOLE_DETECTION_H
|
|
#define HOLE_DETECTION_H
|
|
|
|
#include "HoleDetectionParams.h"
|
|
#include "ErrorCodes.h"
|
|
#include "VZNL_Types.h"
|
|
|
|
// Export macro for shared library
|
|
#ifdef _WIN32
|
|
#ifdef HOLE_DETECTION_EXPORTS
|
|
#define HOLE_DETECTION_API __declspec(dllexport)
|
|
#else
|
|
#define HOLE_DETECTION_API __declspec(dllimport)
|
|
#endif
|
|
#else
|
|
#ifdef HOLE_DETECTION_EXPORTS
|
|
#define HOLE_DETECTION_API __attribute__((visibility("default")))
|
|
#else
|
|
#define HOLE_DETECTION_API
|
|
#endif
|
|
#endif
|
|
|
|
/**
|
|
* @brief Boundary point with grid location (for debug callbacks)
|
|
*/
|
|
struct SHoleBoundaryPoint {
|
|
SVzNLPointXYZ point; // 点坐标
|
|
int row; // 行号
|
|
int col; // 列号
|
|
|
|
SHoleBoundaryPoint()
|
|
: point(), row(-1), col(-1) {}
|
|
|
|
SHoleBoundaryPoint(const SVzNLPointXYZ& p, int r, int c)
|
|
: 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
|
|
*/
|
|
struct SClusterInfo {
|
|
const SHoleBoundaryPoint* points; // Points in this cluster
|
|
int count; // Number of points in this cluster
|
|
};
|
|
|
|
/**
|
|
* @brief Plane segmentation information for debug callbacks
|
|
*/
|
|
struct SPlaneSegmentInfo {
|
|
float normalX, normalY, normalZ; // 平面法向量 (归一化)
|
|
int pointCount; // 该平面的点数
|
|
const int* pointIndices; // 点索引数组 (在原始grid中的索引)
|
|
float normalAngleDeg; // 法向量与参考方向的夹角 (度)
|
|
};
|
|
|
|
/**
|
|
* @brief Debug callbacks for visualization and debugging
|
|
*
|
|
* All callbacks are optional (can be nullptr).
|
|
* userData is passed to all callbacks for user context.
|
|
*/
|
|
struct SHoleDetectionDebugCallbacks {
|
|
/**
|
|
* @brief Called after boundary points are detected
|
|
* @param points Array of boundary points
|
|
* @param count Number of boundary points
|
|
* @param userData User-provided context pointer
|
|
*/
|
|
void (*onBoundaryDetected)(const SHoleBoundaryPoint* points, int count, void* userData);
|
|
|
|
/**
|
|
* @brief Called after clustering is complete
|
|
* @param clusters Array of cluster information
|
|
* @param clusterCount Number of clusters found
|
|
* @param userData User-provided context pointer
|
|
*/
|
|
void (*onClustersFound)(const SClusterInfo* clusters, int clusterCount, void* userData);
|
|
|
|
/**
|
|
* @brief Called when expanded region points are collected for plane fitting
|
|
* @param clusterPoints Array of cluster boundary points
|
|
* @param clusterCount Number of cluster points
|
|
* @param expandedPoints Array of expanded region points (surrounding flat surface)
|
|
* @param expandedCount Number of expanded region points
|
|
* @param userData User-provided context pointer
|
|
*/
|
|
void (*onExpandedRegion)(const SHoleBoundaryPoint* clusterPoints, int clusterCount,
|
|
const SVzNLPointXYZ* expandedPoints, int expandedCount,
|
|
void* userData);
|
|
|
|
/**
|
|
* @brief Called after each hole is fitted
|
|
* @param hole The fitted hole result
|
|
* @param holeIndex Index of this hole (0-based)
|
|
* @param userData User-provided context pointer
|
|
*/
|
|
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 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 Called after RANSAC plane segmentation and normal filtering
|
|
* @param planes Array of plane segment information
|
|
* @param planeCount Number of planes
|
|
* @param totalPointCount Total number of points in the grid (rows * cols)
|
|
* @param userData User-provided context pointer
|
|
*/
|
|
void (*onPlanesSegmented)(
|
|
const SPlaneSegmentInfo* planes,
|
|
int planeCount,
|
|
int totalPointCount,
|
|
void* userData
|
|
);
|
|
|
|
/**
|
|
* @brief Called after masked points grid is built for a plane
|
|
* @param points Masked point array (grid format, rows * cols)
|
|
* @param rows Row count
|
|
* @param cols Column count
|
|
* @param planeIndex Index of the current plane (0-based)
|
|
* @param userData User-provided context pointer
|
|
*/
|
|
void (*onMaskedPointsReady)(
|
|
const SVzNLPointXYZ* points,
|
|
int rows,
|
|
int cols,
|
|
int planeIndex,
|
|
void* userData
|
|
);
|
|
|
|
/**
|
|
* @brief User-provided context pointer, passed to all callbacks
|
|
*/
|
|
void* userData;
|
|
|
|
/**
|
|
* @brief If non-null, each cluster's boundary points are saved as a CSV file
|
|
* in this directory before fitting. Files are named cluster_0.csv, cluster_1.csv, ...
|
|
* Fields: row,col,x,y,z
|
|
*/
|
|
const char* clusterOutputDir;
|
|
};
|
|
|
|
/**
|
|
* @brief Detect multiple holes in point cloud
|
|
*
|
|
* This is the main entry point for hole detection. It performs the following steps:
|
|
* 1. Validate grid format
|
|
* 2. Detect pit boundaries
|
|
* 3. Cluster boundary points
|
|
* 4. Fit ellipse and plane for each cluster
|
|
* 5. Filter and sort results
|
|
*
|
|
* @param [in] points Input point cloud (grid format)
|
|
* @param [in] rows Number of rows
|
|
* @param [in] cols Number of columns
|
|
* @param [in] detectionParams Detection parameters
|
|
* @param [in] filterParams Filter parameters
|
|
* @param [out] result Output result structure
|
|
* @param [in] debugCallbacks Optional debug callbacks for visualization (can be nullptr)
|
|
* @return 0 on success, non-zero on error
|
|
*
|
|
* @pre points != nullptr
|
|
* @pre rows > 0
|
|
* @pre cols > 0
|
|
* @pre result != nullptr
|
|
*
|
|
* @post If return value is 0, result contains detected holes
|
|
* @post Caller must free result->holes using delete[]
|
|
*/
|
|
HOLE_DETECTION_API int DetectMultipleHoles(
|
|
const SVzNLPointXYZ* points,
|
|
int rows,
|
|
int cols,
|
|
const RansacPlaneSegmentationParams& ransacParams,
|
|
const SHoleDetectionParams& detectionParams,
|
|
const SHoleFilterParams& filterParams,
|
|
SMultiHoleResult* result,
|
|
const SHoleDetectionDebugCallbacks* debugCallbacks = nullptr
|
|
);
|
|
|
|
/**
|
|
* @brief Get algorithm name and version information
|
|
*
|
|
* Returned pointers refer to internal static strings and must not be freed
|
|
* or modified by the caller. Either output parameter can be nullptr.
|
|
*
|
|
* @param [out] algorithmName Output algorithm name string
|
|
* @param [out] algorithmVersion Output algorithm version string
|
|
*/
|
|
HOLE_DETECTION_API const char* GetAlgorithmVersion();
|
|
HOLE_DETECTION_API const char* GetAlgorithmName();
|
|
|
|
/**
|
|
* @brief Print detection results to console in a formatted way
|
|
*
|
|
* @param [in] result Detection result structure
|
|
* @param [in] verbose If true, print detailed information for each hole
|
|
*/
|
|
HOLE_DETECTION_API void PrintDetectionResults(const SMultiHoleResult& result, bool verbose = true);
|
|
|
|
#endif // HOLE_DETECTION_H
|