Skip to content

Commit 5a2ef4d

Browse files
authored
Merge pull request #174 from diffCheckOrg/feature/improve_CAD_segmentation
Add ICP registration as step of CAD segmentation
2 parents 84a5d21 + e5115ba commit 5a2ef4d

File tree

6 files changed

+180
-48
lines changed

6 files changed

+180
-48
lines changed

src/diffCheck/segmentation/DFSegmentation.cc

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,12 @@ namespace diffCheck::segmentation
9797

9898
std::vector<std::shared_ptr<geometry::DFPointCloud>> DFSegmentation::AssociateClustersToMeshes(
9999
bool isCylinder,
100+
bool discriminatePoints,
100101
std::vector<std::shared_ptr<geometry::DFMesh>> referenceMesh,
101102
std::vector<std::shared_ptr<geometry::DFPointCloud>> &clusters,
102103
double angleThreshold,
103104
double associationThreshold,
104-
double angleAssociationThreshold)
105+
double maximumFaceSegmentDistance)
105106
{
106107
std::vector<std::shared_ptr<geometry::DFPointCloud>> faceSegments = std::vector<std::shared_ptr<geometry::DFPointCloud>>();
107108

@@ -270,12 +271,12 @@ namespace diffCheck::segmentation
270271
for (auto normal : segment->Normals){segmentNormal += normal;}
271272
segmentNormal.normalize();
272273
double currentDistance = (faceCenter - segmentCenter).norm();
274+
double currentDitanceOrthogonalToFace = std::abs((faceCenter - segmentCenter).dot(faceNormal));
273275
double currentAngle = std::abs(sin(acos(faceNormal.dot(faceCenter - segmentCenter))));
274-
// if the distance is smaller than the previous one, update the distance and the corresponding segment
275-
if (std::abs(sin(acos(faceNormal.dot(segmentNormal)))) < angleThreshold && currentDistance * (angleAssociationThreshold + std::abs(faceNormal.dot((faceCenter - segmentCenter) / (faceCenter - segmentCenter).norm()))) < faceDistance)
276+
if (std::abs(sin(acos(faceNormal.dot(segmentNormal)))) < angleThreshold && currentDitanceOrthogonalToFace < maximumFaceSegmentDistance && currentDitanceOrthogonalToFace < faceDistance)
276277
{
277278
correspondingSegment = segment;
278-
faceDistance = currentDistance * (angleAssociationThreshold + std::abs(faceNormal.dot((faceCenter - segmentCenter) / (faceCenter - segmentCenter).norm())));
279+
faceDistance = currentDitanceOrthogonalToFace;
279280
}
280281
}
281282

@@ -289,8 +290,32 @@ namespace diffCheck::segmentation
289290

