Skip to content

Commit 0f3009d

Browse files
CAP: segmentation function well implemented and documented
1 parent 970e13d commit 0f3009d

File tree

4 files changed

+104
-39
lines changed

4 files changed

+104
-39
lines changed

src/diffCheck/segmentation/DFSegmentation.cc

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ namespace diffCheck::segmentation
1010
geometry::DFPointCloud &pointCloud,
1111
float voxelSize,
1212
float normalThresholdDegree,
13-
int minClusterSize)
13+
int minClusterSize,
14+
bool useKnnNeighborhood,
15+
int radiusNeighborhoodSize,
16+
int knnNeighborhoodSize)
1417
{
1518
std::vector<std::shared_ptr<geometry::DFPointCloud>> segments;
1619
cilantro::PointCloud3f cilantroPointCloud;
@@ -20,41 +23,78 @@ namespace diffCheck::segmentation
2023
{
2124
cilantroPointCloud.points.conservativeResize(3, cilantroPointCloud.points.cols() + 1);
2225
cilantroPointCloud.points.rightCols(1) = pointCloud.Points[i].cast<float>();
23-
cilantroPointCloud.normals.conservativeResize(3, cilantroPointCloud.normals.cols() + 1);
24-
cilantroPointCloud.normals.rightCols(1) = pointCloud.Normals[i].cast<float>();
25-
2626
}
2727

28-
// Compute normals
29-
// cilantroPointCloud.estimateNormals(radiusNormal);
28+
// segment the point cloud using knn or radius neighborhood
29+
if (useKnnNeighborhood)
30+
{
31+
cilantro::KNNNeighborhoodSpecification<int> neighborhood(knnNeighborhoodSize);
3032

31-
// Neighborhood definition
32-
cilantro::RadiusNeighborhoodSpecification<float> neighborhood(voxelSize * 2);
33+
// conpute the normals and downsample
34+
cilantroPointCloud.estimateNormals(neighborhood, false);
35+
cilantroPointCloud.gridDownsample(voxelSize);
3336

34-
// Similarity evaluator
35-
cilantro::NormalsProximityEvaluator<float, 3> similarityEvaluator(cilantroPointCloud.normals, normalThresholdDegree*M_PI/180.0f);
36-
37+
// Similarity evaluator
38+
cilantro::NormalsProximityEvaluator<float, 3> similarityEvaluator(
39+
cilantroPointCloud.normals,
40+
normalThresholdDegree*M_PI/180.0f);
3741

38-
// Segment the point cloud
39-
cilantro::ConnectedComponentExtraction3f<> segmenter(cilantroPointCloud.points);
40-
segmenter.segment(neighborhood, similarityEvaluator, minClusterSize);
41-
auto clusterToPointMap = segmenter.getClusterToPointIndicesMap();
42-
int nSegments = segmenter.getNumberOfClusters();
42+
// Segment the point cloud
43+
cilantro::ConnectedComponentExtraction3f<> segmenter(cilantroPointCloud.points);
44+
segmenter.segment(neighborhood, similarityEvaluator, minClusterSize);
45+
auto clusterToPointMap = segmenter.getClusterToPointIndicesMap();
46+
int nSegments = segmenter.getNumberOfClusters();
4347

44-
// Get the segments
45-
std::cout<<"Number of segments: "<<nSegments<<std::endl;
46-
for (int indice = 0; indice<nSegments; indice++)
48+
// Get the segments
49+
for (int indice = 0; indice<nSegments; indice++)
50+
{
51+
std::shared_ptr<geometry::DFPointCloud> segment = std::make_shared<geometry::DFPointCloud>();
52+
for (auto pointIndice : clusterToPointMap[indice])
53+
{
54+
Eigen::Vector3d point = cilantroPointCloud.points.col(pointIndice).cast<double>();
55+
Eigen::Vector3d normal = cilantroPointCloud.normals.col(pointIndice).cast<double>();
56+
segment->Points.push_back(point);
57+
segment->Normals.push_back(normal);
58+
}
59+
segments.push_back(segment);
60+
}
61+
}
62+
else
4763
{
48-
std::shared_ptr<geometry::DFPointCloud> segment = std::make_shared<geometry::DFPointCloud>();
49-
for (auto pointIndice : clusterToPointMap[indice])
64+
cilantro::RadiusNeighborhoodSpecification<float> neighborhood(radiusNeighborhoodSize);
65+
66+
// conpute the normals and downsample
67+
cilantroPointCloud.estimateNormals(neighborhood, false);
68+
cilantroPointCloud.gridDownsample(voxelSize);
69+
70+
// Similarity evaluator
71+
cilantro::NormalsProximityEvaluator<float, 3> similarityEvaluator(
72+
cilantroPointCloud.normals,
73+
normalThresholdDegree*M_PI/180.0f);
74+
75+
// Segment the point cloud
76+
cilantro::ConnectedComponentExtraction3f<> segmenter(cilantroPointCloud.points);
77+
segmenter.segment(neighborhood, similarityEvaluator, minClusterSize);
78+
79+
auto clusterToPointMap = segmenter.getClusterToPointIndicesMap();
80+
int nSegments = segmenter.getNumberOfClusters();
81+
82+
// Get the segments
83+
for (int indice = 0; indice<nSegments; indice++)
5084
{
51-
std::cout<<"Point indice: "<<pointIndice<<std::endl;
52-
Eigen::Vector3d point = cilantroPointCloud.points.col(pointIndice).cast<double>();
53-
segment->Points.push_back(point);
85+
std::shared_ptr<geometry::DFPointCloud> segment = std::make_shared<geometry::DFPointCloud>();
86+
for (auto pointIndice : clusterToPointMap[indice])
87+
{
88+
Eigen::Vector3d point = cilantroPointCloud.points.col(pointIndice).cast<double>();
89+
Eigen::Vector3d normal = cilantroPointCloud.normals.col(pointIndice).cast<double>();
90+
segment->Points.push_back(point);
91+
segment->Normals.push_back(normal);
92+
}
93+
segments.push_back(segment);
5494
}
55-
segments.push_back(segment);
5695
}
96+
5797

5898
return segments;
5999
}
60-
}
100+
} // namespace diffCheck::segmentation

