00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "mitkNavigationDataLandmarkTransformFilter.h"
00019 #include "itkIndent.h"
00020 #include "itkEuler3DTransform.h"
00021 #include "itkVersorRigid3DTransform.h"
00022 #include "itkEuclideanDistancePointMetric.h"
00023 #include "itkLevenbergMarquardtOptimizer.h"
00024 #include "itkPointSet.h"
00025 #include "itkPointSetToPointSetRegistrationMethod.h"
00026 #include <algorithm>
00027
00028
00029 mitk::NavigationDataLandmarkTransformFilter::NavigationDataLandmarkTransformFilter() : mitk::NavigationDataToNavigationDataFilter(),
00030 m_ErrorMean(-1.0), m_ErrorStdDev(-1.0), m_ErrorRMS(-1.0), m_ErrorMin(-1.0), m_ErrorMax(-1.0), m_ErrorAbsMax(-1.0),
00031 m_SourcePoints(), m_TargetPoints(), m_LandmarkTransformInitializer(NULL), m_LandmarkTransform(NULL),
00032 m_QuatLandmarkTransform(NULL), m_QuatTransform(NULL), m_Errors(), m_UseICPInitialization(false)
00033 {
00034 m_LandmarkTransform = LandmarkTransformType::New();
00035
00036 m_LandmarkTransformInitializer = TransformInitializerType::New();
00037 m_LandmarkTransformInitializer->SetTransform(m_LandmarkTransform);
00038
00039
00040 m_QuatLandmarkTransform = QuaternionTransformType::New();
00041 m_QuatTransform = QuaternionTransformType::New();
00042 }
00043
00044
00045 mitk::NavigationDataLandmarkTransformFilter::~NavigationDataLandmarkTransformFilter()
00046 {
00047 m_LandmarkTransform = NULL;
00048 m_LandmarkTransformInitializer = NULL;
00049 m_QuatLandmarkTransform = NULL;
00050 m_QuatTransform = NULL;
00051 }
00052
00053
00054 void mitk::NavigationDataLandmarkTransformFilter::InitializeLandmarkTransform(LandmarkPointContainer& sources, const LandmarkPointContainer& targets)
00055 {
00056 if (m_UseICPInitialization == true)
00057 if (this->FindCorrespondentLandmarks(sources, targets) == false)
00058 {
00059 itkExceptionMacro("Landmark correspondence finding failed.");
00060 }
00061 this->UpdateLandmarkTransform(sources, targets);
00062 }
00063
00064
00065 void mitk::NavigationDataLandmarkTransformFilter::SetSourceLandmarks(mitk::PointSet::Pointer mitkSourcePointSet)
00066 {
00067 m_SourcePoints.clear();
00068 mitk::PointSet::PointType mitkSourcePoint;
00069 TransformInitializerType::LandmarkPointType lPoint;
00070
00071 for (mitk::PointSet::PointsContainer::ConstIterator it = mitkSourcePointSet->GetPointSet()->GetPoints()->Begin();
00072 it != mitkSourcePointSet->GetPointSet()->GetPoints()->End(); ++it)
00073 {
00074 mitk::FillVector3D(lPoint, it->Value().GetElement(0), it->Value().GetElement(1), it->Value().GetElement(2));
00075 m_SourcePoints.push_back(lPoint);
00076 }
00077
00078 if (m_SourcePoints.size() < 3)
00079 {
00080 itkExceptionMacro("SourcePointSet must contain at least 3 points");
00081 }
00082
00083 if (this->IsInitialized())
00084 this->InitializeLandmarkTransform(m_SourcePoints, m_TargetPoints);
00085 }
00086
00087
00088 void mitk::NavigationDataLandmarkTransformFilter::SetTargetLandmarks(mitk::PointSet::Pointer mitkTargetPointSet)
00089 {
00090 m_TargetPoints.clear();
00091 TransformInitializerType::LandmarkPointType lPoint;
00092 for (mitk::PointSet::PointsContainer::ConstIterator it = mitkTargetPointSet->GetPointSet()->GetPoints()->Begin();
00093 it != mitkTargetPointSet->GetPointSet()->GetPoints()->End(); ++it)
00094 {
00095 mitk::FillVector3D(lPoint, it->Value().GetElement(0), it->Value().GetElement(1), it->Value().GetElement(2));
00096 m_TargetPoints.push_back(lPoint);
00097 }
00098
00099 if (m_TargetPoints.size() < 3)
00100 {
00101 itkExceptionMacro("TargetPointSet must contain at least 3 points");
00102 }
00103
00104 if (this->IsInitialized())
00105 this->InitializeLandmarkTransform(m_SourcePoints, m_TargetPoints);
00106 }
00107
00108
00109 mitk::ScalarType mitk::NavigationDataLandmarkTransformFilter::GetFRE() const
00110 {
00111 return m_ErrorMean;
00112 }
00113
00114
00115 mitk::ScalarType mitk::NavigationDataLandmarkTransformFilter::GetFREStdDev() const
00116 {
00117 return m_ErrorStdDev;
00118 }
00119
00120
00121 mitk::ScalarType mitk::NavigationDataLandmarkTransformFilter::GetRMSError() const
00122 {
00123 return m_ErrorRMS;
00124 }
00125
00126
00127 mitk::ScalarType mitk::NavigationDataLandmarkTransformFilter::GetMinError() const
00128 {
00129 return m_ErrorMin;
00130 }
00131
00132
00133 mitk::ScalarType mitk::NavigationDataLandmarkTransformFilter::GetMaxError() const
00134 {
00135 return m_ErrorMax;
00136 }
00137
00138
00139 mitk::ScalarType mitk::NavigationDataLandmarkTransformFilter::GetAbsMaxError() const
00140 {
00141 return m_ErrorAbsMax;
00142 }
00143
00144
00145 void mitk::NavigationDataLandmarkTransformFilter::AccumulateStatistics(std::vector<mitk::ScalarType>& vector)
00146 {
00147
00148 m_ErrorMean = 0.0;
00149 m_ErrorMin = itk::NumericTraits<mitk::ScalarType>::max();
00150 m_ErrorMax = itk::NumericTraits<mitk::ScalarType>::min();
00151 m_ErrorAbsMax = 0.0;
00152 m_ErrorRMS = 0.0;
00153 for (std::vector<mitk::ScalarType>::size_type i = 0; i < vector.size(); i++)
00154 {
00155 m_ErrorMean += vector[i];
00156 m_ErrorRMS += pow(vector[i],2);
00157 if(vector[i] < m_ErrorMin)
00158 m_ErrorMin = vector[i];
00159 if(vector[i] > m_ErrorMax)
00160 m_ErrorMax = vector[i];
00161 if(fabs(vector[i]) > fabs(m_ErrorAbsMax))
00162 m_ErrorAbsMax = vector[i];
00163 }
00164 m_ErrorMean /= vector.size();
00165 m_ErrorRMS = sqrt(m_ErrorRMS/vector.size());
00166
00167
00168 m_ErrorStdDev = 0.0;
00169 for (std::vector<mitk::ScalarType>::size_type i = 0; i < vector.size(); i++)
00170 m_ErrorStdDev += pow(vector[i] - m_ErrorMean, 2);
00171
00172 if(vector.size() > 1)
00173 m_ErrorStdDev = sqrt(m_ErrorStdDev / (vector.size() - 1.0));
00174 this->Modified();
00175 }
00176
00177
00178 void mitk::NavigationDataLandmarkTransformFilter::GenerateData()
00179 {
00180 this->CreateOutputsForAllInputs();
00181
00182 TransformInitializerType::LandmarkPointType lPointIn, lPointOut;
00183
00184
00185 for (unsigned int i = 0; i < this->GetNumberOfOutputs() ; ++i)
00186 {
00187 mitk::NavigationData* output = this->GetOutput(i);
00188 assert(output);
00189 const mitk::NavigationData* input = this->GetInput(i);
00190 assert(input);
00191
00192 if (input->IsDataValid() == false)
00193 {
00194 output->SetDataValid(false);
00195 continue;
00196 }
00197 output->Graft(input);
00198
00199 if (this->IsInitialized() == false)
00200 continue;
00201
00202 mitk::NavigationData::PositionType tempCoordinate;
00203 tempCoordinate = input->GetPosition();
00204 lPointIn[0] = tempCoordinate[0];
00205 lPointIn[1] = tempCoordinate[1];
00206 lPointIn[2] = tempCoordinate[2];
00207
00208
00209 lPointOut = m_LandmarkTransform->TransformPoint(lPointIn);
00210 tempCoordinate[0] = lPointOut[0];
00211 tempCoordinate[1] = lPointOut[1];
00212 tempCoordinate[2] = lPointOut[2];
00213 output->SetPosition(tempCoordinate);
00214
00215
00216 NavigationData::OrientationType quatIn = input->GetOrientation();
00217 vnl_quaternion<double> const vnlQuatIn(quatIn.x(), quatIn.y(), quatIn.z(), quatIn.r());
00218 m_QuatTransform->SetRotation(vnlQuatIn);
00219
00220 m_QuatLandmarkTransform->SetMatrix(m_LandmarkTransform->GetRotationMatrix());
00221 m_QuatLandmarkTransform->Compose(m_QuatTransform, true);
00222
00223 vnl_quaternion<double> vnlQuatOut = m_QuatLandmarkTransform->GetRotation();
00224 NavigationData::OrientationType quatOut(vnlQuatOut[0], vnlQuatOut[1], vnlQuatOut[2], vnlQuatOut[3]);
00225 output->SetOrientation(quatOut);
00226 output->SetDataValid(true);
00227 }
00228 }
00229
00230
00231 bool mitk::NavigationDataLandmarkTransformFilter::IsInitialized() const
00232 {
00233 return (m_SourcePoints.size() >= 3) && (m_TargetPoints.size() >= 3);
00234 }
00235
00236
00237 void mitk::NavigationDataLandmarkTransformFilter::PrintSelf( std::ostream& os, itk::Indent indent ) const
00238 {
00239 Superclass::PrintSelf(os, indent);
00240
00241 os << indent << this->GetNameOfClass() << ":\n";
00242 os << indent << m_SourcePoints.size() << " SourcePoints exist: \n";
00243 itk::Indent nextIndent = indent.GetNextIndent();
00244 unsigned int i = 0;
00245 for (LandmarkPointContainer::const_iterator it = m_SourcePoints.begin(); it != m_SourcePoints.end(); ++it)
00246 {
00247 os << nextIndent << "Point " << i++ << ": [";
00248 os << it->GetElement(0);
00249 for (unsigned int i = 1; i < TransformInitializerType::LandmarkPointType::GetPointDimension(); ++i)
00250 {
00251 os << ", " << it->GetElement(i);
00252 }
00253 os << "]\n";
00254 }
00255
00256 os << indent << m_TargetPoints.size() << " TargetPoints exist: \n";
00257 i = 0;
00258 for (LandmarkPointContainer::const_iterator it = m_TargetPoints.begin(); it != m_TargetPoints.end(); ++it)
00259 {
00260 os << nextIndent << "Point " << i++ << ": [";
00261 os << it->GetElement(0);
00262 for (unsigned int i = 1; i < TransformInitializerType::LandmarkPointType::GetPointDimension(); ++i)
00263 {
00264 os << ", " << it->GetElement(i);
00265 }
00266 os << "]\n";
00267 }
00268 os << indent << "Landmarktransform initialized: " << this->IsInitialized() << "\n";
00269 if (this->IsInitialized() == true)
00270 m_LandmarkTransform->Print(os, nextIndent);
00271 os << indent << "Registration error statistics:\n";
00272 os << nextIndent << "FRE: " << this->GetFRE() << "\n";
00273 os << nextIndent << "FRE std.dev.: " << this->GetFREStdDev() << "\n";
00274 os << nextIndent << "FRE RMS: " << this->GetRMSError() << "\n";
00275 os << nextIndent << "Minimum registration error: " << this->GetMinError() << "\n";
00276 os << nextIndent << "Maximum registration error: " << this->GetMaxError() << "\n";
00277 os << nextIndent << "Absolute Maximum registration error: " << this->GetAbsMaxError() << "\n";
00278 }
00279
00280
00281 const mitk::NavigationDataLandmarkTransformFilter::ErrorVector& mitk::NavigationDataLandmarkTransformFilter::GetErrorVector() const
00282 {
00283 return m_Errors;
00284 }
00285
00286
00287 bool mitk::NavigationDataLandmarkTransformFilter::FindCorrespondentLandmarks(LandmarkPointContainer& sources, const LandmarkPointContainer& targets) const
00288 {
00289 if (sources.size() < 6 || targets.size() < 6)
00290 return false;
00291
00292
00293
00294 typedef itk::PointSet<mitk::ScalarType, 3> PointSetType;
00295
00296
00297 typedef itk::EuclideanDistancePointMetric< PointSetType, PointSetType> MetricType;
00298
00299
00300
00301
00302 typedef itk::VersorRigid3DTransform< double > TransformType;
00303 typedef TransformType ParametersType;
00304 typedef itk::PointSetToPointSetRegistrationMethod< PointSetType, PointSetType > RegistrationType;
00305
00306
00307 PointSetType::Pointer sourcePointSet = PointSetType::New();
00308 unsigned int i = 0;
00309 for (LandmarkPointContainer::const_iterator it = sources.begin(); it != sources.end(); ++it)
00310 {
00311 PointSetType::PointType doublePoint;
00312 mitk::itk2vtk(*it, doublePoint);
00313 sourcePointSet->SetPoint(i++, doublePoint );
00314 }
00315
00316 i = 0;
00317 PointSetType::Pointer targetPointSet = PointSetType::New();
00318 for (LandmarkPointContainer::const_iterator it = targets.begin(); it != targets.end(); ++it)
00319 {
00320 PointSetType::PointType doublePoint;
00321 mitk::itk2vtk(*it, doublePoint);
00322 targetPointSet->SetPoint(i++, doublePoint );
00323 }
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334 TransformType::Pointer transform = TransformType::New();
00335 transform->SetIdentity();
00336
00337
00338 itk::LevenbergMarquardtOptimizer::Pointer optimizer = itk::LevenbergMarquardtOptimizer::New();
00339 optimizer->SetUseCostFunctionGradient(false);
00340
00341 RegistrationType::Pointer registration = RegistrationType::New();
00342
00343
00344 itk::LevenbergMarquardtOptimizer::ScalesType scales(transform->GetNumberOfParameters());
00345 const double translationScale = 5000;
00346 const double rotationScale = 1.0;
00347 scales[0] = 1.0 / rotationScale;
00348 scales[1] = 1.0 / rotationScale;
00349 scales[2] = 1.0 / rotationScale;
00350 scales[3] = 1.0 / translationScale;
00351 scales[4] = 1.0 / translationScale;
00352 scales[5] = 1.0 / translationScale;
00353
00354 unsigned long numberOfIterations = 80000;
00355 double gradientTolerance = 1e-10;
00356 double valueTolerance = 1e-10;
00357 double epsilonFunction = 1e-10;
00358 optimizer->SetScales( scales );
00359 optimizer->SetNumberOfIterations( numberOfIterations );
00360 optimizer->SetValueTolerance( valueTolerance );
00361 optimizer->SetGradientTolerance( gradientTolerance );
00362 optimizer->SetEpsilonFunction( epsilonFunction );
00363
00364
00365 registration->SetInitialTransformParameters( transform->GetParameters() );
00366
00367
00368
00369 MetricType::Pointer metric = MetricType::New();
00370
00371 registration->SetMetric( metric );
00372 registration->SetOptimizer( optimizer );
00373 registration->SetTransform( transform );
00374 registration->SetFixedPointSet( targetPointSet );
00375 registration->SetMovingPointSet( sourcePointSet );
00376
00377 try
00378 {
00379
00380 registration->Update();
00381 }
00382 catch( itk::ExceptionObject & e )
00383 {
00384 MITK_INFO << "Exception caught during ICP optimization: " << e;
00385 return false;
00386
00387 }
00388 MITK_INFO << "ICP successful: Solution = " << transform->GetParameters() << std::endl;
00389 MITK_INFO << "Metric value: " << metric->GetValue(transform->GetParameters());
00390
00391
00392
00393
00394 for (LandmarkPointContainer::const_iterator sourcesIt = sources.begin(); sourcesIt != sources.end(); ++sourcesIt)
00395 {
00396 }
00397
00398
00399 LandmarkPointContainer sortedSources;
00400 for (LandmarkPointContainer::const_iterator targetsIt = targets.begin(); targetsIt != targets.end(); ++targetsIt)
00401 {
00402 double minDistance = itk::NumericTraits<double>::max();
00403 LandmarkPointContainer::iterator minDistanceIterator = sources.end();
00404 for (LandmarkPointContainer::iterator sourcesIt = sources.begin(); sourcesIt != sources.end(); ++sourcesIt)
00405 {
00406 TransformInitializerType::LandmarkPointType transformedSource = transform->TransformPoint(*sourcesIt);
00407 double dist = targetsIt->EuclideanDistanceTo(transformedSource);
00408 MITK_INFO << "target: " << *targetsIt << ", source: " << *sourcesIt << ", transformed source: " << transformedSource << ", dist: " << dist;
00409 if (dist < minDistance )
00410 {
00411 minDistanceIterator = sourcesIt;
00412 minDistance = dist;
00413 }
00414 }
00415 if (minDistanceIterator == sources.end())
00416 return false;
00417 MITK_INFO << "minimum distance point is: " << *minDistanceIterator << " (dist: " << targetsIt->EuclideanDistanceTo(transform->TransformPoint(*minDistanceIterator)) << ", minDist: " << minDistance << ")";
00418 sortedSources.push_back(*minDistanceIterator);
00419 sources.erase(minDistanceIterator);
00420 }
00421
00422 sources = sortedSources;
00423 return true;
00424 }
00425
00426
00427 void mitk::NavigationDataLandmarkTransformFilter::UpdateLandmarkTransform(const LandmarkPointContainer &sources, const LandmarkPointContainer &targets)
00428 {
00429 try
00430 {
00431
00432 m_LandmarkTransformInitializer->SetMovingLandmarks(targets);
00433 m_LandmarkTransformInitializer->SetFixedLandmarks(sources);
00434 m_LandmarkTransform->SetIdentity();
00435 m_LandmarkTransformInitializer->InitializeTransform();
00436
00437
00438 TransformInitializerType::LandmarkPointType curData;
00439 m_Errors.clear();
00440 for (LandmarkPointContainer::size_type index = 0; index < sources.size(); index++)
00441 {
00442 curData = m_LandmarkTransform->TransformPoint(sources.at(index));
00443 m_Errors.push_back(curData.EuclideanDistanceTo(targets.at(index)));
00444 }
00445 this->AccumulateStatistics(m_Errors);
00446 this->Modified();
00447 }
00448 catch (std::exception& e)
00449 {
00450 m_Errors.clear();
00451 m_LandmarkTransform->SetIdentity();
00452 itkExceptionMacro("Initializing landmark-transform failed\n. " << e.what());
00453 }
00454 }