290291
for (Eigen::Vector3d point : correspondingSegment->Points)
291292
{
292-
bool pointInFace = false;
293-
if (face->IsPointOnFace(point, associationThreshold))
293+
if (discriminatePoints)
294+
{
295+
bool pointInFace = false;
296+
if (face->IsPointOnFace(point, associationThreshold))
297+
{
298+
facePoints->Points.push_back(point);
299+
facePoints->Normals.push_back(
300+
correspondingSegment->Normals[std::distance(
301+
correspondingSegment->Points.begin(),
302+
std::find(correspondingSegment->Points.begin(),
303+
correspondingSegment->Points.end(),
304+
point))]
305+
);
306+
if (hasColors)
307+
{
308+
facePoints->Colors.push_back(
309+
correspondingSegment->Colors[std::distance(
310+
correspondingSegment->Points.begin(),
311+
std::find(correspondingSegment->Points.begin(),
312+
correspondingSegment->Points.end(),
313+
point))]
314+
);
315+
}
316+
}
317+
}
318+
else
294319
{
295320
facePoints->Points.push_back(point);
296321
facePoints->Normals.push_back(
@@ -330,12 +355,13 @@ namespace diffCheck::segmentation
330355

331356
void DFSegmentation::CleanUnassociatedClusters(
332357
bool isCylinder,
358+
bool discriminatePoints,
333359
std::vector<std::shared_ptr<geometry::DFPointCloud>> &unassociatedClusters,
334360
std::vector<std::vector<std::shared_ptr<geometry::DFPointCloud>>> &existingPointCloudSegments,
335361
std::vector<std::vector<std::shared_ptr<geometry::DFMesh>>> meshes,
336362
double angleThreshold,
337363
double associationThreshold,
338-
double angleAssociationThreshold)
364+
double maximumFaceSegmentDistance)
339365
{
340366
if (unassociatedClusters.size() == 0)
341367
{
@@ -443,7 +469,7 @@ namespace diffCheck::segmentation
443469

444470
double currentDistance = (clusterCenter - faceCenter).norm() * std::abs(std::cos(clusterNormalToJunctionLineAngle))
445471
/ std::min(std::abs(clusterNormal.dot(faceNormal)), 0.05) ;
446-
if (std::abs(sin(acos(faceNormal.dot(clusterNormal)))) < angleThreshold && currentDistance * (angleAssociationThreshold + std::abs(faceNormal.dot((faceCenter - clusterCenter) / (faceCenter - clusterCenter).norm()))) < distance)
472+
if (std::abs(sin(acos(faceNormal.dot(clusterNormal)))) < angleThreshold && currentDistance < maximumFaceSegmentDistance && currentDistance * (std::abs(faceNormal.dot((faceCenter - clusterCenter) / (faceCenter - clusterCenter).norm()))) < distance)
447473
{
448474
goodMeshIndex = meshIndex;
449475
goodFaceIndex = faceIndex;
@@ -477,12 +503,23 @@ namespace diffCheck::segmentation
477503
completed_segment->Colors.push_back(cluster->Colors[std::distance(cluster->Points.begin(), std::find(cluster->Points.begin(), cluster->Points.end(), point))]);
478504
}
479505
else
480-
if (correspondingMeshFace->IsPointOnFace(point, associationThreshold))
506+
{
507+
if (discriminatePoints)
508+
{
509+
if (correspondingMeshFace->IsPointOnFace(point, associationThreshold))
510+
{
511+
completed_segment->Points.push_back(point);
512+
completed_segment->Normals.push_back(cluster->Normals[std::distance(cluster->Points.begin(), std::find(cluster->Points.begin(), cluster->Points.end(), point))]);
513+
completed_segment->Colors.push_back(cluster->Colors[std::distance(cluster->Points.begin(), std::find(cluster->Points.begin(), cluster->Points.end(), point))]);
514+
}
515+
}
516+
else
481517
{
482518
completed_segment->Points.push_back(point);
483519
completed_segment->Normals.push_back(cluster->Normals[std::distance(cluster->Points.begin(), std::find(cluster->Points.begin(), cluster->Points.end(), point))]);
484520
completed_segment->Colors.push_back(cluster->Colors[std::distance(cluster->Points.begin(), std::find(cluster->Points.begin(), cluster->Points.end(), point))]);
485521
}
522+
}
486523
}
487524
std::vector<int> indicesToRemove;
488525

src/diffCheck/segmentation/DFSegmentation.hh

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,38 +28,42 @@ namespace diffCheck::segmentation
2828
public: ///< segmentation refinement methods
2929
/** @brief Associates point cloud segments to mesh faces and merges them. It uses the center of mass of the segments and the mesh faces to find correspondances. For each mesh face it then iteratively associate the points of the segment that are actually on the mesh face.
3030
* @param isCylinder a boolean to indicate if the model is a cylinder. If true, the method will use the GetCenterAndAxis method of the mesh to find the center and axis of the mesh. based on that, we only want points that have normals more or less perpendicular to the cylinder axis.
31+
* @param discriminatePoints a boolean to indicate if we want to discriminate points based on their normal direction when associating clusters to mesh faces. If true, only points that have normals more or less aligned with the face normal will be considered for association.
3132
* @param referenceMesh the vector of mesh faces to associate with the segments. It is a representation of a beam and its faces.
3233
* @param clusters the vector of clusters from cilantro to associate with the mesh faces of the reference mesh
3334
* @param angleThreshold the threshold to consider the a cluster as potential candidate for association. the value passed is the minimum sine of the angles. A value of 0 requires perfect alignment (angle = 0), while a value of 0.1 allows an angle of 5.7 degrees.
3435
* @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.
35-
* @param angleAssociationThreshold a number to indicate how much distance in the plane of the face should be favored, compared to distance orthogonal to the face normal. If set to 0, any face in the same plane as the face will be considered as having a distance of 0. If set to a high value (e.g. 1000000), no difference will be made between distance in the plane of the face and orthogonal to it. Default is 0.5
36+
* @param maximumFaceSegmentDistance the maximum distance a segment's center of mass can be perpendicularly to a mesh face
3637
* @return std::shared_ptr<geometry::DFPointCloud> The unified segments
3738
*/
3839
static std::vector<std::shared_ptr<geometry::DFPointCloud>> DFSegmentation::AssociateClustersToMeshes(
3940
bool isCylinder,
41+
bool discriminatePoints,
4042
std::vector<std::shared_ptr<geometry::DFMesh>> referenceMesh,
4143
std::vector<std::shared_ptr<geometry::DFPointCloud>> &clusters,
4244
double angleThreshold = 0.1,
4345
double associationThreshold = 0.1,
44-
double angleAssociationThreshold = 0.5);
46+
double maximumFaceSegmentDistance = 0.05);
4547

4648
/** @brief Iterated through clusters and finds the corresponding mesh face. It then associates the points of the cluster that are on the mesh face to the segment already associated with the mesh face.
4749
* @param isCylinder a boolean to indicate if the model is a cylinder. If true, the method will use the GetCenterAndAxis method of the mesh to find the center and axis of the mesh. based on that, we only want points that have normals more or less perpendicular to the cylinder axis.
50+
* @param discriminatePoints a boolean to indicate if we want to discriminate points based on their normal direction when associating clusters to mesh faces. If true, only points that have normals more or less aligned with the face normal will be considered for association.
4851
* @param unassociatedClusters the clusters from the normal-based segmentatinon that haven't been associated yet.
4952
* @param existingPointCloudSegments the already associated segments per mesh face.
5053
* @param meshes the mesh faces for all the model. This is used to associate the clusters to the mesh faces.
5154
* @param angleThreshold the threshold to consider the a cluster as potential candidate for association. the value passed is the minimum sine of the angles. A value of 0 requires perfect alignment (angle = 0), while a value of 0.1 allows an angle of 5.7 degrees.
5255
* @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.
53-
* @param angleAssociationThreshold a number to indicate how much distance in the plane of the face should be favored, compared to distance orthogonal to the face normal. If set to 0, any face in the same plane as the face will be considered as having a distance of 0. If set to a high value (e.g. 1000000), no difference will be made between distance in the plane of the face and orthogonal to it. Default is 0.5
56+
* @param maximumFaceSegmentDistance the maximum distance a segment's center of mass can be perpendicularly to a mesh face
5457
* @return void
5558
*/
5659
static void DFSegmentation::CleanUnassociatedClusters(
5760
bool isCylinder,
61+
bool discriminatePoints,
5862
std::vector<std::shared_ptr<geometry::DFPointCloud>> &unassociatedClusters,
5963
std::vector<std::vector<std::shared_ptr<geometry::DFPointCloud>>> &existingPointCloudSegments,
6064
std::vector<std::vector<std::shared_ptr<geometry::DFMesh>>> meshes,
6165
double angleThreshold = 0.1,
6266
double associationThreshold = 0.1,
63-
double angleAssociationThreshold = 0.5);
67+
double maximumFaceSegmentDistance = 0.05);
6468
};
6569
} // namespace diffCheck::segmentation

