From fc26651ac512774493535cd6193037fd1fcc7665 Mon Sep 17 00:00:00 2001 From: Paul Leroy Date: Wed, 26 Mar 2025 10:52:15 +0100 Subject: [PATCH] duplicates shall be removed before segmentation + 1 bug keep only one g3point_summits cloud better handling of stacks checking correction: very strange hardcoded value 10 instead of nlabels --- include/G3PointAction.h | 2 +- src/G3PointAction.cpp | 46 ++++++++++++++++++++++++++++++++--------- ui/G3PointDisclaimer.ui | 8 +++---- 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/include/G3PointAction.h b/include/G3PointAction.h index 6aa0212..78b04bc 100644 --- a/include/G3PointAction.h +++ b/include/G3PointAction.h @@ -64,7 +64,7 @@ private: bool updateLabelsAndColors(); bool checkStacks(const std::vector>& stacks, int count); void addToStackBraunWillett(int index, const Eigen::ArrayXi& delta, const Eigen::ArrayXi &Di, std::vector& stack, int local_maximum); - int segmentLabelsBraunWillett(bool useParallelStrategy=true); + int segmentLabelsBraunWillett(); void getNeighborsDistancesSlopes(unsigned index); void computeNodeSurfaces(); bool computeNormalsAndOrientThemWithCloudCompare(); diff --git a/src/G3PointAction.cpp b/src/G3PointAction.cpp index 92084b3..19751dc 100644 --- a/src/G3PointAction.cpp +++ b/src/G3PointAction.cpp @@ -463,13 +463,17 @@ bool G3PointAction::checkStacks(const std::vector>& stacks, int if (errorCount) { - ccLog::Error("[G3PointAction::check_stacks] number of duplicates " + QString::number(errorCount)); + ccLog::Warning("[G3PointAction::check_stacks] number of duplicates " + QString::number(errorCount)); + ret = false; } // the number of points in the stacks shall be equal to count if(indexes.size() != count) { - ccLog::Warning("[G3PointAction::check_stacks] size of indexes " + QString::number(indexes.size()) + ", point count " + QString::number(m_cloud->size())); + ccLog::Warning("[G3PointAction::check_stacks] point in stacks " + + QString::number(indexes.size()) + + ", expected " + QString::number(m_cloud->size()) + + " (may be due to duplicates in the point cloud)"); ret = false; } @@ -602,12 +606,11 @@ bool G3PointAction::exportLocalMaximaAsCloud(const Eigen::ArrayXi& localMaximumI cloud->showColors(true); - ccHObject* parent = m_cloud->getParent(); - int nbChildren = parent->getChildrenNumber(); + int nbChildren = m_cloud->getChildrenNumber(); std::vector toDelete; for (int k = 0; k < nbChildren; k++) { - auto child = parent->getChild(k); + auto child = m_cloud->getChild(k); if (child->getName() == cloudName) { @@ -821,7 +824,7 @@ bool G3PointAction::EigenArrayToFile(QString name, T array) bool G3PointAction::cluster() { - ccLog::Print("[cluster_labels]"); + ccLog::Print("[cluster labels]"); size_t nlabels = m_stacks.size(); m_maxAngle1 = m_dlg->getMaxAngle1(); @@ -865,7 +868,7 @@ bool G3PointAction::cluster() // If the radius of the sink is above the distance to the other sink (by a factor of rad_factor), set Dist to 1 Eigen::ArrayXXi Dist = Eigen::ArrayXXi::Zero(nlabels, nlabels); Dist = (m_radiusFactor * D2 > D1).select(1, Dist); - for (int i = 0; i < 10; i++) // set the values of the diagonal to 0 + for (int i = 0; i < nlabels; i++) // set the values of the diagonal to 0 { Dist(i, i) = 0; } @@ -903,6 +906,7 @@ bool G3PointAction::cluster() if (!checkStacks(m_stacks, m_cloud->size())) { ccLog::Error("m_stacks is not valid"); + return false; } // create the condition matrix and force the symmetry of the matrix @@ -1328,6 +1332,7 @@ bool G3PointAction::cleanLabels() // merge points considering the normals at the border { ccLog::Print("[cleanLabels] merge points considering the normals at the border"); + std::cout << "[cleanLabels] merge points considering the normals at the border" << std::endl; Eigen::ArrayXXd A = computeMeanAngleBetweenNormalsAtBorders(); XXb condition = (A > m_maxAngle2) || (A != A); // add true on the diagonal (important for the if hereafter) XXb symmetrical_condition = (condition == condition.transpose()).select(condition, true); @@ -1340,10 +1345,11 @@ bool G3PointAction::cleanLabels() //remove small labels { ccLog::Print("[cleanLabels] remove small labels"); + std::cout << "[cleanLabels] remove small labels" << std::endl; Eigen::ArrayXi stackSize(m_stacks.size()); for (size_t k = 0; k < m_stacks.size(); k++) { - stackSize(k) = static_cast(m_stacks[k].size()); + stackSize(k) = static_cast(m_stacks[k].size()); } Xb condition = (stackSize > m_nMin); size_t numberOfGrainsToKeep = condition.count(); @@ -1366,6 +1372,7 @@ bool G3PointAction::cleanLabels() // remove flattish labels { ccLog::Print("[cleanLabels] remove flattish labels"); + std::cout << "[cleanLabels] remove flattish labels" << std::endl; Eigen::ArrayX3d s(m_stacks.size(), 3); for (size_t k = 0; k < m_stacks.size(); k++) { @@ -1421,7 +1428,7 @@ void G3PointAction::addToStackBraunWillett(int index, const Eigen::ArrayXi& delt } } -int G3PointAction::segmentLabelsBraunWillett(bool useParallelStrategy) +int G3PointAction::segmentLabelsBraunWillett() { std::cout << "[segment_labels]" << std::endl; @@ -1573,6 +1580,12 @@ int G3PointAction::segmentLabelsBraunWillett(bool useParallelStrategy) m_initialStacks.push_back(stack); } + if (!checkStacks(m_initialStacks, m_cloud->size())) // check the stacks coherency + { + m_cloud->deleteScalarField(sfIdx); + return -1; + } + if (g3point_label) { g3point_label->computeMinAndMax(); @@ -1817,7 +1830,13 @@ void G3PointAction::segment() init(); // Find neighbors of each point of the cloud - queryNeighbors(m_cloud, m_app, true); + bool useParallelStrategy; +#ifdef NDEBUG + useParallelStrategy = true; +#else + useParallelStrategy = false; +#endif + queryNeighbors(m_cloud, m_app, useParallelStrategy); computeNodeSurfaces(); @@ -1840,6 +1859,11 @@ void G3PointAction::segment() // Perform initial segmentation int nLabels = segmentLabelsBraunWillett(); + if (nLabels == -1) + { + ccLog::Error("[G3Point::segment] initial segmentation failed, abort segmentation"); + return; + } exportLocalMaximaAsCloud(m_initial_localMaximumIndexes); @@ -1867,6 +1891,7 @@ void G3PointAction::clusterAndOrClean() if (!cluster()) { ccLog::Error("[G3PointAction::clusterAndOrClean] clustering failed"); + return; } } @@ -1875,6 +1900,7 @@ void G3PointAction::clusterAndOrClean() if (!cleanLabels()) { ccLog::Error("[G3PointAction::clusterAndOrClean] cleaning failed"); + return; } } } diff --git a/ui/G3PointDisclaimer.ui b/ui/G3PointDisclaimer.ui index 2dcdb75..3bb1a3f 100644 --- a/ui/G3PointDisclaimer.ui +++ b/ui/G3PointDisclaimer.ui @@ -6,8 +6,8 @@ 0 0 - 1086 - 392 + 823 + 308 @@ -31,8 +31,8 @@ li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;"> <p align="center" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Calibri,sans-serif'; font-size:12pt; font-weight:700; color:#1f497d;">G3Point: grain segmentation algorithm</span></p> -<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#ffffff;"><span style=" font-family:'Slack-Lato','appleLogo','sans-serif'; font-size:10pt; font-weight:700; color:#1f497d;">Plugin</span><span style=" font-family:'Slack-Lato','appleLogo','sans-serif'; font-size:10pt; font-weight:600; color:#1f497d;"> </span><span style=" font-family:'Slack-Lato','appleLogo','sans-serif'; font-size:10pt; color:#1f497d;">P. Leroy</span></p> -<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#ffffff;"><span style=" font-family:'Slack-Lato','appleLogo','sans-serif'; font-size:10pt; color:#1f497d;">Leroy, P., Guérit, L., Steer, P. &amp; Lague, D. (2025). </span><span style=" font-family:'Slack-Lato','appleLogo','sans-serif'; font-size:10pt; font-style:italic; color:#1f497d;">G3Point plugin for CloudCompare [software]</span></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#ffffff;"><span style=" font-family:'Slack-Lato','appleLogo','sans-serif'; font-size:10pt; font-weight:700; color:#1f497d;">Plugin</span><span style=" font-family:'Slack-Lato','appleLogo','sans-serif'; font-size:10pt; font-weight:600; color:#1f497d;"> </span><span style=" font-family:'Slack-Lato','appleLogo','sans-serif'; font-size:10pt; color:#1f497d;">Leroy, P., Guérit, L., Steer, P. &amp; Lague, D. (2025).</span></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#ffffff;"><span style=" font-family:'Slack-Lato','appleLogo','sans-serif'; font-size:10pt; font-style:italic; color:#1f497d;">G3Point plugin for CloudCompare [software]</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#ffffff;"><span style=" font-family:'Slack-Lato','appleLogo','sans-serif'; font-size:10pt; color:#1f497d;">Univ Rennes, CNRS, Lidar Platform, OSERen, UAR 3343, Rennes France. https://doi.org/10.26169/g3point.</span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#ffffff;"><span style=" font-family:'Slack-Lato','appleLogo','sans-serif'; font-size:6pt; color:#1f497d; background-color:#ffffff;"> </span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#ffffff;"><span style=" font-family:'Slack-Lato','appleLogo','sans-serif'; font-size:10pt; font-weight:700; color:#1f497d; background-color:#ffffff;">Article</span><span style=" font-family:'Slack-Lato','appleLogo','sans-serif'; font-size:10pt; color:#1f497d; background-color:#ffffff;"> Steer, P., Guerit, L., Lague, D., Crave, A., and Gourdon, A.</span></p>