src/diffCheck/segmentation/DFSegmentation.hh

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,23 @@ namespace diffCheck::segmentation
66
class DFSegmentation
77
{
88
public:
9-
/** @brief Segment the point cloud into planes
10-
* Using Cilantro's ConnectedComponentExtraction3f method
9+
/** @brief Downsamples and segments the point cloud using Cilantro's ConnectedComponentExtraction3f method
1110
* @param pointCloud the point cloud to segment
12-
* @param voxelSize the voxel size for the search in the point cloud
13-
* @param normalThresholdDegree the normal threshold in degrees do differentiate segments
14-
* @param minClusterSize the minimum cluster size to consider a segment
11+
* @param voxelSize the voxel size for the downsampling of the point cloud. The point cloud is downsampled after the normal calculation. A lower number will result in a denser point cloud
12+
* @param normalThresholdDegree the normal threshold in degrees do differentiate segments. The higher the number, the more tolerent the segmentation will be to normal differences
13+
* @param minClusterSize the minimum cluster size to consider a segment. A lower number will discard smaller segments
14+
* @param useKnnNeighborhood if true, the neighborhood search will be done using the knnNeighborhoodSize, otherwise it will be done using radiusNeighborhoodSize
15+
* @param knnNeighborhoodSize the k nearest neighbors size for the "neighborhood search". This is used when useKnnNeighborhood is true. a higher number will result in smoother segmentation, but at the cost of computation time
16+
* @param radiusNeighborhoodSize the radius of the neighborhood size for the "radius search". This is used when useKnnNeighborhood is false. A higher number will result in smoother segmentation, but at the cost of computation time.
1517
* @return std::vector<geometry::DFPointCloud> the segmented point clouds
1618
*/
1719
static std::vector<std::shared_ptr<geometry::DFPointCloud>> SegmentationPointCloud(
1820
geometry::DFPointCloud &pointCloud,
1921
float voxelSize = 0.2,
2022
float normalThresholdDegree = 20,
21-
int minClusterSize = 10);
23+
int minClusterSize = 10,
24+
bool useKnnNeighborhood = true,
25+
int radiusNeighborhoodSize = 10,
26+
int knnNeighborhoodSize = 10);
2227
};
2328
} // namespace diffCheck::segmentation

src/diffCheckApp.cc

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,32 @@
77
int main()
88
{
99
std::shared_ptr<diffCheck::geometry::DFPointCloud> pcdSrc = std::make_shared<diffCheck::geometry::DFPointCloud>();
10-
11-
std::string pathPcdSrc = R"(C:\Users\andre\Downloads\04_pt.ply)";
10+
std::shared_ptr<diffCheck::geometry::DFMesh> meshSrc = std::make_shared<diffCheck::geometry::DFMesh>();
11+
std::vector<std::shared_ptr<diffCheck::geometry::DFPointCloud>> segments;
12+
std::string pathMeshSrc = R"(C:\Users\localuser\Downloads\02_mesh.ply)";
13+
std::string pathPcdSrc = R"(C:\Users\localuser\Downloads\02_points_with_errors_1e6_pts.ply)";
1214

1315
pcdSrc->LoadFromPLY(pathPcdSrc);
16+
meshSrc->LoadFromPLY(pathMeshSrc);
17+
18+
segments = diffCheck::segmentation::DFSegmentation::SegmentationPointCloud(*pcdSrc, 0.01, 1, 30, true, 50, 30);
19+
std::cout << "number of segments:" << segments.size()<< std::endl;
1420

15-
pcdSrc->DownsampleBySize(100);
21+
diffCheck::visualizer::Visualizer vis;
22+
vis.AddMesh(meshSrc);
23+
for (auto segment : segments)
24+
{
25+
// colorize the segments with random colors
26+
double r = static_cast<double>(rand()) / RAND_MAX;
27+
double g = static_cast<double>(rand()) / RAND_MAX;
28+
double b = static_cast<double>(rand()) / RAND_MAX;
29+
for (int i = 0; i < segment->Points.size(); i++)
30+
{
31+
segment->Colors.push_back(Eigen::Vector3d(r, g, b));
32+
}
33+
vis.AddPointCloud(segment);
1634

17-
std::shared_ptr<diffCheck::visualizer::Visualizer> vis = std::make_shared<diffCheck::visualizer::Visualizer>();
18-
vis->AddPointCloud(pcdSrc);
19-
vis->Run();
35+
}
36+
vis.Run();
2037
return 0;
2138
}

src/diffCheckBindings.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,5 +163,8 @@ PYBIND11_MODULE(diffcheck_bindings, m) {
163163
py::arg("point_cloud"),
164164
py::arg("voxel_size") = 1,
165165
py::arg("normal_threshold_degree") = 20,
166-
py::arg("min_cluster_size") = 10);
166+
py::arg("min_cluster_size") = 10,
167+
py::arg("use_knn_neighborhood") = false,
168+
py::arg("radius_neighborhood_size") = 10,
169+
py::arg("knn_neighborhood_size") = 10);
167170
}

0 commit comments

Comments
 (0)