src/diffCheckBindings.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,18 +226,20 @@ PYBIND11_MODULE(diffcheck_bindings, m) {
226226

227227
.def_static("associate_clusters", &diffCheck::segmentation::DFSegmentation::AssociateClustersToMeshes,
228228
py::arg("is_roundwood"),
229+
py::arg("discriminate_points"),
229230
py::arg("reference_mesh"),
230231
py::arg("unassociated_clusters"),
231232
py::arg("angle_threshold") = 0.1,
232233
py::arg("association_threshold") = 0.1,
233-
py::arg("angle_association_threshold") = 0.5)
234+
py::arg("maximum_face_segment_distance") = 0.05)
234235

235236
.def_static("clean_unassociated_clusters", &diffCheck::segmentation::DFSegmentation::CleanUnassociatedClusters,
236237
py::arg("is_roundwood"),
238+
py::arg("discriminate_points"),
237239
py::arg("unassociated_clusters"),
238240
py::arg("associated_clusters"),
239241
py::arg("reference_mesh"),
240242
py::arg("angle_threshold") = 0.1,
241243
py::arg("association_threshold") = 0.1,
242-
py::arg("angle_association_threshold") = 0.5);
244+
py::arg("maximum_face_segment_distance") = 0.05);
243245
}

0 commit comments

Comments
 (0)