Skip to content

Commit acc643c

Browse files
committed
TEMP: working on colored cluster + visualizer
1 parent 3940e23 commit acc643c

File tree

9 files changed

+215
-78
lines changed

9 files changed

+215
-78
lines changed

src/diffCheck.hh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include <open3d/Open3D.h>
44
#include <loguru.hpp>
55

6+
#include <cilantro/cilantro.hpp>
7+
68
// diffCheck includes
79
#include "diffCheck/log.hh"
810
const diffCheck::Log LOG = diffCheck::Log();

src/diffCheck/geometry/DFPointCloud.cc

Lines changed: 115 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ namespace diffCheck::geometry
88
{
99
void DFPointCloud::Cvt2DFPointCloud(const std::shared_ptr<open3d::geometry::PointCloud> &O3DPointCloud)
1010
{
11+
this->Points.clear();
12+
this->Colors.clear();
13+
this->Normals.clear();
14+
1115
if (O3DPointCloud->points_.size() != 0)
1216
for (auto &point : O3DPointCloud->points_)
1317
this->Points.push_back(point);
@@ -19,6 +23,44 @@ namespace diffCheck::geometry
1923
this->Normals.push_back(normal);
2024
}
2125

26+
void DFPointCloud::Cvt2DFPointCloud(const std::shared_ptr<cilantro::PointCloud3f> &cilantroPointCloud)
27+
{
28+
this->Points.clear();
29+
this->Colors.clear();
30+
this->Normals.clear();
31+
32+
auto ptt = cilantroPointCloud->points;
33+
int n_pt = (int)ptt.cols();
34+
auto col = cilantroPointCloud->colors;
35+
auto nor = cilantroPointCloud->normals;
36+
37+
if (n_pt == 0)
38+
throw std::invalid_argument("The point cloud is empty.");
39+
for (int i = 0; i < n_pt; i++)
40+
{
41+
Eigen::Vector3d pt_d = ptt.col(i).cast<double>();
42+
this->Points.push_back(pt_d);
43+
}
44+
45+
if (cilantroPointCloud->hasColors())
46+
{
47+
for (int i = 0; i < n_pt; i++)
48+
{
49+
Eigen::Vector3d cl_d = col.col(i).cast <double>();
50+
this->Colors.push_back(cl_d);
51+
}
52+
}
53+
54+
if (cilantroPointCloud->hasNormals())
55+
{
56+
for (int i = 0; i < n_pt; i++)
57+
{
58+
Eigen::Vector3d no_d = nor.col(i).cast <double>();
59+
this->Normals.push_back(no_d);
60+
}
61+
}
62+
}
63+
2264
std::shared_ptr<open3d::geometry::PointCloud> DFPointCloud::Cvt2O3DPointCloud()
2365
{
2466
std::shared_ptr<open3d::geometry::PointCloud> O3DPointCloud(new open3d::geometry::PointCloud());
@@ -34,6 +76,46 @@ namespace diffCheck::geometry
3476
return O3DPointCloud;
3577
}
3678

79+
std::shared_ptr<cilantro::PointCloud3f> DFPointCloud::Cvt2CilantroPointCloud()
80+
{
81+
std::shared_ptr<cilantro::PointCloud3f> cilantroPointCloud = std::make_shared<cilantro::PointCloud3f>();
82+
83+
cilantro::VectorSet3f points;
84+
for (auto& pt : this->Points)
85+
{
86+
Eigen::Vector3f pt_f = pt.cast <float>();
87+
points.conservativeResize(points.rows(), points.cols() + 1);
88+
points.col(points.cols() - 1) = pt_f;
89+
}
90+
cilantroPointCloud->points = points;
91+
92+
cilantro::VectorSet3f colors;
93+
if (this->HasColors())
94+
{
95+
for (auto& color : this->Colors)
96+
{
97+
Eigen::Vector3f color_f = color.cast <float>();
98+
colors.conservativeResize(colors.rows(), colors.cols() + 1);
99+
colors.col(colors.cols() - 1) = color_f;
100+
}
101+
}
102+
cilantroPointCloud->colors = colors;
103+
104+
cilantro::VectorSet3f normals;
105+
if (this->HasNormals())
106+
{
107+
for (auto& normal : this->Normals)
108+
{
109+
Eigen::Vector3f normal_f = normal.cast <float>();
110+
normals.conservativeResize(normals.rows(), normals.cols() + 1);
111+
normals.col(normals.cols() - 1) = normal_f;
112+
}
113+
}
114+
cilantroPointCloud->normals = normals;
115+
116+
return cilantroPointCloud;
117+
}
118+
37119
std::vector<double> DFPointCloud::ComputeP2PDistance(std::shared_ptr<geometry::DFPointCloud> target)
38120
{
39121
std::vector<double> errors;
@@ -57,34 +139,49 @@ namespace diffCheck::geometry
57139
}
58140

59141
void DFPointCloud::EstimateNormals(
142+
bool useCilantroEvaluator,
60143
std::optional<int> knn,
61144
std::optional<double> searchRadius
62145
)
63146
{
64-
auto O3DPointCloud = this->Cvt2O3DPointCloud();
65-
O3DPointCloud->EstimateNormals();
66-
67-
if (knn.value() != 30 && searchRadius.has_value() == false)
68-
{
69-
open3d::geometry::KDTreeSearchParamKNN knnSearchParam(knn.value());
70-
O3DPointCloud->EstimateNormals(knnSearchParam);
71-
DIFFCHECK_INFO(("Estimating normals with knn = " + std::to_string(knn.value())).c_str());
72-
}
73-
else if (searchRadius.has_value())
147+
if (!useCilantroEvaluator)
74148
{
75-
open3d::geometry::KDTreeSearchParamHybrid hybridSearchParam(searchRadius.value(), knn.value());
76-
O3DPointCloud->EstimateNormals(hybridSearchParam);
77-
DIFFCHECK_INFO(("Estimating normals with hybrid search radius = " + std::to_string(searchRadius.value()) + "and knn = " + std::to_string(knn.value())).c_str());
149+
auto O3DPointCloud = this->Cvt2O3DPointCloud();
150+
151+
if (knn.value() != 30 && searchRadius.has_value() == false)
152+
{
153+
open3d::geometry::KDTreeSearchParamKNN knnSearchParam(knn.value());
154+
O3DPointCloud->EstimateNormals(knnSearchParam);
155+
DIFFCHECK_INFO(("Estimating normals with knn = " + std::to_string(knn.value())).c_str());
156+
}
157+
else if (searchRadius.has_value())
158+
{
159+
open3d::geometry::KDTreeSearchParamHybrid hybridSearchParam(searchRadius.value(), knn.value());
160+
O3DPointCloud->EstimateNormals(hybridSearchParam);
161+
DIFFCHECK_INFO(("Estimating normals with hybrid search radius = " + std::to_string(searchRadius.value()) + "and knn = " + std::to_string(knn.value())).c_str());
162+
}
163+
else
164+
{
165+
O3DPointCloud->EstimateNormals();
166+
DIFFCHECK_INFO("Default estimation of normals with knn = 30");
167+
}
168+
169+
this->Normals.clear();
170+
for (auto &normal : O3DPointCloud->normals_)
171+
this->Normals.push_back(normal);
78172
}
79173
else
80174
{
81-
O3DPointCloud->EstimateNormals();
82-
DIFFCHECK_INFO("Default estimation of normals with knn = 30");
175+
std::shared_ptr<cilantro::PointCloud3f> cilantroPointCloud = this->Cvt2CilantroPointCloud();
176+
cilantro::KNNNeighborhoodSpecification<int> neighborhood(knn.value());
177+
cilantroPointCloud->estimateNormals(neighborhood, false);
178+
179+
this->Normals.clear();
180+
for (int i = 0; i < cilantroPointCloud->normals.cols(); i++)
181+
this->Normals.push_back(cilantroPointCloud->normals.col(i).cast<double>());
182+
DIFFCHECK_INFO(("Estimating normals with cilantro evaluator with knn = " + std::to_string(knn.value())).c_str());
83183
}
84184

85-
this->Normals.clear();
86-
for (auto &normal : O3DPointCloud->normals_)
87-
this->Normals.push_back(normal);
88185
}
89186

90187
void DFPointCloud::VoxelDownsample(double voxelSize)

src/diffCheck/geometry/DFPointCloud.hh

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
#include <diffCheck/transformation/DFTransformation.hh>
88

9+
#include <cilantro/utilities/point_cloud.hpp>
10+
#include <cilantro/core/nearest_neighbors.hpp>
911

1012
namespace diffCheck::geometry
1113
{
@@ -29,14 +31,22 @@ namespace diffCheck::geometry
2931
* @param pointCloud the open3d point cloud
3032
*/
3133
void Cvt2DFPointCloud(const std::shared_ptr<open3d::geometry::PointCloud> &O3DPointCloud);
32-
34+
void Cvt2DFPointCloud(const std::shared_ptr<cilantro::PointCloud3f> &cilantroPointCloud);
35+
3336
/**
3437
* @brief Convert the DFPointCloud to open3d point cloud
3538
*
3639
* @return std::shared_ptr<open3d::geometry::PointCloud> the open3d point cloud
3740
*/
3841
std::shared_ptr<open3d::geometry::PointCloud> Cvt2O3DPointCloud();
3942

43+
/**
44+
* @brief Convert DFPointCloud to cilantro point cloud
45+
*
46+
* @return std::shared_ptr<cilantro::PointCloud3f> the cilantro point cloud
47+
*/
48+
std::shared_ptr<cilantro::PointCloud3f> Cvt2CilantroPointCloud();
49+
4050
public: ///< Utilities
4151
/**
4252
* @brief Compute the "point to point" distance between this and another point clouds.
@@ -64,11 +74,14 @@ namespace diffCheck::geometry
6474
* is provided by hybrid search.
6575
*
6676
* <a href=https://www.open3d.org/html/cpp_api/classopen3d_1_1t_1_1geometry_1_1_point_cloud.html#a4937528c4b6194092631f002bccc44d0> Reference from Open3d</a>.
77+
*
78+
* @param useCilantroEvaluator if true, the cilantro evaluator will be used, otherwise the open3d one
6779
* @param knn the number of nearest neighbors to consider (by default 30)
68-
* @param searchRadius the radius of the search, by default deactivated
80+
* @param searchRadius the radius of the search, by default deactivated (only if useCilantroEvaluator is false)
6981
*/
7082
void EstimateNormals(
71-
std::optional<int> knn = 30,
83+
bool useCilantroEvaluator = false,
84+
std::optional<int> knn = 10,
7285
std::optional<double> searchRadius = std::nullopt);
7386

7487
public: ///< Downsamplers

src/diffCheck/segmentation/DFSegmentation.cc

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,54 +7,55 @@
77
namespace diffCheck::segmentation
88
{
99
std::vector<std::shared_ptr<geometry::DFPointCloud>> DFSegmentation::NormalBasedSegmentation(
10-
geometry::DFPointCloud &pointCloud,
11-
float voxelSize,
10+
std::shared_ptr<geometry::DFPointCloud> &pointCloud,
1211
float normalThresholdDegree,
1312
int minClusterSize,
1413
bool useKnnNeighborhood,
1514
int knnNeighborhoodSize,
16-
int radiusNeighborhoodSize)
15+
int radiusNeighborhoodSize,
16+
bool colorClusters)
1717
{
18-
std::vector<std::shared_ptr<geometry::DFPointCloud>> segments;
19-
cilantro::PointCloud3f cilantroPointCloud;
20-
21-
// Convert the point cloud to cilantro point cloud
22-
for (int i = 0; i < pointCloud.Points.size(); i++)
23-
{
24-
cilantroPointCloud.points.conservativeResize(3, cilantroPointCloud.points.cols() + 1);
25-
cilantroPointCloud.points.rightCols(1) = pointCloud.Points[i].cast<float>();
26-
}
18+
std::shared_ptr<cilantro::PointCloud3f> cilantroPointCloud = pointCloud->Cvt2CilantroPointCloud();
2719

28-
// segment the point cloud using knn or radius neighborhood
20+
std::vector<std::shared_ptr<geometry::DFPointCloud>> segments;
2921
if (useKnnNeighborhood)
3022
{
3123
cilantro::KNNNeighborhoodSpecification<int> neighborhood(knnNeighborhoodSize);
3224

33-
// conpute the normals and downsample
34-
cilantroPointCloud.estimateNormals(neighborhood, false);
35-
cilantroPointCloud.gridDownsample(voxelSize);
25+
cilantroPointCloud->estimateNormals(neighborhood);
3626

37-
// Similarity evaluator
3827
cilantro::NormalsProximityEvaluator<float, 3> similarityEvaluator(
39-
cilantroPointCloud.normals,
28+
cilantroPointCloud->normals,
4029
normalThresholdDegree*M_PI/180.0f);
4130

42-
// Segment the point cloud
43-
cilantro::ConnectedComponentExtraction3f<> segmenter(cilantroPointCloud.points);
31+
cilantro::ConnectedComponentExtraction3f<> segmenter(cilantroPointCloud->points);
4432
segmenter.segment(neighborhood, similarityEvaluator, minClusterSize);
4533
auto clusterToPointMap = segmenter.getClusterToPointIndicesMap();
4634
int nSegments = segmenter.getNumberOfClusters();
4735

48-
// Get the segments
36+
// FIXME: painting color not working (see paint_uniform?)
4937
for (int indice = 0; indice<nSegments; indice++)
5038
{
5139
std::shared_ptr<geometry::DFPointCloud> segment = std::make_shared<geometry::DFPointCloud>();
40+
41+
// random rgb color in format Eigen::Vector3d from 0 to 1
42+
Eigen::Vector3d color = Eigen::Vector3d::Random();
5243
for (auto pointIndice : clusterToPointMap[indice])
5344
{
54-
Eigen::Vector3d point = cilantroPointCloud.points.col(pointIndice).cast<double>();
55-
Eigen::Vector3d normal = cilantroPointCloud.normals.col(pointIndice).cast<double>();
45+
Eigen::Vector3d point = cilantroPointCloud->points.col(pointIndice).cast<double>();
46+
Eigen::Vector3d normal = cilantroPointCloud->normals.col(pointIndice).cast<double>();
5647
segment->Points.push_back(point);
5748
segment->Normals.push_back(normal);
49+
if (colorClusters)
50+
segment->Colors.push_back(color);
51+
else
52+
{
53+
if (cilantroPointCloud->colors.cols() > 0)
54+
{
55+
Eigen::Vector3d color = cilantroPointCloud->colors.col(pointIndice).cast<double>();
56+
segment->Colors.push_back(color);
57+
}
58+
}
5859
}
5960
segments.push_back(segment);
6061
}
@@ -63,37 +64,43 @@ namespace diffCheck::segmentation
6364
{
6465
cilantro::RadiusNeighborhoodSpecification<float> neighborhood(radiusNeighborhoodSize);
6566

66-
// conpute the normals and downsample
67-
cilantroPointCloud.estimateNormals(neighborhood, false);
68-
cilantroPointCloud.gridDownsample(voxelSize);
69-
70-
// Similarity evaluator
67+
cilantroPointCloud->estimateNormals(neighborhood);
68+
7169
cilantro::NormalsProximityEvaluator<float, 3> similarityEvaluator(
72-
cilantroPointCloud.normals,
70+
cilantroPointCloud->normals,
7371
normalThresholdDegree*M_PI/180.0f);
7472

75-
// Segment the point cloud
76-
cilantro::ConnectedComponentExtraction3f<> segmenter(cilantroPointCloud.points);
73+
cilantro::ConnectedComponentExtraction3f<> segmenter(cilantroPointCloud->points);
7774
segmenter.segment(neighborhood, similarityEvaluator, minClusterSize);
7875

7976
auto clusterToPointMap = segmenter.getClusterToPointIndicesMap();
8077
int nSegments = segmenter.getNumberOfClusters();
8178

82-
// Get the segments
79+
// FIXME: painting color not working (see paint_uniform?)
8380
for (int indice = 0; indice<nSegments; indice++)
8481
{
8582
std::shared_ptr<geometry::DFPointCloud> segment = std::make_shared<geometry::DFPointCloud>();
83+
Eigen::Vector3d color = Eigen::Vector3d::Random();
8684
for (auto pointIndice : clusterToPointMap[indice])
8785
{
88-
Eigen::Vector3d point = cilantroPointCloud.points.col(pointIndice).cast<double>();
89-
Eigen::Vector3d normal = cilantroPointCloud.normals.col(pointIndice).cast<double>();
86+
Eigen::Vector3d point = cilantroPointCloud->points.col(pointIndice).cast<double>();
87+
Eigen::Vector3d normal = cilantroPointCloud->normals.col(pointIndice).cast<double>();
9088
segment->Points.push_back(point);
9189
segment->Normals.push_back(normal);
90+
if (colorClusters)
91+
segment->Colors.push_back(color);
92+
else
93+
{
94+
if (cilantroPointCloud->colors.cols() > 0)
95+
{
96+
Eigen::Vector3d color = cilantroPointCloud->colors.col(pointIndice).cast<double>();
97+
segment->Colors.push_back(color);
98+
}
99+
}
92100
}
93101
segments.push_back(segment);
94102
}
95103
}
96-
97104

98105
return segments;
99106
}

src/diffCheck/segmentation/DFSegmentation.hh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,21 @@ namespace diffCheck::segmentation
88
public:
99
/** @brief Downsamples and segments the point cloud using Cilantro's ConnectedComponentExtraction3f method. It uses the normals' variations to detect different parts in the point cloud.
1010
* @param pointCloud the point cloud to 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
1211
* @param normalThresholdDegree the normal threshold in degrees do differentiate segments. The higher the number, the more tolerent the segmentation will be to normal differences
1312
* @param minClusterSize the minimum cluster size to consider a segment. A lower number will discard smaller segments
1413
* @param useKnnNeighborhood if true, the neighborhood search will be done using the knnNeighborhoodSize, otherwise it will be done using radiusNeighborhoodSize
1514
* @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
1615
* @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.
16+
* @param colorClusters if true, the clusters will be colored with random colors
1717
* @return std::vector<std::shared_ptr<geometry::DFPointCloud>> the segmented point clouds
1818
*/
1919
static std::vector<std::shared_ptr<geometry::DFPointCloud>> NormalBasedSegmentation(
20-
geometry::DFPointCloud &pointCloud,
21-
float voxelSize = 0.2,
20+
std::shared_ptr<geometry::DFPointCloud> &pointCloud,
2221
float normalThresholdDegree = 20,
2322
int minClusterSize = 10,
2423
bool useKnnNeighborhood = true,
2524
int knnNeighborhoodSize = 10,
26-
int radiusNeighborhoodSize = 10);
25+
int radiusNeighborhoodSize = 10,
26+
bool colorClusters = false);
2727
};
2828
} // namespace diffCheck::segmentation

0 commit comments

Comments
 (0)