Skip to content

Commit 6548095

Browse files
per-joint segmentation works at joint face level (#117)
* FIX-UPDATE: clustering works at face level and not joint level anymore * FIX: diffCheckApp replaced with non-failing one (currently not needed) * FIX-UPDATE: Joint segmentator component adapted to output the joints as well as the joint faces individually * FIX: Component and metadata clean-up * FIX: Clean unassociated cliusters adds the colors as well * FIX-UPDATE: CAD degmentator adapted to reflect changes to segmetation backend for face-level analysis * FIX: return value of RunScript of code.py * FIX: syntax fixes for pre-commit * FIX: cleaning PR * FIX-CAP: minor fixes + convertion to ghtree --------- Co-authored-by: Andrea Settimi <andreasettimi39@gmail.com>
1 parent 39b6b36 commit 6548095

File tree

7 files changed

+104
-202
lines changed

7 files changed

+104
-202
lines changed

src/diffCheck/segmentation/DFSegmentation.cc

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -95,23 +95,24 @@ namespace diffCheck::segmentation
9595
return segments;
9696
}
9797

98-
std::shared_ptr<geometry::DFPointCloud> DFSegmentation::AssociateClustersToMeshes(
98+
std::vector<std::shared_ptr<geometry::DFPointCloud>> DFSegmentation::AssociateClustersToMeshes(
9999
std::vector<std::shared_ptr<geometry::DFMesh>> referenceMesh,
100100
std::vector<std::shared_ptr<geometry::DFPointCloud>> &clusters,
101101
double angleThreshold,
102102
double associationThreshold)
103103
{
104-
std::shared_ptr<geometry::DFPointCloud> unifiedPointCloud = std::make_shared<geometry::DFPointCloud>();
104+
std::vector<std::shared_ptr<geometry::DFPointCloud>> jointFaces = std::vector<std::shared_ptr<geometry::DFPointCloud>>();
105105

106106
// iterate through the mesh faces given as function argument
107107
if (referenceMesh.size() == 0)
108108
{
109109
DIFFCHECK_WARN("No mesh faces to associate with the clusters. Returning an empty point cloud.");
110-
return unifiedPointCloud;
110+
return std::vector<std::shared_ptr<geometry::DFPointCloud>>();
111111
}
112112
for (std::shared_ptr<diffCheck::geometry::DFMesh> face : referenceMesh)
113113
{
114114
std::shared_ptr<geometry::DFPointCloud> correspondingSegment;
115+
std::shared_ptr<geometry::DFPointCloud> facePoints = std::make_shared<geometry::DFPointCloud>();
115116

116117
// Getting the center of the mesh face
117118
Eigen::Vector3d faceCenter = face->Cvt2O3DTriangleMesh()->GetCenter();
@@ -124,7 +125,7 @@ namespace diffCheck::segmentation
124125
if (clusters.size() == 0)
125126
{
126127
DIFFCHECK_WARN("No clusters to associate with the mesh faces. Returning an empty point cloud.");
127-
return unifiedPointCloud;
128+
return std::vector<std::shared_ptr<geometry::DFPointCloud>>();
128129
}
129130
for (auto segment : clusters)
130131
{
@@ -160,28 +161,35 @@ namespace diffCheck::segmentation
160161
DIFFCHECK_WARN("No segment found for the face. Skipping the face.");
161162
continue;
162163
}
164+
bool hasColors = correspondingSegment->GetNumColors() > 0;
165+
163166
for (Eigen::Vector3d point : correspondingSegment->Points)
164167
{
165168
bool pointInFace = false;
166169
if (face->IsPointOnFace(point, associationThreshold))
167170
{
168-
unifiedPointCloud->Points.push_back(point);
169-
unifiedPointCloud->Normals.push_back(
171+
facePoints->Points.push_back(point);
172+
facePoints->Normals.push_back(
170173
correspondingSegment->Normals[std::distance(
171174
correspondingSegment->Points.begin(),
172175
std::find(correspondingSegment->Points.begin(),
173176
correspondingSegment->Points.end(),
174177
point))]
175178
);
179+
if (hasColors)
180+
{
181+
facePoints->Colors.push_back(
182+
correspondingSegment->Colors[std::distance(
183+
correspondingSegment->Points.begin(),
184+
std::find(correspondingSegment->Points.begin(),
185+
correspondingSegment->Points.end(),
186+
point))]
187+
);
188+
}
176189
}
177190
}
178-
// removing points from the segment that are in the face
179-
if (unifiedPointCloud->GetNumPoints() == 0)
180-
{
181-
DIFFCHECK_WARN("No point was associated to this segment. Skipping the segment.");
182-
continue;
183-
}
184-
for(Eigen::Vector3d point : unifiedPointCloud->Points)
191+
192+
for(Eigen::Vector3d point : facePoints->Points)
185193
{
186194
correspondingSegment->Points.erase(
187195
std::remove(
@@ -190,8 +198,9 @@ namespace diffCheck::segmentation
190198
point),
191199
correspondingSegment->Points.end());
192200
}
201+
jointFaces.push_back(facePoints);
193202
}
194-
return unifiedPointCloud;
203+
return jointFaces;
195204
}
196205

197206
void DFSegmentation::CleanUnassociatedClusters(
@@ -307,6 +316,10 @@ namespace diffCheck::segmentation
307316
{
308317
completed_segment->Points.push_back(point);
309318
completed_segment->Normals.push_back(cluster->Normals[std::distance(cluster->Points.begin(), std::find(cluster->Points.begin(), cluster->Points.end(), point))]);
319+
if (cluster->GetNumColors() > 0)
320+
{
321+
completed_segment->Colors.push_back(cluster->Colors[std::distance(cluster->Points.begin(), std::find(cluster->Points.begin(), cluster->Points.end(), point))]);
322+
}
310323
}
311324
}
312325
std::vector<int> indicesToRemove;

src/diffCheck/segmentation/DFSegmentation.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ namespace diffCheck::segmentation
3333
* @param associationThreshold the threshold to consider the points of a segment and a mesh face as associable. It is the ratio between the surface of the closest mesh triangle and the sum of the areas of the three triangles that form the rest of the pyramid described by the mesh triangle and the point we want to associate or not. The lower the number, the more strict the association will be and some poinnts on the mesh face might be wrongfully excluded.
3434
* @return std::shared_ptr<geometry::DFPointCloud> The unified segments
3535
*/
36-
static std::shared_ptr<geometry::DFPointCloud> DFSegmentation::AssociateClustersToMeshes(
36+
static std::vector<std::shared_ptr<geometry::DFPointCloud>> DFSegmentation::AssociateClustersToMeshes(
3737
std::vector<std::shared_ptr<geometry::DFMesh>> referenceMesh,
3838
std::vector<std::shared_ptr<geometry::DFPointCloud>> &clusters,
3939
double angleThreshold = 0.1,

src/diffCheckApp.cc

Lines changed: 1 addition & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -12,139 +12,6 @@
1212

1313
int main()
1414
{
15-
auto initTime = std::chrono::high_resolution_clock::now();
16-
17-
std::shared_ptr<diffCheck::geometry::DFPointCloud> pcdSrc = std::make_shared<diffCheck::geometry::DFPointCloud>();
18-
19-
std::vector<std::vector<std::shared_ptr<diffCheck::geometry::DFMesh>>> meshSrc = std::vector<std::vector<std::shared_ptr<diffCheck::geometry::DFMesh>>>();
20-
std::vector<std::shared_ptr<diffCheck::geometry::DFPointCloud>> segments;
21-
std::vector<std::string> meshPaths;
22-
23-
std::string meshesFolderPath = R"(C:\Users\localuser\Desktop\meshes_for_diffCheck\joints\)";
24-
25-
for (int i = 1; i <= 3; i++)
26-
{
27-
std::vector<std::shared_ptr<diffCheck::geometry::DFMesh>> fullJoint;
28-
for (int j = 1; j <= 3; j++)
29-
{
30-
std::string meshPath = meshesFolderPath + std::to_string(i) + "/" + std::to_string(j) + ".ply";
31-
std::shared_ptr<diffCheck::geometry::DFMesh> mesh = std::make_shared<diffCheck::geometry::DFMesh>();
32-
mesh->LoadFromPLY(meshPath);
33-
fullJoint.push_back(mesh);
34-
}
35-
meshSrc.push_back(fullJoint);
36-
}
37-
38-
std::string pathPcdSrc = R"(C:\Users\localuser\Desktop\meshes_for_diffCheck\joints\full_beam.ply)";
39-
40-
pcdSrc->LoadFromPLY(pathPcdSrc);
41-
42-
pcdSrc->EstimateNormals(false, 100);
43-
pcdSrc->VoxelDownsample(0.007);
44-
auto intermediateTime = std::chrono::high_resolution_clock::now();
45-
segments = diffCheck::segmentation::DFSegmentation::NormalBasedSegmentation(
46-
pcdSrc,
47-
15.0f,
48-
15,
49-
true,
50-
50,
51-
0.5f,
52-
false);
53-
std::cout << "number of segments:" << segments.size()<< std::endl;
54-
55-
std::vector<std::shared_ptr<diffCheck::geometry::DFPointCloud>> unifiedSegments;
56-
for (int i = 0; i < meshSrc.size(); i++)
57-
{
58-
std::shared_ptr<diffCheck::geometry::DFPointCloud> unifiedSegment = std::make_shared<diffCheck::geometry::DFPointCloud>();
59-
unifiedSegment = diffCheck::segmentation::DFSegmentation::AssociateClustersToMeshes(
60-
meshSrc[i],
61-
segments,
62-
.2,
63-
.05);
64-
unifiedSegments.push_back(unifiedSegment);
65-
}
66-
67-
diffCheck::segmentation::DFSegmentation::CleanUnassociatedClusters(segments,
68-
unifiedSegments,
69-
meshSrc,
70-
.2,
71-
.05);
72-
73-
// Perform a registration per joint
74-
for (int i = 0; i < meshSrc.size(); i++)
75-
{
76-
std::shared_ptr<diffCheck::geometry::DFPointCloud> referencePointCloud = std::make_shared<diffCheck::geometry::DFPointCloud>();
77-
for (auto jointFace : meshSrc[i])
78-
{
79-
std::shared_ptr<diffCheck::geometry::DFPointCloud> facePointCloud = jointFace->SampleCloudUniform(1000);
80-
referencePointCloud->Points.insert(referencePointCloud->Points.end(), facePointCloud->Points.begin(), facePointCloud->Points.end());
81-
}
82-
referencePointCloud->EstimateNormals(false, 100);
83-
84-
diffCheck::transformation::DFTransformation transformation = diffCheck::registrations::DFRefinedRegistration::O3DICP(
85-
unifiedSegments[i],
86-
referencePointCloud);
87-
88-
std::cout << "Transformation matrix:" << std::endl;
89-
std::cout << transformation.TransformationMatrix << std::endl;
90-
91-
diffCheck::visualizer::Visualizer deVisu = diffCheck::visualizer::Visualizer("DiffCheckApp", 1000, 800, 50, 50, false, true, false);
92-
for (int i = 0; i < segments.size(); i++)
93-
{
94-
segments[i]->ApplyTransformation(transformation);
95-
deVisu.AddPointCloud(segments[i]);
96-
}
97-
for (auto joint : meshSrc)
98-
{
99-
for (auto face : joint)
100-
{
101-
deVisu.AddMesh(face);
102-
}
103-
}
104-
deVisu.Run();
105-
}
106-
107-
diffCheck::visualizer::Visualizer vis(std::string("DiffCheckApp"), 1000, 800, 50, 50, false, true, false);
108-
for (auto segment : segments)
109-
{
110-
// colorize the segments with random colors
111-
double r = static_cast<double>(rand()) / RAND_MAX;
112-
double g = static_cast<double>(rand()) / RAND_MAX;
113-
double b = static_cast<double>(rand()) / RAND_MAX;
114-
115-
segment->Colors.clear();
116-
for (int i = 0; i < segment->Points.size(); i++)
117-
{
118-
segment->Colors.push_back(Eigen::Vector3d(0, 0, 0));
119-
}
120-
vis.AddPointCloud(segment);
121-
}
122-
for(auto joint : meshSrc)
123-
{
124-
for(auto mesh : joint){vis.AddMesh(mesh);}
125-
}
126-
127-
int numSegments = unifiedSegments.size();
128-
129-
for (int i = 0; i < numSegments; i++)
130-
{
131-
for (int j = 0; j < unifiedSegments[i]->Points.size(); j++)
132-
{
133-
unifiedSegments[i]->Colors.push_back(Eigen::Vector3d((double(numSegments) - double(i))/double(numSegments), 1, double(i) / double(numSegments)));
134-
}
135-
}
136-
for (auto seg : unifiedSegments)
137-
{
138-
vis.AddPointCloud(seg);
139-
}
140-
141-
auto endTime = std::chrono::high_resolution_clock::now();
142-
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - initTime);
143-
auto segmentationTime = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - intermediateTime);
144-
std::cout << "Total computation time:" << duration.count() << std::endl;
145-
std::cout << "Segmentation time:" << segmentationTime.count() << std::endl;
146-
147-
vis.Run();
148-
15+
std::cout << "Hello, World!" << std::endl;
14916
return 0;
15017
}

src/gh/components/DF_CAD_segmentator/code.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99

1010
from diffCheck.diffcheck_bindings import dfb_segmentation
11+
from diffCheck.diffcheck_bindings import dfb_geometry
1112

1213
from diffCheck import df_cvt_bindings
1314

@@ -18,10 +19,10 @@ def RunScript(self,
1819
i_clouds: System.Collections.Generic.IList[Rhino.Geometry.PointCloud],
1920
i_assembly,
2021
i_angle_threshold: float = 0.1,
21-
i_association_threshold: float = 0.1) -> rg.PointCloud:
22+
i_association_threshold: float = 0.1) -> Rhino.Geometry.PointCloud:
2223

2324
if i_clouds is None or i_assembly is None:
24-
self.AddRuntimeMessage(RML.Warning, "Please provide a cloud and an assembly to segmentate")
25+
self.AddRuntimeMessage(RML.Warning, "Please provide a cloud and an assembly to segment.")
2526
return None
2627
if i_angle_threshold is None:
2728
i_angle_threshold = 0.1
@@ -43,12 +44,16 @@ def RunScript(self,
4344
df_beams_meshes.append(df_b_mesh_faces)
4445
rh_beams_meshes.append(rh_b_mesh_faces)
4546

46-
df_asssociated_cluster = dfb_segmentation.DFSegmentation.associate_clusters(
47+
df_asssociated_cluster_faces = dfb_segmentation.DFSegmentation.associate_clusters(
4748
reference_mesh=df_b_mesh_faces,
4849
unassociated_clusters=df_clouds,
4950
angle_threshold=i_angle_threshold,
5051
association_threshold=i_association_threshold
5152
)
53+
54+
df_asssociated_cluster = dfb_geometry.DFPointCloud()
55+
for df_associated_face in df_asssociated_cluster_faces:
56+
df_asssociated_cluster.add_points(df_associated_face)
5257
df_clusters.append(df_asssociated_cluster)
5358

5459
dfb_segmentation.DFSegmentation.clean_unassociated_clusters(
@@ -61,4 +66,4 @@ def RunScript(self,
6166

6267
o_clusters = [df_cvt_bindings.cvt_dfcloud_2_rhcloud(cluster) for cluster in df_clusters]
6368

64-
return o_clusters, rh_beams_meshes
69+
return o_clusters

0 commit comments

Comments
 (0)