Medical Imaging Interaction Toolkit  2018.4.99-389bf124
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 (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 // MITK
17 #include <mitkProgressBar.h>
18 #include <mitkSurface.h>
19 // VTK
20 #include <vtkIdList.h>
21 #include <vtkKdTree.h>
22 #include <vtkKdTreePointLocator.h>
23 #include <vtkPoints.h>
24 #include <vtkPolyData.h>
25 // STL pair
26 #include <utility>
27 
31 struct AICPComperator
32 {
33  typedef std::pair<unsigned int, double> Correspondence;
34 
35  bool operator()(const Correspondence &a, const Correspondence &b) { return (a.second < b.second); }
36 } AICPComp;
37 
39  : m_MaxIterations(1000),
40  m_Threshold(0.000001),
41  m_FRENormalizationFactor(1.0),
42  m_SearchRadius(30.0),
43  m_MaxIterationsInWeightedPointTransform(1000),
44  m_FRE(0.0),
45  m_TrimmFactor(0.0),
46  m_NumberOfIterations(0),
47  m_MovingSurface(nullptr),
48  m_FixedSurface(nullptr),
49  m_WeightedPointTransform(mitk::WeightedPointTransform::New())
50 {
51 }
52 
54 {
55 }
56 
58  vtkPoints *Z,
59  vtkKdTreePointLocator *Y,
60  const CovarianceMatrixList &sigma_X,
61  const CovarianceMatrixList &sigma_Y,
62  CovarianceMatrixList &sigma_Z,
63  CorrespondenceList &correspondences,
64  const double radius)
65 {
66  typedef itk::Matrix<double, 3, 3> WeightMatrix;
67 
68 #pragma omp parallel for
69  for (int i = 0; i < X->GetNumberOfPoints(); ++i)
70  {
71  vtkIdType bestIdx = 0;
74  double bestDist = std::numeric_limits<double>::max();
75  vtkIdList *ids = vtkIdList::New();
76  double r = radius;
77  double p[3];
78  // get point
79  X->GetPoint(i, p);
80  // fill vector
81  x[0] = p[0];
82  x[1] = p[1];
83  x[2] = p[2];
84 
85  // double the radius till we find at least one point
86  while (ids->GetNumberOfIds() <= 0)
87  {
88  Y->FindPointsWithinRadius(r, p, ids);
89  r *= 2.0;
90  }
91 
92  // loop over the points in the sphere and find the point with the
93  // minimal weighted squared distance
94  for (vtkIdType j = 0; j < ids->GetNumberOfIds(); ++j)
95  {
96  // get id
97  const vtkIdType id = ids->GetId(j);
98  // compute weightmatrix
99  WeightMatrix m = mitk::AnisotropicRegistrationCommon::CalculateWeightMatrix(sigma_X[i], sigma_Y[id]);
100  // point of the fixed data set
101  Y->GetDataSet()->GetPoint(id, p);
102 
103  // fill mitk vector
104  y[0] = p[0];
105  y[1] = p[1];
106  y[2] = p[2];
107 
108  const mitk::Vector3D res = m * (x - y);
109 
110  const double dist = res[0] * res[0] + res[1] * res[1] + res[2] * res[2];
111 
112  if (dist < bestDist)
113  {
114  bestDist = dist;
115  bestIdx = id;
116  }
117  }
118 
119  // save correspondences of the fixed point set
120  Y->GetDataSet()->GetPoint(bestIdx, p);
121  Z->SetPoint(i, p);
122  sigma_Z[i] = sigma_Y[bestIdx];
123 
124  Correspondence _pair(i, bestDist);
125  correspondences[i] = _pair;
126 
127  ids->Delete();
128  }
129 }
130 
132 {
133  unsigned int k = 0;
134  unsigned int numberOfTrimmedPoints = 0;
135  double diff = 0.0;
136  double FRE_new = std::numeric_limits<double>::max();
137  // Moving pointset
138  vtkPoints *X = vtkPoints::New();
139  // Correspondences
140  vtkPoints *Z = vtkPoints::New();
141  // Covariance matrices of the pointset X
143  // Covariance matrices of the pointset Y
145  // Covariance matrices of the correspondences
146  CovarianceMatrixList Sigma_Z;
147  // transform of the current iteration
148  Rotation RotationNew;
149  Translation TranslationNew;
150  // corresponding indizes with distance
151  CorrespondenceList distanceList;
152  // sorted datasets used if trimming is enabled
153  vtkPoints *X_sorted = vtkPoints::New();
154  vtkPoints *Z_sorted = vtkPoints::New();
155  CovarianceMatrixList Sigma_X_sorted;
156  CovarianceMatrixList Sigma_Z_sorted;
157 
158  // create kdtree for correspondence search
159  vtkKdTreePointLocator *Y = vtkKdTreePointLocator::New();
160  Y->SetDataSet(m_FixedSurface->GetVtkPolyData());
161  Y->BuildLocator();
162 
163  // initialize local variables
164  // copy the moving pointset to prevent to modify it
165  X->DeepCopy(m_MovingSurface->GetVtkPolyData()->GetPoints());
166  // initialize size of the correspondences
167  Z->SetNumberOfPoints(X->GetNumberOfPoints());
168  // size of the corresponding matrices
169  Sigma_Z.resize(X->GetNumberOfPoints());
170  distanceList.resize(X->GetNumberOfPoints());
171  RotationNew.SetIdentity();
172  TranslationNew.Fill(0.0);
173 
174  // reset members
176  m_Rotation.SetIdentity();
177  m_Translation.Fill(0.0);
178 
179  // compute number of correspondences based
180  // on the trimmfactor
181  if (m_TrimmFactor > 0.0)
182  {
183  numberOfTrimmedPoints = X->GetNumberOfPoints() * m_TrimmFactor;
184  }
185 
186  // initialize the sizes of the sorted datasets
187  // used in the trimmed version of the algorithm
188  Sigma_Z_sorted.resize(numberOfTrimmedPoints);
189  Sigma_X_sorted.resize(numberOfTrimmedPoints);
190  X_sorted->SetNumberOfPoints(numberOfTrimmedPoints);
191  Z_sorted->SetNumberOfPoints(numberOfTrimmedPoints);
192 
193  // initialize the progress bar
194  unsigned int steps = m_MaxIterations;
195  unsigned int stepSize = m_MaxIterations / 10;
197 
198  do
199  {
200  // reset innerloop
201  double currSearchRadius = m_SearchRadius;
202  unsigned int radiusDoubled = 0;
203 
204  k = k + 1;
205 
206  MITK_DEBUG << "iteration: " << k;
207 
208  do
209  {
210  // search correspondences
211  ComputeCorrespondences(X, Z, Y, Sigma_X, Sigma_Y, Sigma_Z, distanceList, currSearchRadius);
212 
213  // tmp pointers
214  vtkPoints *X_k = X;
215  vtkPoints *Z_k = Z;
216  CovarianceMatrixList *Sigma_Z_k = &Sigma_Z;
217  CovarianceMatrixList *Sigma_X_k = &Sigma_X;
218 
219  // sort the correspondences depending on their
220  // distance, if trimming is enabled
221  if (m_TrimmFactor > 0.0)
222  {
223  std::sort(distanceList.begin(), distanceList.end(), AICPComp);
224  // map correspondences to the data arrays
225  for (unsigned int i = 0; i < numberOfTrimmedPoints; ++i)
226  {
227  const int idx = distanceList[i].first;
228  Sigma_Z_sorted[i] = Sigma_Z[idx];
229  Sigma_X_sorted[i] = Sigma_X[idx];
230  Z_sorted->SetPoint(i, Z->GetPoint(idx));
231  X_sorted->SetPoint(i, X->GetPoint(idx));
232  }
233  // assign pointers
234  X_k = X_sorted;
235  Z_k = Z_sorted;
236  Sigma_X_k = &Sigma_X_sorted;
237  Sigma_Z_k = &Sigma_Z_sorted;
238  }
239 
240  // compute weighted transformation
241  // set parameters
242  m_WeightedPointTransform->SetMovingPointSet(X_k);
243  m_WeightedPointTransform->SetFixedPointSet(Z_k);
244  m_WeightedPointTransform->SetCovarianceMatricesMoving(*Sigma_X_k);
245  m_WeightedPointTransform->SetCovarianceMatricesFixed(*Sigma_Z_k);
247  m_WeightedPointTransform->SetFRENormalizationFactor(m_FRENormalizationFactor);
248 
249  // run computation
250  m_WeightedPointTransform->ComputeTransformation();
251  // retrieve result
252  RotationNew = m_WeightedPointTransform->GetTransformR();
253  TranslationNew = m_WeightedPointTransform->GetTransformT();
254  FRE_new = m_WeightedPointTransform->GetFRE();
255 
256  // double the radius
257  radiusDoubled += 1;
258  currSearchRadius *= 2.0;
259 
260  // sanity check to prevent endless loop
261  if (radiusDoubled >= 20)
262  {
263  mitkThrow() << "Radius doubled 20 times, preventing endless loop, check input and search radius";
264  }
265 
266  // termination constraint
267  diff = m_FRE - FRE_new;
268 
269  } while (diff < -1.0e-3); // increase radius as long as the FRE grows
270 
271  MITK_DEBUG << "FRE:" << m_FRE << ", FRE_new: " << FRE_new;
272  // transform points and propagate matrices
273  mitk::AnisotropicRegistrationCommon::TransformPoints(X, X, RotationNew, TranslationNew);
274  mitk::AnisotropicRegistrationCommon::PropagateMatrices(Sigma_X, Sigma_X, RotationNew);
275 
276  // update global transformation
277  m_Rotation = RotationNew * m_Rotation;
278  m_Translation = RotationNew * m_Translation + TranslationNew;
279 
280  MITK_DEBUG << "diff:" << diff;
281  // update FRE
282  m_FRE = FRE_new;
283 
284  // update the progressbar. Just use the half every 2nd iteration
285  // to use a simulated endless progress bar since we don't have
286  // a fixed amount of iterations
287  stepSize = (k % 2 == 0) ? stepSize / 2 : stepSize;
288  stepSize = (stepSize == 0) ? 1 : stepSize;
290 
291  } while (diff > m_Threshold && k < m_MaxIterations);
292 
294 
295  // finish the progress bar if there are more steps
296  // left than iterations used
297  if (k < steps)
299 
300  // free memory
301  Y->Delete();
302  Z->Delete();
303  X->Delete();
304  X_sorted->Delete();
305  Z_sorted->Delete();
306 }
void Progress(unsigned int steps=1)
Sets the current amount of progress to current progress + steps.
float k(1.0)
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:22
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:56
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.