diff --git a/Modules/IGT/IGTFilters/mitkNavigationDataLandmarkTransformFilter.cpp b/Modules/IGT/IGTFilters/mitkNavigationDataLandmarkTransformFilter.cpp index b7a8d5b6f1..b5be218bce 100644 --- a/Modules/IGT/IGTFilters/mitkNavigationDataLandmarkTransformFilter.cpp +++ b/Modules/IGT/IGTFilters/mitkNavigationDataLandmarkTransformFilter.cpp @@ -1,460 +1,462 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkNavigationDataLandmarkTransformFilter.h" #include "itkIndent.h" #include "itkEuler3DTransform.h" #include "itkVersorRigid3DTransform.h" #include "itkEuclideanDistancePointMetric.h" #include "itkLevenbergMarquardtOptimizer.h" #include "itkPointSet.h" #include "itkPointSetToPointSetRegistrationMethod.h" #include mitk::NavigationDataLandmarkTransformFilter::NavigationDataLandmarkTransformFilter() : mitk::NavigationDataToNavigationDataFilter(), m_ErrorMean(-1.0), m_ErrorStdDev(-1.0), m_ErrorRMS(-1.0), m_ErrorMin(-1.0), m_ErrorMax(-1.0), m_ErrorAbsMax(-1.0), m_SourcePoints(), m_TargetPoints(), m_LandmarkTransformInitializer(NULL), m_LandmarkTransform(NULL), m_QuatLandmarkTransform(NULL), m_QuatTransform(NULL), m_Errors(), m_UseICPInitialization(false) { m_LandmarkTransform = LandmarkTransformType::New(); m_LandmarkTransformInitializer = TransformInitializerType::New(); m_LandmarkTransformInitializer->SetTransform(m_LandmarkTransform); //transform to rotate orientation m_QuatLandmarkTransform = QuaternionTransformType::New(); m_QuatTransform = QuaternionTransformType::New(); } mitk::NavigationDataLandmarkTransformFilter::~NavigationDataLandmarkTransformFilter() { m_LandmarkTransform = NULL; m_LandmarkTransformInitializer = NULL; m_QuatLandmarkTransform = NULL; m_QuatTransform = NULL; } void mitk::NavigationDataLandmarkTransformFilter::InitializeLandmarkTransform(LandmarkPointContainer& sources, const LandmarkPointContainer& targets) { if (m_UseICPInitialization == true) { if (this->FindCorrespondentLandmarks(sources, targets) == false) // determine landmark correspondences with iterative closest point optimization, sort sort landmarks accordingly { itkExceptionMacro("Landmark correspondence finding failed."); } } if(m_SourcePoints.size() != m_TargetPoints.size())// check whether target and source points size are equal itk registration won't work otherways - return; + { + itkExceptionMacro("Cannot initialize Filter, number of input datas does not equal number of output datas."); + } this->UpdateLandmarkTransform(sources, targets); // if size of source and target points is equal } void mitk::NavigationDataLandmarkTransformFilter::SetSourceLandmarks(mitk::PointSet::Pointer mitkSourcePointSet) { m_SourcePoints.clear(); mitk::PointSet::PointType mitkSourcePoint; TransformInitializerType::LandmarkPointType lPoint; for (mitk::PointSet::PointsContainer::ConstIterator it = mitkSourcePointSet->GetPointSet()->GetPoints()->Begin(); it != mitkSourcePointSet->GetPointSet()->GetPoints()->End(); ++it) { mitk::FillVector3D(lPoint, it->Value().GetElement(0), it->Value().GetElement(1), it->Value().GetElement(2)); m_SourcePoints.push_back(lPoint); } if (m_SourcePoints.size() < 3) { itkExceptionMacro("SourcePointSet must contain at least 3 points"); } if (this->IsInitialized()) this->InitializeLandmarkTransform(m_SourcePoints, m_TargetPoints); } void mitk::NavigationDataLandmarkTransformFilter::SetTargetLandmarks(mitk::PointSet::Pointer mitkTargetPointSet) { m_TargetPoints.clear(); TransformInitializerType::LandmarkPointType lPoint; for (mitk::PointSet::PointsContainer::ConstIterator it = mitkTargetPointSet->GetPointSet()->GetPoints()->Begin(); it != mitkTargetPointSet->GetPointSet()->GetPoints()->End(); ++it) { mitk::FillVector3D(lPoint, it->Value().GetElement(0), it->Value().GetElement(1), it->Value().GetElement(2)); m_TargetPoints.push_back(lPoint); } if (m_TargetPoints.size() < 3) { itkExceptionMacro("TargetPointSet must contain at least 3 points"); } if (this->IsInitialized()) this->InitializeLandmarkTransform(m_SourcePoints, m_TargetPoints); } mitk::ScalarType mitk::NavigationDataLandmarkTransformFilter::GetFRE() const { return m_ErrorMean; } mitk::ScalarType mitk::NavigationDataLandmarkTransformFilter::GetFREStdDev() const { return m_ErrorStdDev; } mitk::ScalarType mitk::NavigationDataLandmarkTransformFilter::GetRMSError() const { return m_ErrorRMS; } mitk::ScalarType mitk::NavigationDataLandmarkTransformFilter::GetMinError() const { return m_ErrorMin; } mitk::ScalarType mitk::NavigationDataLandmarkTransformFilter::GetMaxError() const { return m_ErrorMax; } mitk::ScalarType mitk::NavigationDataLandmarkTransformFilter::GetAbsMaxError() const { return m_ErrorAbsMax; } void mitk::NavigationDataLandmarkTransformFilter::AccumulateStatistics(std::vector& vector) { //mean, min, max m_ErrorMean = 0.0; m_ErrorMin = itk::NumericTraits::max(); m_ErrorMax = itk::NumericTraits::min(); m_ErrorAbsMax = 0.0; m_ErrorRMS = 0.0; for (std::vector::size_type i = 0; i < vector.size(); i++) { m_ErrorMean += vector[i]; // mean m_ErrorRMS += pow(vector[i],2); // RMS if(vector[i] < m_ErrorMin) // min m_ErrorMin = vector[i]; if(vector[i] > m_ErrorMax) // max m_ErrorMax = vector[i]; if(fabs(vector[i]) > fabs(m_ErrorAbsMax)) // abs_max m_ErrorAbsMax = vector[i]; } m_ErrorMean /= vector.size(); m_ErrorRMS = sqrt(m_ErrorRMS/vector.size()); //standard deviation m_ErrorStdDev = 0.0; for (std::vector::size_type i = 0; i < vector.size(); i++) m_ErrorStdDev += pow(vector[i] - m_ErrorMean, 2); if(vector.size() > 1) m_ErrorStdDev = sqrt(m_ErrorStdDev / (vector.size() - 1.0)); this->Modified(); } void mitk::NavigationDataLandmarkTransformFilter::GenerateData() { this->CreateOutputsForAllInputs(); // make sure that we have the same number of outputs as inputs TransformInitializerType::LandmarkPointType lPointIn, lPointOut; /* update outputs with tracking data from tools */ for (unsigned int i = 0; i < this->GetNumberOfOutputs() ; ++i) { mitk::NavigationData* output = this->GetOutput(i); assert(output); const mitk::NavigationData* input = this->GetInput(i); assert(input); if (input->IsDataValid() == false) { output->SetDataValid(false); continue; } output->Graft(input); // First, copy all information from input to output if (this->IsInitialized() == false) // as long as there is no valid transformation matrix, only graft the outputs continue; mitk::NavigationData::PositionType tempCoordinate; tempCoordinate = input->GetPosition(); lPointIn[0] = tempCoordinate[0]; // convert navigation data position to transform point lPointIn[1] = tempCoordinate[1]; lPointIn[2] = tempCoordinate[2]; /* transform position */ lPointOut = m_LandmarkTransform->TransformPoint(lPointIn); // transform position tempCoordinate[0] = lPointOut[0]; // convert back into navigation data position tempCoordinate[1] = lPointOut[1]; tempCoordinate[2] = lPointOut[2]; output->SetPosition(tempCoordinate); // update output navigation data with new position /* transform orientation */ NavigationData::OrientationType quatIn = input->GetOrientation(); vnl_quaternion const vnlQuatIn(quatIn.x(), quatIn.y(), quatIn.z(), quatIn.r()); // convert orientation into vnl quaternion m_QuatTransform->SetRotation(vnlQuatIn); // convert orientation into transform m_QuatLandmarkTransform->SetMatrix(m_LandmarkTransform->GetMatrix()); m_QuatLandmarkTransform->Compose(m_QuatTransform, true); // compose navigation data transform and landmark transform vnl_quaternion vnlQuatOut = m_QuatLandmarkTransform->GetRotation(); // convert composed transform back into a quaternion NavigationData::OrientationType quatOut(vnlQuatOut[0], vnlQuatOut[1], vnlQuatOut[2], vnlQuatOut[3]); // convert back into navigation data orientation output->SetOrientation(quatOut); // update output navigation data with new orientation output->SetDataValid(true); // operation was successful, therefore data of output is valid. } } bool mitk::NavigationDataLandmarkTransformFilter::IsInitialized() const { return (m_SourcePoints.size() >= 3) && (m_TargetPoints.size() >= 3); } void mitk::NavigationDataLandmarkTransformFilter::PrintSelf( std::ostream& os, itk::Indent indent ) const { Superclass::PrintSelf(os, indent); os << indent << this->GetNameOfClass() << ":\n"; os << indent << m_SourcePoints.size() << " SourcePoints exist: \n"; itk::Indent nextIndent = indent.GetNextIndent(); unsigned int i = 0; for (LandmarkPointContainer::const_iterator it = m_SourcePoints.begin(); it != m_SourcePoints.end(); ++it) { os << nextIndent << "Point " << i++ << ": ["; os << it->GetElement(0); for (unsigned int i = 1; i < TransformInitializerType::LandmarkPointType::GetPointDimension(); ++i) { os << ", " << it->GetElement(i); } os << "]\n"; } os << indent << m_TargetPoints.size() << " TargetPoints exist: \n"; i = 0; for (LandmarkPointContainer::const_iterator it = m_TargetPoints.begin(); it != m_TargetPoints.end(); ++it) { os << nextIndent << "Point " << i++ << ": ["; os << it->GetElement(0); for (unsigned int i = 1; i < TransformInitializerType::LandmarkPointType::GetPointDimension(); ++i) { os << ", " << it->GetElement(i); } os << "]\n"; } os << indent << "Landmarktransform initialized: " << this->IsInitialized() << "\n"; if (this->IsInitialized() == true) m_LandmarkTransform->Print(os, nextIndent); os << indent << "Registration error statistics:\n"; os << nextIndent << "FRE: " << this->GetFRE() << "\n"; os << nextIndent << "FRE std.dev.: " << this->GetFREStdDev() << "\n"; os << nextIndent << "FRE RMS: " << this->GetRMSError() << "\n"; os << nextIndent << "Minimum registration error: " << this->GetMinError() << "\n"; os << nextIndent << "Maximum registration error: " << this->GetMaxError() << "\n"; os << nextIndent << "Absolute Maximum registration error: " << this->GetAbsMaxError() << "\n"; } const mitk::NavigationDataLandmarkTransformFilter::ErrorVector& mitk::NavigationDataLandmarkTransformFilter::GetErrorVector() const { return m_Errors; } bool mitk::NavigationDataLandmarkTransformFilter::FindCorrespondentLandmarks(LandmarkPointContainer& sources, const LandmarkPointContainer& targets) const { if (sources.size() < 6 || targets.size() < 6) return false; //throw std::invalid_argument("ICP correspondence finding needs at least 6 landmarks"); /* lots of type definitions */ typedef itk::PointSet PointSetType; //typedef itk::BoundingBox BoundingBoxType; typedef itk::EuclideanDistancePointMetric< PointSetType, PointSetType> MetricType; //typedef MetricType::TransformType TransformBaseType; //typedef MetricType::TransformType::ParametersType ParametersType; //typedef TransformBaseType::JacobianType JacobianType; //typedef itk::Euler3DTransform< double > TransformType; typedef itk::VersorRigid3DTransform< double > TransformType; typedef TransformType ParametersType; typedef itk::PointSetToPointSetRegistrationMethod< PointSetType, PointSetType > RegistrationType; /* copy landmarks to itk pointsets for registration */ PointSetType::Pointer sourcePointSet = PointSetType::New(); unsigned int i = 0; for (LandmarkPointContainer::const_iterator it = sources.begin(); it != sources.end(); ++it) { PointSetType::PointType doublePoint; mitk::itk2vtk(*it, doublePoint); // copy mitk::ScalarType point into double point as workaround to ITK 3.10 bug sourcePointSet->SetPoint(i++, doublePoint /**it*/); } i = 0; PointSetType::Pointer targetPointSet = PointSetType::New(); for (LandmarkPointContainer::const_iterator it = targets.begin(); it != targets.end(); ++it) { PointSetType::PointType doublePoint; mitk::itk2vtk(*it, doublePoint); // copy mitk::ScalarType point into double point as workaround to ITK 3.10 bug targetPointSet->SetPoint(i++, doublePoint /**it*/); } /* get centroid and extends of our pointsets */ //BoundingBoxType::Pointer sourceBoundingBox = BoundingBoxType::New(); //sourceBoundingBox->SetPoints(sourcePointSet->GetPoints()); //sourceBoundingBox->ComputeBoundingBox(); //BoundingBoxType::Pointer targetBoundingBox = BoundingBoxType::New(); //targetBoundingBox->SetPoints(targetPointSet->GetPoints()); //targetBoundingBox->ComputeBoundingBox(); TransformType::Pointer transform = TransformType::New(); transform->SetIdentity(); //transform->SetTranslation(targetBoundingBox->GetCenter() - sourceBoundingBox->GetCenter()); itk::LevenbergMarquardtOptimizer::Pointer optimizer = itk::LevenbergMarquardtOptimizer::New(); optimizer->SetUseCostFunctionGradient(false); RegistrationType::Pointer registration = RegistrationType::New(); // Scale the translation components of the Transform in the Optimizer itk::LevenbergMarquardtOptimizer::ScalesType scales(transform->GetNumberOfParameters()); const double translationScale = 5000; //sqrtf(targetBoundingBox->GetDiagonalLength2()) * 1000; // dynamic range of translations const double rotationScale = 1.0; // dynamic range of rotations scales[0] = 1.0 / rotationScale; scales[1] = 1.0 / rotationScale; scales[2] = 1.0 / rotationScale; scales[3] = 1.0 / translationScale; scales[4] = 1.0 / translationScale; scales[5] = 1.0 / translationScale; //scales.Fill(0.01); unsigned long numberOfIterations = 80000; double gradientTolerance = 1e-10; // convergence criterion double valueTolerance = 1e-10; // convergence criterion double epsilonFunction = 1e-10; // convergence criterion optimizer->SetScales( scales ); optimizer->SetNumberOfIterations( numberOfIterations ); optimizer->SetValueTolerance( valueTolerance ); optimizer->SetGradientTolerance( gradientTolerance ); optimizer->SetEpsilonFunction( epsilonFunction ); registration->SetInitialTransformParameters( transform->GetParameters() ); //------------------------------------------------------ // Connect all the components required for Registration //------------------------------------------------------ MetricType::Pointer metric = MetricType::New(); registration->SetMetric( metric ); registration->SetOptimizer( optimizer ); registration->SetTransform( transform ); registration->SetFixedPointSet( targetPointSet ); registration->SetMovingPointSet( sourcePointSet ); try { //registration->StartRegistration(); registration->Update(); } catch( itk::ExceptionObject & e ) { MITK_INFO << "Exception caught during ICP optimization: " << e; return false; //throw e; } MITK_INFO << "ICP successful: Solution = " << transform->GetParameters() << std::endl; MITK_INFO << "Metric value: " << metric->GetValue(transform->GetParameters()); /* find point correspondences */ //mitk::PointLocator::Pointer pointLocator = mitk::PointLocator::New(); // <<- use mitk::PointLocator instead of searching manually? //pointLocator->SetPoints() for (LandmarkPointContainer::const_iterator sourcesIt = sources.begin(); sourcesIt != sources.end(); ++sourcesIt) { } //MetricType::MeasureType closestDistances = metric->GetValue(transform->GetParameters()); //unsigned int index = 0; LandmarkPointContainer sortedSources; for (LandmarkPointContainer::const_iterator targetsIt = targets.begin(); targetsIt != targets.end(); ++targetsIt) { double minDistance = itk::NumericTraits::max(); LandmarkPointContainer::iterator minDistanceIterator = sources.end(); for (LandmarkPointContainer::iterator sourcesIt = sources.begin(); sourcesIt != sources.end(); ++sourcesIt) { TransformInitializerType::LandmarkPointType transformedSource = transform->TransformPoint(*sourcesIt); double dist = targetsIt->EuclideanDistanceTo(transformedSource); MITK_INFO << "target: " << *targetsIt << ", source: " << *sourcesIt << ", transformed source: " << transformedSource << ", dist: " << dist; if (dist < minDistance ) { minDistanceIterator = sourcesIt; minDistance = dist; } } if (minDistanceIterator == sources.end()) return false; MITK_INFO << "minimum distance point is: " << *minDistanceIterator << " (dist: " << targetsIt->EuclideanDistanceTo(transform->TransformPoint(*minDistanceIterator)) << ", minDist: " << minDistance << ")"; sortedSources.push_back(*minDistanceIterator); // this point is assigned sources.erase(minDistanceIterator); // erase it from sources to avoid duplicate assigns } //for (LandmarkPointContainer::const_iterator sortedSourcesIt = sortedSources.begin(); targetsIt != sortedSources.end(); ++targetsIt) sources = sortedSources; return true; } void mitk::NavigationDataLandmarkTransformFilter::UpdateLandmarkTransform(const LandmarkPointContainer &sources, const LandmarkPointContainer &targets) { try { /* calculate transform from landmarks */ m_LandmarkTransformInitializer->SetMovingLandmarks(targets); m_LandmarkTransformInitializer->SetFixedLandmarks(sources); // itk registration always maps from fixed object space to moving object space m_LandmarkTransform->SetIdentity(); m_LandmarkTransformInitializer->InitializeTransform(); /* Calculate error statistics for the transform */ TransformInitializerType::LandmarkPointType curData; m_Errors.clear(); for (LandmarkPointContainer::size_type index = 0; index < sources.size(); index++) { curData = m_LandmarkTransform->TransformPoint(sources.at(index)); m_Errors.push_back(curData.EuclideanDistanceTo(targets.at(index))); } this->AccumulateStatistics(m_Errors); this->Modified(); } catch (std::exception& e) { m_Errors.clear(); m_LandmarkTransform->SetIdentity(); itkExceptionMacro("Initializing landmark-transform failed\n. " << e.what()); } } diff --git a/Modules/IGT/IGTFilters/mitkNavigationDataLandmarkTransformFilter.h b/Modules/IGT/IGTFilters/mitkNavigationDataLandmarkTransformFilter.h index ec0c7014a3..a4f3860cc6 100644 --- a/Modules/IGT/IGTFilters/mitkNavigationDataLandmarkTransformFilter.h +++ b/Modules/IGT/IGTFilters/mitkNavigationDataLandmarkTransformFilter.h @@ -1,187 +1,187 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKNavigationDataLandmarkTransformFilter_H_HEADER_INCLUDED_ #define MITKNavigationDataLandmarkTransformFilter_H_HEADER_INCLUDED_ #include #include #include #include #include namespace mitk { /**Documentation * \brief NavigationDataLandmarkTransformFilter applies a itk-landmark-transformation * defined by source and target pointsets. * * Before executing the filter SetSourceLandmarks and SetTargetLandmarks must be called. Before both source * and target landmarks are set, the filter performs an identity transform. * If source or target points are changed after calling SetXXXPoints, the corresponding SetXXXPoints * method has to be called again to apply the changes. * If UseICPInitialization is false (standard value, or set with SetUseICPInitialization(false) or UseICPInitializationOff()) - * then source landmarks and target landmarks with the same ID must correspondent to each other. + * then source landmarks and target landmarks with the same ID must correspond to each other. * (--> source landmark with ID x will be mapped to target landmark with ID x). * If you do not know the correspondences, call SetUseICPInitialization(true) or UseICPInitializationOn() * to let the filter guess the correspondences during initialization with an iterative closest point search. * This is only possible, if at least 6 source and target landmarks are available. * * \ingroup IGT */ class MitkIGT_EXPORT NavigationDataLandmarkTransformFilter : public NavigationDataToNavigationDataFilter { public: mitkClassMacro(NavigationDataLandmarkTransformFilter, NavigationDataToNavigationDataFilter); itkNewMacro(Self); typedef std::vector ErrorVector; typedef itk::VersorRigid3DTransform< double > LandmarkTransformType; /** *\brief Set points used as source points for landmark transform. * */ virtual void SetSourceLandmarks(mitk::PointSet::Pointer sourcePointSet); /** *\brief Set points used as target points for landmark transform * */ virtual void SetTargetLandmarks(mitk::PointSet::Pointer targetPointSet); virtual bool IsInitialized() const; /** *\brief Returns the Fiducial Registration Error * */ mitk::ScalarType GetFRE() const; /** *\brief Returns the standard deviation of the Fiducial Registration Error * */ mitk::ScalarType GetFREStdDev() const; /** *\brief Returns the Root Mean Square of the registration error * */ mitk::ScalarType GetRMSError() const; /** *\brief Returns the minimum registration error / best fitting landmark distance * */ mitk::ScalarType GetMinError() const; /** *\brief Returns the maximum registration error / worst fitting landmark distance * */ mitk::ScalarType GetMaxError() const; /** *\brief Returns the absolute maximum registration error * */ mitk::ScalarType GetAbsMaxError() const; /** *\brief Returns a vector with the euclidean distance of each transformed source point to its respective target point * */ const ErrorVector& GetErrorVector() const; itkSetMacro(UseICPInitialization, bool); ///< If set to true, source and target point correspondences are established with iterative closest point optimization itkGetMacro(UseICPInitialization, bool); ///< If set to true, source and target point correspondences are established with iterative closest point optimization itkBooleanMacro(UseICPInitialization); ///< If set to true, source and target point correspondences are established with iterative closest point optimization itkGetConstObjectMacro(LandmarkTransform, LandmarkTransformType); ///< returns the current landmark transform protected: typedef itk::Image< signed short, 3> ImageType; // only because itk::LandmarkBasedTransformInitializer must be templated over two imagetypes typedef itk::LandmarkBasedTransformInitializer< LandmarkTransformType, ImageType, ImageType > TransformInitializerType; typedef TransformInitializerType::LandmarkPointContainer LandmarkPointContainer; typedef itk::QuaternionRigidTransform QuaternionTransformType; /** * \brief Constructor **/ NavigationDataLandmarkTransformFilter(); virtual ~NavigationDataLandmarkTransformFilter(); /** * \brief transforms input NDs according to the calculated LandmarkTransform * */ virtual void GenerateData(); /**Documentation * \brief perform an iterative closest point matching to find corresponding landmarks that will be used for landmark transform calculation * * Perform ICP optimization to match source landmarks to target landmarks. Landmark containers must contain * at least 6 landmarks for the optimization. * after ICP, landmark correspondences are established and the source landmarks are sorted, so that * corresponding landmarks have the same indices. * * \param[in] sources Source landmarks that will be mapped to the target landmarks * \param[in] targets Target landmarks onto which the source landmarks will be mapped * \param[out] sources The sources container will be sorted, so that landmarks have the same index as their corresponding target landmarks * \return true if ICP was successful and sources are sorted , false otherwise */ bool FindCorrespondentLandmarks(LandmarkPointContainer& sources, const LandmarkPointContainer& targets) const; /** * \brief initializes the transform using source and target PointSets * * if UseICPInitialization is true, FindCorrespondentLandmarks() will be used to sort the source landmarks in order to * establish corresponding landmark pairs before the landmark transform is build */ void InitializeLandmarkTransform(LandmarkPointContainer& sources, const LandmarkPointContainer& targets); /** * \brief calculates the transform using source and target PointSets */ void UpdateLandmarkTransform(const LandmarkPointContainer &sources, const LandmarkPointContainer &targets); ///< void AccumulateStatistics(ErrorVector& vector); ///< calculate error metrics for the transforms. void PrintSelf( std::ostream& os, itk::Indent indent ) const; ///< print object info to ostream mitk::ScalarType m_ErrorMean; ///< Fiducial Registration Error mitk::ScalarType m_ErrorStdDev; ///< standard deviation of the Fiducial Registration Error mitk::ScalarType m_ErrorRMS; ///< Root Mean Square of the registration error mitk::ScalarType m_ErrorMin; ///< minimum registration error / best fitting landmark distance mitk::ScalarType m_ErrorMax; ///< maximum registration error / worst fitting landmark distance mitk::ScalarType m_ErrorAbsMax; ///< the absolute maximum registration error LandmarkPointContainer m_SourcePoints; ///< positions of the source points LandmarkPointContainer m_TargetPoints; ///< positions of the target points TransformInitializerType::Pointer m_LandmarkTransformInitializer; ///< landmark based transform initializer LandmarkTransformType::Pointer m_LandmarkTransform; ///< transform calculated from source and target points QuaternionTransformType::Pointer m_QuatLandmarkTransform; ///< transform needed to rotate orientation QuaternionTransformType::Pointer m_QuatTransform; ///< further transform needed to rotate orientation ErrorVector m_Errors; ///< stores the euclidean distance of each transformed source landmark and its respective target landmark bool m_UseICPInitialization; ///< find source <--> target point correspondences with iterative closest point optimization }; } // namespace mitk #endif /* MITKNavigationDataLandmarkTransformFilter_H_HEADER_INCLUDED_ */