From 30c2b6b7e831eb2be5e63b62ae3673c3edeb27a4 Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Mon, 4 Nov 2019 12:40:28 +0100 Subject: [PATCH] NEW ICP parameter GUI + show algorithm information at the end parameters of the vtkIterativeClosestPointTransform are now accessible + some code cleaning --- .../mesh/meshprocessing/ICPRegistration.cpp | 70 +++++++++++++++---- .../mesh/meshprocessing/ICPRegistration.h | 23 +++--- 2 files changed, 70 insertions(+), 23 deletions(-) diff --git a/sdk/actions/mesh/meshprocessing/ICPRegistration.cpp b/sdk/actions/mesh/meshprocessing/ICPRegistration.cpp index 9630eef5..27801437 100644 --- a/sdk/actions/mesh/meshprocessing/ICPRegistration.cpp +++ b/sdk/actions/mesh/meshprocessing/ICPRegistration.cpp @@ -37,10 +37,11 @@ using namespace camitk; +// -------------------- constructor -------------------- ICPRegistration::ICPRegistration(camitk::ActionExtension* ext) : Action(ext) { this->setName("ICP Registration"); - this->setDescription(QString(tr("Iterative Closest Point algorithm bewteen two mesh.
")) + + this->setDescription(QString(tr("Iterative Closest Point algorithm between two mesh.
")) + QString(tr("At least two mesh components must be selected :")) + QString("")); this->setComponent("MeshComponent"); this->setFamily("Mesh Processing"); - this->addTag(tr("registration")); - distanceMeasureType = RMS; - - Property* numberOfIterationsProperty = new Property(tr("Number of iterations"), 20, tr("The number of iteration of the ICP algorithm."), ""); - addParameter(numberOfIterationsProperty); - - Property* distanceMesureTypeProperty = new Property(tr("Distance mesure type"), RMS, tr("The distance mesure type use by the ICP algorithm."), ""); + this->addTag(tr("Registration")); + this->addTag(tr("CPI")); + + addParameter(new Property(tr("Maximum Number Of Iterations"), 50, tr("The maximum number of iterations of the ICP algorithm."), "")); + + addParameter(new Property(tr("Maximum Number Of Landmarks"), 200, tr("The maximum number of landmarks sampled in your dataset. If your dataset is dense, then you will typically not need all the points to compute the ICP transform. The default is 200."), "")); + + Property* distanceMesureTypeProperty = new Property(tr("Distance Mesure Type"), RMS, tr("The distance mesure type used by the ICP algorithm. Specify the mean distance mode. The RMS mode is the square root of the average of the sum of squares of the closest point distances. The Absolute Value mode is the mean of the sum of absolute values of the closest point distances."), ""); distanceMesureTypeProperty->setEnumTypeName("DistanceMeasureType", this); addParameter(distanceMesureTypeProperty); + + Property* transformTypeProperty = new Property(tr("Transform Type"), Similarity, tr("The landmark transformation type used by the ICP agorithm. Set the number of degrees of freedom to constrain the solution to: Rigidbody (rotation and translation only), Similarity (rotation, translation and isotropic scaling) or Affine (collinearity is preserved, ratios of distances along a line are preserved."), ""); + transformTypeProperty->setEnumTypeName("LandmarkTransformType", this); + addParameter(transformTypeProperty); + + addParameter(new Property(tr("Match Centroid First"), false, tr("Starts the process by translating source centroid to target centroid."), "")); + + addParameter(new Property(tr("Check Mean Distance"), false, tr("Force the algorithm to check the mean distance between two iterations. This is slower but generally more accurate."), "")); + + Property* maxMeanDistanceProperty = new Property(tr("Maximum Mean Distance"), 0.01, tr("The maximum mean distance between two iterations. If the mean distance is lower than this, the convergence stops."), ""); + maxMeanDistanceProperty->setAttribute("decimals", 5); + maxMeanDistanceProperty->setAttribute("minimum", 0); + maxMeanDistanceProperty->setAttribute("singleStep", 0.001); + addParameter(maxMeanDistanceProperty); } +// -------------------- apply -------------------- camitk::Action::ApplyStatus ICPRegistration::apply() { // set waiting cursor and status bar QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); @@ -92,19 +109,32 @@ camitk::Action::ApplyStatus ICPRegistration::apply() { vtkSmartPointer icp = vtkSmartPointer::New(); icp->SetSource(sourceMesh->getPointSet()); icp->SetTarget(targetMesh->getPointSet()); - icp->GetLandmarkTransform()->SetModeToRigidBody(); - icp->SetMaximumNumberOfIterations(property("Number of iterations").toInt()); - switch (property("Distance mesure type").toInt()) { - case RMS : - icp->SetMeanDistanceModeToRMS(); - break; + icp->SetMaximumNumberOfIterations(property("Maximum Number Of Iterations").toInt()); + icp->SetMaximumNumberOfLandmarks(property("Maximum Number Of Landmarks").toInt()); + switch (property("Distance Mesure Type").toInt()) { case ABS : icp->SetMeanDistanceModeToAbsoluteValue(); break; + case RMS : default: icp->SetMeanDistanceModeToRMS(); break; } + switch(property("Transform Type").toInt()) { + case Rigidbody: + icp->GetLandmarkTransform()->SetModeToRigidBody(); + break; + case Affine: + icp->GetLandmarkTransform()->SetModeToAffine(); + break; + case Similarity: + default: + icp->GetLandmarkTransform()->SetModeToSimilarity(); + break; + } + icp->SetStartByMatchingCentroids(property("Match Centroid First").toBool()); + icp->SetCheckMeanDistance(property("Check Mean Distance").toBool()); + icp->SetMaximumMeanDistance(property("Maximum Mean Distance").toDouble()); icp->AddObserver(vtkCommand::ProgressEvent, progressCallback); icp->Modified(); icp->Update(); @@ -121,6 +151,18 @@ camitk::Action::ApplyStatus ICPRegistration::apply() { icpTransformFilter->AddObserver(vtkCommand::ProgressEvent, progressCallback); icpTransformFilter->Update(); + // get the algorithm output information + vtkSmartPointer registrationMatrix = icp->GetMatrix(); + QStringList stringMatrix; + for (int i=0;i<4;i++) { + for (int j=0;j<4;j++) { + stringMatrix << QString::number(icp->GetMatrix()->GetElement(i,j)); + } + } + int numberOfIterations = icp->GetNumberOfIterations(); + double meanDistance = icp->GetMeanDistance(); + CAMITK_TRACE("ICP algorithm information: " + QString::number(numberOfIterations) + " iterations, mean distance = " + QString::number(meanDistance) + ", transform: [" + stringMatrix.join(", ") + "]") + // create a new MeshComponent for the result new MeshComponent(icpTransformFilter->GetOutput(), sourceMesh->getName() + "_registered_mesh"); diff --git a/sdk/actions/mesh/meshprocessing/ICPRegistration.h b/sdk/actions/mesh/meshprocessing/ICPRegistration.h index 5690c583..31380b38 100644 --- a/sdk/actions/mesh/meshprocessing/ICPRegistration.h +++ b/sdk/actions/mesh/meshprocessing/ICPRegistration.h @@ -43,12 +43,21 @@ class ICPRegistration : public camitk::Action { public: + /// \enum DistanceMeasureType specify the mean distance mode enum DistanceMeasureType { - RMS, - ABS - }; + RMS, ///< The RMS mode is the square root of the average of the sum of squares of the closest point distances + ABS ///< The Absolute Value mode is the mean of the sum of absolute values of the closest point distances. + }; Q_ENUMS(DistanceMeasureType) - + + /// \enum LandmarkTransformType Set the number of degrees of freedom to constrain the solution to. + enum LandmarkTransformType { + Rigidbody, ///< rotation and translation only. + Similarity, ///< rotation, translation and isotropic scaling. + Affine ///< collinearity is preserved, ratios of distances along a line are preserved + }; + Q_ENUMS(LandmarkTransformType) + public: /// the constructor @@ -57,18 +66,14 @@ public: /// the destructor virtual ~ICPRegistration() = default; - public slots : /// method applied when the action is called virtual ApplyStatus apply(); -protected : - - DistanceMeasureType distanceMeasureType; - }; Q_DECLARE_METATYPE(ICPRegistration::DistanceMeasureType) +Q_DECLARE_METATYPE(ICPRegistration::LandmarkTransformType) #endif // ICP_REGISTRATION_H -- GitLab