Skip to content

Commit

Permalink
per-joint segmentation works at joint face level (#117)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
DamienGilliard and 9and3 authored Sep 21, 2024
1 parent 39b6b36 commit 6548095
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 202 deletions.
41 changes: 27 additions & 14 deletions src/diffCheck/segmentation/DFSegmentation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,23 +95,24 @@ namespace diffCheck::segmentation
return segments;
}

std::shared_ptr<geometry::DFPointCloud> DFSegmentation::AssociateClustersToMeshes(
std::vector<std::shared_ptr<geometry::DFPointCloud>> DFSegmentation::AssociateClustersToMeshes(
std::vector<std::shared_ptr<geometry::DFMesh>> referenceMesh,
std::vector<std::shared_ptr<geometry::DFPointCloud>> &clusters,
double angleThreshold,
double associationThreshold)
{
std::shared_ptr<geometry::DFPointCloud> unifiedPointCloud = std::make_shared<geometry::DFPointCloud>();
std::vector<std::shared_ptr<geometry::DFPointCloud>> jointFaces = std::vector<std::shared_ptr<geometry::DFPointCloud>>();

// iterate through the mesh faces given as function argument
if (referenceMesh.size() == 0)
{
DIFFCHECK_WARN("No mesh faces to associate with the clusters. Returning an empty point cloud.");
return unifiedPointCloud;
return std::vector<std::shared_ptr<geometry::DFPointCloud>>();
}
for (std::shared_ptr<diffCheck::geometry::DFMesh> face : referenceMesh)
{
std::shared_ptr<geometry::DFPointCloud> correspondingSegment;
std::shared_ptr<geometry::DFPointCloud> facePoints = std::make_shared<geometry::DFPointCloud>();

// Getting the center of the mesh face
Eigen::Vector3d faceCenter = face->Cvt2O3DTriangleMesh()->GetCenter();
Expand All @@ -124,7 +125,7 @@ namespace diffCheck::segmentation
if (clusters.size() == 0)
{
DIFFCHECK_WARN("No clusters to associate with the mesh faces. Returning an empty point cloud.");
return unifiedPointCloud;
return std::vector<std::shared_ptr<geometry::DFPointCloud>>();
}
for (auto segment : clusters)
{
Expand Down Expand Up @@ -160,28 +161,35 @@ namespace diffCheck::segmentation
DIFFCHECK_WARN("No segment found for the face. Skipping the face.");
continue;
}
bool hasColors = correspondingSegment->GetNumColors() > 0;

for (Eigen::Vector3d point : correspondingSegment->Points)
{
bool pointInFace = false;
if (face->IsPointOnFace(point, associationThreshold))
{
unifiedPointCloud->Points.push_back(point);
unifiedPointCloud->Normals.push_back(
facePoints->Points.push_back(point);
facePoints->Normals.push_back(
correspondingSegment->Normals[std::distance(
correspondingSegment->Points.begin(),
std::find(correspondingSegment->Points.begin(),
correspondingSegment->Points.end(),
point))]
);
if (hasColors)
{
facePoints->Colors.push_back(
correspondingSegment->Colors[std::distance(
correspondingSegment->Points.begin(),
std::find(correspondingSegment->Points.begin(),
correspondingSegment->Points.end(),
point))]
);
}
}
}
// removing points from the segment that are in the face
if (unifiedPointCloud->GetNumPoints() == 0)
{
DIFFCHECK_WARN("No point was associated to this segment. Skipping the segment.");
continue;
}
for(Eigen::Vector3d point : unifiedPointCloud->Points)

for(Eigen::Vector3d point : facePoints->Points)
{
correspondingSegment->Points.erase(
std::remove(
Expand All @@ -190,8 +198,9 @@ namespace diffCheck::segmentation
point),
correspondingSegment->Points.end());
}
jointFaces.push_back(facePoints);
}
return unifiedPointCloud;
return jointFaces;
}

void DFSegmentation::CleanUnassociatedClusters(
Expand Down Expand Up @@ -307,6 +316,10 @@ namespace diffCheck::segmentation
{
completed_segment->Points.push_back(point);
completed_segment->Normals.push_back(cluster->Normals[std::distance(cluster->Points.begin(), std::find(cluster->Points.begin(), cluster->Points.end(), point))]);
if (cluster->GetNumColors() > 0)
{
completed_segment->Colors.push_back(cluster->Colors[std::distance(cluster->Points.begin(), std::find(cluster->Points.begin(), cluster->Points.end(), point))]);
}
}
}
std::vector<int> indicesToRemove;
Expand Down
2 changes: 1 addition & 1 deletion src/diffCheck/segmentation/DFSegmentation.hh
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace diffCheck::segmentation
* @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.
* @return std::shared_ptr<geometry::DFPointCloud> The unified segments
*/
static std::shared_ptr<geometry::DFPointCloud> DFSegmentation::AssociateClustersToMeshes(
static std::vector<std::shared_ptr<geometry::DFPointCloud>> DFSegmentation::AssociateClustersToMeshes(
std::vector<std::shared_ptr<geometry::DFMesh>> referenceMesh,
std::vector<std::shared_ptr<geometry::DFPointCloud>> &clusters,
double angleThreshold = 0.1,
Expand Down
135 changes: 1 addition & 134 deletions src/diffCheckApp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,139 +12,6 @@

int main()
{
auto initTime = std::chrono::high_resolution_clock::now();

std::shared_ptr<diffCheck::geometry::DFPointCloud> pcdSrc = std::make_shared<diffCheck::geometry::DFPointCloud>();

std::vector<std::vector<std::shared_ptr<diffCheck::geometry::DFMesh>>> meshSrc = std::vector<std::vector<std::shared_ptr<diffCheck::geometry::DFMesh>>>();
std::vector<std::shared_ptr<diffCheck::geometry::DFPointCloud>> segments;
std::vector<std::string> meshPaths;

std::string meshesFolderPath = R"(C:\Users\localuser\Desktop\meshes_for_diffCheck\joints\)";

for (int i = 1; i <= 3; i++)
{
std::vector<std::shared_ptr<diffCheck::geometry::DFMesh>> fullJoint;
for (int j = 1; j <= 3; j++)
{
std::string meshPath = meshesFolderPath + std::to_string(i) + "/" + std::to_string(j) + ".ply";
std::shared_ptr<diffCheck::geometry::DFMesh> mesh = std::make_shared<diffCheck::geometry::DFMesh>();
mesh->LoadFromPLY(meshPath);
fullJoint.push_back(mesh);
}
meshSrc.push_back(fullJoint);
}

std::string pathPcdSrc = R"(C:\Users\localuser\Desktop\meshes_for_diffCheck\joints\full_beam.ply)";

pcdSrc->LoadFromPLY(pathPcdSrc);

pcdSrc->EstimateNormals(false, 100);
pcdSrc->VoxelDownsample(0.007);
auto intermediateTime = std::chrono::high_resolution_clock::now();
segments = diffCheck::segmentation::DFSegmentation::NormalBasedSegmentation(
pcdSrc,
15.0f,
15,
true,
50,
0.5f,
false);
std::cout << "number of segments:" << segments.size()<< std::endl;

std::vector<std::shared_ptr<diffCheck::geometry::DFPointCloud>> unifiedSegments;
for (int i = 0; i < meshSrc.size(); i++)
{
std::shared_ptr<diffCheck::geometry::DFPointCloud> unifiedSegment = std::make_shared<diffCheck::geometry::DFPointCloud>();
unifiedSegment = diffCheck::segmentation::DFSegmentation::AssociateClustersToMeshes(
meshSrc[i],
segments,
.2,
.05);
unifiedSegments.push_back(unifiedSegment);
}

diffCheck::segmentation::DFSegmentation::CleanUnassociatedClusters(segments,
unifiedSegments,
meshSrc,
.2,
.05);

// Perform a registration per joint
for (int i = 0; i < meshSrc.size(); i++)
{
std::shared_ptr<diffCheck::geometry::DFPointCloud> referencePointCloud = std::make_shared<diffCheck::geometry::DFPointCloud>();
for (auto jointFace : meshSrc[i])
{
std::shared_ptr<diffCheck::geometry::DFPointCloud> facePointCloud = jointFace->SampleCloudUniform(1000);
referencePointCloud->Points.insert(referencePointCloud->Points.end(), facePointCloud->Points.begin(), facePointCloud->Points.end());
}
referencePointCloud->EstimateNormals(false, 100);

diffCheck::transformation::DFTransformation transformation = diffCheck::registrations::DFRefinedRegistration::O3DICP(
unifiedSegments[i],
referencePointCloud);

std::cout << "Transformation matrix:" << std::endl;
std::cout << transformation.TransformationMatrix << std::endl;

diffCheck::visualizer::Visualizer deVisu = diffCheck::visualizer::Visualizer("DiffCheckApp", 1000, 800, 50, 50, false, true, false);
for (int i = 0; i < segments.size(); i++)
{
segments[i]->ApplyTransformation(transformation);
deVisu.AddPointCloud(segments[i]);
}
for (auto joint : meshSrc)
{
for (auto face : joint)
{
deVisu.AddMesh(face);
}
}
deVisu.Run();
}

diffCheck::visualizer::Visualizer vis(std::string("DiffCheckApp"), 1000, 800, 50, 50, false, true, false);
for (auto segment : segments)
{
// colorize the segments with random colors
double r = static_cast<double>(rand()) / RAND_MAX;
double g = static_cast<double>(rand()) / RAND_MAX;
double b = static_cast<double>(rand()) / RAND_MAX;

segment->Colors.clear();
for (int i = 0; i < segment->Points.size(); i++)
{
segment->Colors.push_back(Eigen::Vector3d(0, 0, 0));
}
vis.AddPointCloud(segment);
}
for(auto joint : meshSrc)
{
for(auto mesh : joint){vis.AddMesh(mesh);}
}

int numSegments = unifiedSegments.size();

for (int i = 0; i < numSegments; i++)
{
for (int j = 0; j < unifiedSegments[i]->Points.size(); j++)
{
unifiedSegments[i]->Colors.push_back(Eigen::Vector3d((double(numSegments) - double(i))/double(numSegments), 1, double(i) / double(numSegments)));
}
}
for (auto seg : unifiedSegments)
{
vis.AddPointCloud(seg);
}

auto endTime = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - initTime);
auto segmentationTime = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - intermediateTime);
std::cout << "Total computation time:" << duration.count() << std::endl;
std::cout << "Segmentation time:" << segmentationTime.count() << std::endl;

vis.Run();

std::cout << "Hello, World!" << std::endl;
return 0;
}
13 changes: 9 additions & 4 deletions src/gh/components/DF_CAD_segmentator/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@


from diffCheck.diffcheck_bindings import dfb_segmentation
from diffCheck.diffcheck_bindings import dfb_geometry

from diffCheck import df_cvt_bindings

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

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

df_asssociated_cluster = dfb_segmentation.DFSegmentation.associate_clusters(
df_asssociated_cluster_faces = dfb_segmentation.DFSegmentation.associate_clusters(
reference_mesh=df_b_mesh_faces,
unassociated_clusters=df_clouds,
angle_threshold=i_angle_threshold,
association_threshold=i_association_threshold
)

df_asssociated_cluster = dfb_geometry.DFPointCloud()
for df_associated_face in df_asssociated_cluster_faces:
df_asssociated_cluster.add_points(df_associated_face)
df_clusters.append(df_asssociated_cluster)

dfb_segmentation.DFSegmentation.clean_unassociated_clusters(
Expand All @@ -61,4 +66,4 @@ def RunScript(self,

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

return o_clusters, rh_beams_meshes
return o_clusters
Loading

0 comments on commit 6548095

Please sign in to comment.