Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkAnisotropicIterativeClosestPointRegistration.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
17 // MITK
21 #include <mitkProgressBar.h>
22 #include <mitkSurface.h>
23 // VTK
24 #include <vtkIdList.h>
25 #include <vtkKdTree.h>
26 #include <vtkKdTreePointLocator.h>
27 #include <vtkPoints.h>
28 #include <vtkPolyData.h>
29 // STL pair
30 #include <utility>
31 
35 struct AICPComperator
36 {
37  typedef std::pair<unsigned int, double> Correspondence;
38 
39  bool operator()(const Correspondence &a, const Correspondence &b) { return (a.second < b.second); }
40 } AICPComp;
41 
43  : m_MaxIterations(1000),
44  m_Threshold(0.000001),
45  m_FRENormalizationFactor(1.0),
46  m_SearchRadius(30.0),
47  m_MaxIterationsInWeightedPointTransform(1000),
48  m_FRE(0.0),
49  m_TrimmFactor(0.0),
50  m_NumberOfIterations(0),
51  m_MovingSurface(nullptr),
52  m_FixedSurface(nullptr),
53  m_WeightedPointTransform(mitk::WeightedPointTransform::New())
54 {
55 }
56 
58 {
59 }
60 
62  vtkPoints *Z,
63  vtkKdTreePointLocator *Y,
64  const CovarianceMatrixList &sigma_X,
65  const CovarianceMatrixList &sigma_Y,
66  CovarianceMatrixList &sigma_Z,
67  CorrespondenceList &correspondences,
68  const double radius)
69 {
70  typedef itk::Matrix<double, 3, 3> WeightMatrix;
71 
72 #pragma omp parallel for
73  for (vtkIdType i = 0; i < X->GetNumberOfPoints(); ++i)
74  {
75  vtkIdType bestIdx = 0;
78  double bestDist = std::numeric_limits<double>::max();
79  vtkIdList *ids = vtkIdList::New();
80  double r = radius;
81  double p[3];
82  // get point
83  X->GetPoint(i, p);
84  // fill vector
85  x[0] = p[0];
86  x[1] = p[1];
87  x[2] = p[2];
88 
89  // double the radius till we find at least one point
90  while (ids->GetNumberOfIds() <= 0)
91  {
92  Y->FindPointsWithinRadius(r, p, ids);
93  r *= 2.0;
94  }
95 
96  // loop over the points in the sphere and find the point with the
97  // minimal weighted squared distance
98  for (vtkIdType j = 0; j < ids->GetNumberOfIds(); ++j)
99  {
100  // get id
101  const vtkIdType id = ids->GetId(j);
102  // compute weightmatrix
103  WeightMatrix m = mitk::AnisotropicRegistrationCommon::CalculateWeightMatrix(sigma_X[i], sigma_Y[id]);
104  // point of the fixed data set
105  Y->GetDataSet()->GetPoint(id, p);
106 
107  // fill mitk vector
108  y[0] = p[0];
109  y[1] = p[1];
110  y[2] = p[2];
111 
112  const mitk::Vector3D res = m * (x - y);
113 
114  const double dist = res[0] * res[0] + res[1] * res[1] + res[2] * res[2];
115 
116  if (dist < bestDist)
117  {
118  bestDist = dist;
119  bestIdx = id;
120  }
121  }
122 
123  // save correspondences of the fixed point set
124  Y->GetDataSet()->GetPoint(bestIdx, p);
125  Z->SetPoint(i, p);
126  sigma_Z[i] = sigma_Y[bestIdx];
127 
128  Correspondence _pair(i, bestDist);
129  correspondences[i] = _pair;
130 
131  ids->Delete();
132  }
133 }
134 
136 {
137  unsigned int k = 0;
138  unsigned int numberOfTrimmedPoints = 0;
139  double diff = 0.0;
140  double FRE_new = std::numeric_limits<double>::max();
141  // Moving pointset
142  vtkPoints *X = vtkPoints::New();
143  // Correspondences
144  vtkPoints *Z = vtkPoints::New();
145  // Covariance matrices of the pointset X
146  CovarianceMatrixList &Sigma_X = m_CovarianceMatricesMovingSurface;
147  // Covariance matrices of the pointset Y
148  CovarianceMatrixList &Sigma_Y = m_CovarianceMatricesFixedSurface;
149  // Covariance matrices of the correspondences
150  CovarianceMatrixList Sigma_Z;
151  // transform of the current iteration
152  Rotation RotationNew;
153  Translation TranslationNew;
154  // corresponding indizes with distance
155  CorrespondenceList distanceList;
156  // sorted datasets used if trimming is enabled
157  vtkPoints *X_sorted = vtkPoints::New();
158  vtkPoints *Z_sorted = vtkPoints::New();
159  CovarianceMatrixList Sigma_X_sorted;
160  CovarianceMatrixList Sigma_Z_sorted;
161 
162  // create kdtree for correspondence search
163  vtkKdTreePointLocator *Y = vtkKdTreePointLocator::New();
164  Y->SetDataSet(m_FixedSurface->GetVtkPolyData());
165  Y->BuildLocator();
166 
167  // initialize local variables
168  // copy the moving pointset to prevent to modify it
169  X->DeepCopy(m_MovingSurface->GetVtkPolyData()->GetPoints());
170  // initialize size of the correspondences
171  Z->SetNumberOfPoints(X->GetNumberOfPoints());
172  // size of the corresponding matrices
173  Sigma_Z.resize(X->GetNumberOfPoints());
174  distanceList.resize(X->GetNumberOfPoints());
175  RotationNew.SetIdentity();
176  TranslationNew.Fill(0.0);
177 
178  // reset members
180  m_Rotation.SetIdentity();
181  m_Translation.Fill(0.0);
182 
183  // compute number of correspondences based
184  // on the trimmfactor
185  if (m_TrimmFactor > 0.0)
186  {
187  numberOfTrimmedPoints = X->GetNumberOfPoints() * m_TrimmFactor;
188  }
189 
190  // initialize the sizes of the sorted datasets
191  // used in the trimmed version of the algorithm
192  Sigma_Z_sorted.resize(numberOfTrimmedPoints);
193  Sigma_X_sorted.resize(numberOfTrimmedPoints);
194  X_sorted->SetNumberOfPoints(numberOfTrimmedPoints);
195  Z_sorted->SetNumberOfPoints(numberOfTrimmedPoints);
196 
197  // initialize the progress bar
198  unsigned int steps = m_MaxIterations;
199  unsigned int stepSize = m_MaxIterations / 10;
201 
202  do
203  {
204  // reset innerloop
205  double currSearchRadius = m_SearchRadius;
206  unsigned int radiusDoubled = 0;
207 
208  k = k + 1;
209 
210  MITK_DEBUG << "iteration: " << k;
211 
212  do
213  {
214  // search correspondences
215  ComputeCorrespondences(X, Z, Y, Sigma_X, Sigma_Y, Sigma_Z, distanceList, currSearchRadius);
216 
217  // tmp pointers
218  vtkPoints *X_k = X;
219  vtkPoints *Z_k = Z;
220  CovarianceMatrixList *Sigma_Z_k = &Sigma_Z;
221  CovarianceMatrixList *Sigma_X_k = &Sigma_X;
222 
223  // sort the correspondences depending on their
224  // distance, if trimming is enabled
225  if (m_TrimmFactor > 0.0)
226  {
227  std::sort(distanceList.begin(), distanceList.end(), AICPComp);
228  // map correspondences to the data arrays
229  for (unsigned int i = 0; i < numberOfTrimmedPoints; ++i)
230  {
231  const int idx = distanceList[i].first;
232  Sigma_Z_sorted[i] = Sigma_Z[idx];
233  Sigma_X_sorted[i] = Sigma_X[idx];
234  Z_sorted->SetPoint(i, Z->GetPoint(idx));
235  X_sorted->SetPoint(i, X->GetPoint(idx));
236  }
237  // assign pointers
238  X_k = X_sorted;
239  Z_k = Z_sorted;
240  Sigma_X_k = &Sigma_X_sorted;
241  Sigma_Z_k = &Sigma_Z_sorted;
242  }
243 
244  // compute weighted transformation
245  // set parameters
246  m_WeightedPointTransform->SetMovingPointSet(X_k);
247  m_WeightedPointTransform->SetFixedPointSet(Z_k);
248  m_WeightedPointTransform->SetCovarianceMatricesMoving(*Sigma_X_k);
249  m_WeightedPointTransform->SetCovarianceMatricesFixed(*Sigma_Z_k);
250  m_WeightedPointTransform->SetMaxIterations(m_MaxIterationsInWeightedPointTransform);
251  m_WeightedPointTransform->SetFRENormalizationFactor(m_FRENormalizationFactor);
252 
253  // run computation
254  m_WeightedPointTransform->ComputeTransformation();
255  // retrieve result
256  RotationNew = m_WeightedPointTransform->GetTransformR();
257  TranslationNew = m_WeightedPointTransform->GetTransformT();
258  FRE_new = m_WeightedPointTransform->GetFRE();
259 
260  // double the radius
261  radiusDoubled += 1;
262  currSearchRadius *= 2.0;
263 
264  // sanity check to prevent endless loop
265  if (radiusDoubled >= 20)
266  {
267  mitkThrow() << "Radius doubled 20 times, preventing endless loop, check input and search radius";
268  }
269 
270  // termination constraint
271  diff = m_FRE - FRE_new;
272 
273  } while (diff < -1.0e-3); // increase radius as long as the FRE grows
274 
275  MITK_DEBUG << "FRE:" << m_FRE << ", FRE_new: " << FRE_new;
276  // transform points and propagate matrices
277  mitk::AnisotropicRegistrationCommon::TransformPoints(X, X, RotationNew, TranslationNew);
278  mitk::AnisotropicRegistrationCommon::PropagateMatrices(Sigma_X, Sigma_X, RotationNew);
279 
280  // update global transformation
281  m_Rotation = RotationNew * m_Rotation;
282  m_Translation = RotationNew * m_Translation + TranslationNew;
283 
284  MITK_DEBUG << "diff:" << diff;
285  // update FRE
286  m_FRE = FRE_new;
287 
288  // update the progressbar. Just use the half every 2nd iteration
289  // to use a simulated endless progress bar since we don't have
290  // a fixed amount of iterations
291  stepSize = (k % 2 == 0) ? stepSize / 2 : stepSize;
292  stepSize = (stepSize == 0) ? 1 : stepSize;
294 
295  } while (diff > m_Threshold && k < m_MaxIterations);
296 
297  m_NumberOfIterations = k;
298 
299  // finish the progress bar if there are more steps
300  // left than iterations used
301  if (k < steps)
303 
304  // free memory
305  Y->Delete();
306  Z->Delete();
307  X->Delete();
308  X_sorted->Delete();
309  Z_sorted->Delete();
310 }
void Progress(unsigned int steps=1)
Sets the current amount of progress to current progress + steps.
This class implements an extension of the weighted point based registration algorithm from A...
void ComputeCorrespondences(vtkPoints *X, vtkPoints *Z, vtkKdTreePointLocator *Y, const CovarianceMatrixList &sigma_X, const CovarianceMatrixList &sigma_Y, CovarianceMatrixList &sigma_Z, CorrespondenceList &correspondences, const double radius)
#define MITK_DEBUG
Definition: mitkLogMacros.h:26
DataCollection - Class to facilitate loading/accessing structured data.
static ProgressBar * GetInstance()
static method to get the GUI dependent ProgressBar-instance so the methods for steps to do and progre...
struct AICPComperator AICPComp
static void PropagateMatrices(const MatrixList &src, MatrixList &dst, const Rotation &rotation)
Propagate a list of matrices with a rotation matrix.
#define mitkThrow()
static T max(T x, T y)
Definition: svm.cpp:70
void AddStepsToDo(unsigned int steps)
Adds steps to totalSteps.
static void TransformPoints(vtkPoints *src, vtkPoints *dst, const Rotation &rotation, const Translation &translation)
Transforms a point cloud with a Rotation and Translation.
static WeightMatrix CalculateWeightMatrix(const CovarianceMatrix &sigma_X, const CovarianceMatrix &sigma_Y)
Method that computes a WeightMatrix with two CovarianceMatrices.
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.