ANIMA  4.0
animaBalooSVFTransformAgregator.hxx
Go to the documentation of this file.
1 #pragma once
3 
8 
9 #include <animaMatrixLogExp.h>
10 #include <itkTimeProbe.h>
11 
12 namespace anima
13 {
14 
15 template <unsigned int NDimensions>
16 BalooSVFTransformAgregator <NDimensions>::
17 BalooSVFTransformAgregator() : Superclass()
18 {
21  m_ZeroWeight = 0.0;
22 
23  m_NumberOfThreads = itk::MultiThreaderBase::GetGlobalDefaultNumberOfThreads();
24 }
25 
26 template <unsigned int NDimensions>
27 bool
30 {
31  this->SetUpToDate(false);
32 
33  if (this->GetInputWeights().size() != this->GetInputTransforms().size())
34  return false;
35 
37  return false;
38 
39  itk::TimeProbe tmpTime;
40  tmpTime.Start();
41  switch (this->GetInputTransformType())
42  {
45  this->estimateSVFFromTranslations();
46  this->SetUpToDate(true);
47  break;
48 
49  case Superclass::RIGID:
50  this->estimateSVFFromRigidTransforms();
51  this->SetUpToDate(true);
52  break;
53 
54  case Superclass::AFFINE:
55  default:
56  this->estimateSVFFromAffineTransforms();
57  this->SetUpToDate(true);
58  break;
59  }
60 
61  tmpTime.Stop();
62  if (this->GetVerboseAgregation())
63  std::cout << "Agregation performed in " << tmpTime.GetTotal() << std::endl;
64 
65  return true;
66 }
67 
68 template <unsigned int NDimensions>
69 void
71 estimateSVFFromTranslations()
72 {
73  unsigned int nbPts = this->GetInputRegions().size();
74  VelocityFieldPointer velocityField = VelocityFieldType::New();
75  velocityField->Initialize();
76 
77  velocityField->SetRegions (m_LargestRegion);
78  velocityField->SetSpacing (m_Spacing);
79  velocityField->SetOrigin (m_Origin);
80  velocityField->SetDirection (m_Direction);
81  velocityField->Allocate();
82 
83  VelocityFieldPixelType zeroDisp;
84  zeroDisp.Fill(0);
85  itk::ImageRegionIterator < VelocityFieldType > svfIterator(velocityField,m_LargestRegion);
86  while (!svfIterator.IsAtEnd())
87  {
88  svfIterator.Set(zeroDisp);
89  ++svfIterator;
90  }
91 
92  WeightImagePointer weights = WeightImageType::New();
93  weights->Initialize();
94 
95  weights->SetRegions (m_LargestRegion);
96  weights->SetSpacing (m_Spacing);
97  weights->SetOrigin (m_Origin);
98  weights->SetDirection (m_Direction);
99  weights->Allocate();
100  weights->FillBuffer(m_ZeroWeight);
101 
102  ParametersType tmpParams(NDimensions);
103  std::vector <VelocityFieldPixelType> curDisps(nbPts);
104  std::vector <VelocityFieldIndexType> posIndexes(nbPts);
105 
106  for (unsigned int i = 0;i < nbPts;++i)
107  {
109  tmpParams = this->GetInputTransform(i)->GetParameters();
110  else
111  {
112  BaseMatrixTransformType *tmpTr = dynamic_cast <BaseMatrixTransformType *> (this->GetInputTransform(i));
113  for (unsigned int j = 0;j < NDimensions;++j)
114  tmpParams[j] = tmpTr->GetOffset()[j];
115  }
116 
117  double tmpWeight = this->GetInputWeight(i);
118  weights->TransformPhysicalPointToIndex(this->GetInputOrigin(i),posIndexes[i]);
119 
120  for (unsigned int j = 0;j < NDimensions;++j)
121  curDisps[i][j] = tmpParams[j];
122 
123  velocityField->SetPixel(posIndexes[i],curDisps[i] * tmpWeight);
124  weights->SetPixel(posIndexes[i],tmpWeight);
125  }
126 
127  this->filterInputs<NDimensions>(weights,velocityField,curDisps,posIndexes);
128 
129  // Create the final transform
130  typename BaseOutputTransformType::Pointer resultTransform = BaseOutputTransformType::New();
131  resultTransform->SetIdentity();
132  resultTransform->SetParametersAsVectorField(velocityField.GetPointer());
133 
134  this->SetOutput(resultTransform);
135 }
136 
137 template <unsigned int NDimensions>
138 void
140 estimateSVFFromRigidTransforms()
141 {
142  const unsigned int NDegreesFreedom = NDimensions * (NDimensions + 1) / 2;
143  typedef itk::Image < itk::Vector <ScalarType, NDegreesFreedom>, NDimensions > RigidFieldType;
144  typedef typename RigidFieldType::Pointer RigidFieldPointer;
145  typedef itk::Vector <ScalarType, NDegreesFreedom> RigidVectorType;
146 
147  unsigned int nbPts = this->GetInputRegions().size();
148  RigidFieldPointer rigidField = RigidFieldType::New();
149  rigidField->Initialize();
150 
151  rigidField->SetRegions (m_LargestRegion);
152  rigidField->SetSpacing (m_Spacing);
153  rigidField->SetOrigin (m_Origin);
154  rigidField->SetDirection (m_Direction);
155  rigidField->Allocate();
156 
157  RigidVectorType zeroDisp;
158  zeroDisp.Fill(0);
159  itk::ImageRegionIterator < RigidFieldType > rigidIterator(rigidField,m_LargestRegion);
160  while (!rigidIterator.IsAtEnd())
161  {
162  rigidIterator.Set(zeroDisp);
163  ++rigidIterator;
164  }
165 
166  WeightImagePointer weights = WeightImageType::New();
167  weights->Initialize();
168 
169  weights->SetRegions (m_LargestRegion);
170  weights->SetSpacing (m_Spacing);
171  weights->SetOrigin (m_Origin);
172  weights->SetDirection (m_Direction);
173  weights->Allocate();
174  weights->FillBuffer(m_ZeroWeight);
175 
176  RigidVectorType curLog;
177 
178  vnl_matrix <InternalScalarType> tmpMatrix(NDimensions+1,NDimensions+1,0);
179  tmpMatrix(NDimensions,NDimensions) = 1;
180  std::vector < RigidVectorType > logVectors(nbPts);
181  std::vector <VelocityFieldIndexType> posIndexes(nbPts);
182  VelocityFieldPointType curPoint;
183 
184  typedef anima::LogRigid3DTransform <InternalScalarType> LogRigidTransformType;
185 
186  for (unsigned int i = 0;i < nbPts;++i)
187  {
188  double tmpWeight = this->GetInputWeight(i);
189  weights->TransformPhysicalPointToIndex(this->GetInputOrigin(i),posIndexes[i]);
190 
191  LogRigidTransformType *tmpTrsf = (LogRigidTransformType *)this->GetInputTransform(i);
192  logVectors[i] = tmpTrsf->GetLogVector();
193  rigidField->SetPixel(posIndexes[i],logVectors[i] * tmpWeight);
194  weights->SetPixel(posIndexes[i],tmpWeight);
195  }
196 
197  this->filterInputs<NDegreesFreedom>(weights,rigidField,logVectors,posIndexes);
198 
199  VelocityFieldPointer velocityField = VelocityFieldType::New();
200  velocityField->Initialize();
201 
202  velocityField->SetRegions (m_LargestRegion);
203  velocityField->SetSpacing (m_Spacing);
204  velocityField->SetOrigin (m_Origin);
205  velocityField->SetDirection (m_Direction);
206  velocityField->Allocate();
207 
208  itk::ImageRegionIteratorWithIndex < VelocityFieldType > svfIterator(velocityField,m_LargestRegion);
209  tmpMatrix.fill(0);
210  VelocityFieldIndexType curIndex;
211  VelocityFieldPixelType curDisp;
212 
213  rigidIterator = itk::ImageRegionIterator < RigidFieldType > (rigidField,m_LargestRegion);
214  while (!svfIterator.IsAtEnd())
215  {
216  curLog = rigidIterator.Get();
217 
218  unsigned int pos = 0;
219  for (unsigned int j = 0;j < NDimensions;++j)
220  for (unsigned int k = j+1;k < NDimensions;++k)
221  {
222  tmpMatrix(j,k) = curLog[pos];
223  tmpMatrix(k,j) = - curLog[pos];
224  ++pos;
225  }
226 
227  for (unsigned int j = 0;j < NDimensions;++j)
228  {
229  tmpMatrix(j,NDimensions) = curLog[pos];
230  ++pos;
231  }
232 
233  curIndex = svfIterator.GetIndex();
234  velocityField->TransformIndexToPhysicalPoint(curIndex,curPoint);
235  for (unsigned int i = 0;i < NDimensions;++i)
236  {
237  curDisp[i] = tmpMatrix(i,NDimensions);
238  for (unsigned int j = 0;j < NDimensions;++j)
239  curDisp[i] += tmpMatrix(i,j) * curPoint[j];
240  }
241 
242  svfIterator.Set(curDisp);
243 
244  ++rigidIterator;
245  ++svfIterator;
246  }
247 
248  // Create the final transform
249  typename BaseOutputTransformType::Pointer resultTransform = BaseOutputTransformType::New();
250  resultTransform->SetIdentity();
251  resultTransform->SetParametersAsVectorField(velocityField.GetPointer());
252 
253  this->SetOutput(resultTransform);
254 }
255 
256 template <unsigned int NDimensions>
257 void
259 estimateSVFFromAffineTransforms()
260 {
261  const unsigned int NDegreesFreedom = NDimensions * (NDimensions + 1);
262  typedef itk::Image < itk::Vector <ScalarType, NDegreesFreedom>, NDimensions > AffineFieldType;
263  typedef typename AffineFieldType::Pointer AffineFieldPointer;
264  typedef itk::Vector <ScalarType, NDegreesFreedom> AffineVectorType;
265 
266  unsigned int nbPts = this->GetInputRegions().size();
267  AffineFieldPointer affineField = AffineFieldType::New();
268  affineField->Initialize();
269 
270  affineField->SetRegions (m_LargestRegion);
271  affineField->SetSpacing (m_Spacing);
272  affineField->SetOrigin (m_Origin);
273  affineField->SetDirection (m_Direction);
274  affineField->Allocate();
275 
276  AffineVectorType zeroDisp;
277  zeroDisp.Fill(0);
278  itk::ImageRegionIterator < AffineFieldType > affineIterator(affineField,m_LargestRegion);
279  while (!affineIterator.IsAtEnd())
280  {
281  affineIterator.Set(zeroDisp);
282  ++affineIterator;
283  }
284 
285  WeightImagePointer weights = WeightImageType::New();
286  weights->Initialize();
287 
288  weights->SetRegions (m_LargestRegion);
289  weights->SetSpacing (m_Spacing);
290  weights->SetOrigin (m_Origin);
291  weights->SetDirection (m_Direction);
292  weights->Allocate();
293  weights->FillBuffer(m_ZeroWeight);
294 
295  AffineVectorType curLog;
296  VelocityFieldPointType curPoint;
297 
298  vnl_matrix <InternalScalarType> tmpMatrix(NDimensions+1,NDimensions+1,0);
299  tmpMatrix(NDimensions,NDimensions) = 1;
300  std::vector < AffineVectorType > logVectors(nbPts);
301  std::vector < VelocityFieldIndexType > posIndexes(nbPts);
302 
304  {
306 
307  MatrixLoggerFilterType *logFilter = new MatrixLoggerFilterType;
308  logFilter->SetInput(this->GetInputTransforms());
309  logFilter->SetNumberOfWorkUnits(m_NumberOfThreads);
310  logFilter->SetUseRigidTransforms(false);
311 
312  logFilter->Update();
313  logVectors = logFilter->GetOutput();
314 
315  delete logFilter;
316  }
317  else
318  {
320  DistoTrsfType *tmpTrsf;
321  for (unsigned int i = 0;i < nbPts;++i)
322  {
323  tmpTrsf = dynamic_cast <DistoTrsfType *> (this->GetInputTransform(i));
324  logVectors[i] = tmpTrsf->GetLogVector();
325  }
326  }
327 
328  for (unsigned int i = 0;i < nbPts;++i)
329  {
330  double tmpWeight = this->GetInputWeight(i);
331  weights->TransformPhysicalPointToIndex(this->GetInputOrigin(i),posIndexes[i]);
332 
333  if (std::isnan(logVectors[i][0]))
334  {
335  logVectors[i].Fill(0);
336  tmpWeight = 0;
337  }
338 
339  affineField->SetPixel(posIndexes[i],logVectors[i] * tmpWeight);
340  weights->SetPixel(posIndexes[i],tmpWeight);
341  }
342 
343  this->filterInputs<NDegreesFreedom>(weights,affineField,logVectors,posIndexes);
344 
345  VelocityFieldPointer velocityField = VelocityFieldType::New();
346  velocityField->Initialize();
347 
348  velocityField->SetRegions (m_LargestRegion);
349  velocityField->SetSpacing (m_Spacing);
350  velocityField->SetOrigin (m_Origin);
351  velocityField->SetDirection (m_Direction);
352  velocityField->Allocate();
353 
354  itk::ImageRegionIteratorWithIndex < VelocityFieldType > svfIterator(velocityField,m_LargestRegion);
355  tmpMatrix.fill(0);
356  VelocityFieldIndexType curIndex;
357  VelocityFieldPixelType curDisp;
358 
359  affineIterator = itk::ImageRegionIterator < AffineFieldType > (affineField,m_LargestRegion);
360  while (!svfIterator.IsAtEnd())
361  {
362  curLog = affineIterator.Get();
363 
364  unsigned int pos = 0;
365  for (unsigned int j = 0;j < NDimensions;++j)
366  for (unsigned int k = 0;k <= NDimensions;++k)
367  {
368  tmpMatrix(j,k) = curLog[pos];
369  ++pos;
370  }
371 
372  curIndex = svfIterator.GetIndex();
373  velocityField->TransformIndexToPhysicalPoint(curIndex,curPoint);
374  for (unsigned int i = 0;i < NDimensions;++i)
375  {
376  curDisp[i] = tmpMatrix(i,NDimensions);
377  for (unsigned int j = 0;j < NDimensions;++j)
378  curDisp[i] += tmpMatrix(i,j) * curPoint[j];
379  }
380 
381  svfIterator.Set(curDisp);
382 
383  ++affineIterator;
384  ++svfIterator;
385  }
386 
387  // Create the final transform
388  typename BaseOutputTransformType::Pointer resultTransform = BaseOutputTransformType::New();
389  resultTransform->SetIdentity();
390  resultTransform->SetParametersAsVectorField(velocityField.GetPointer());
391 
392  this->SetOutput(resultTransform);
393 }
394 
395 template <unsigned int NDimensions>
396 template <unsigned int NDegreesOfFreedom>
397 void
399 filterInputs(WeightImageType *weights, typename itk::Image < itk::Vector <ScalarType, NDegreesOfFreedom>, NDimensions >::Pointer &output,
400  std::vector < itk::Vector <ScalarType, NDegreesOfFreedom> > &curTrsfs,
401  std::vector < typename itk::Image < itk::Vector <ScalarType, NDegreesOfFreedom>, NDimensions >::IndexType > &posIndexes)
402 {
403  typedef itk::Image < itk::Vector <ScalarType, NDegreesOfFreedom>, NDimensions > FieldType;
404  typedef itk::Vector <ScalarType, NDegreesOfFreedom> FieldPixelType;
405 
406  typedef itk::Image <ScalarType,NDimensions> WeightImageType;
407 
408  FieldPixelType zeroTrsf;
409  zeroTrsf.Fill(0);
410 
412  typename WeightSmootherType::Pointer weightSmooth = WeightSmootherType::New();
413 
414  weightSmooth->SetInput(weights);
415  weightSmooth->SetSigma(m_ExtrapolationSigma);
416  weightSmooth->SetNumberOfWorkUnits(m_NumberOfThreads);
417 
418  weightSmooth->Update();
419 
420  typename WeightImageType::Pointer smoothedWeights = weightSmooth->GetOutput();
421  smoothedWeights->DisconnectPipeline();
422  weightSmooth = 0;
423 
425  typename SVFSmoothingFilterType::Pointer smootherPtr = SVFSmoothingFilterType::New();
426 
427  smootherPtr->SetInput(output);
428  smootherPtr->SetSigma(m_ExtrapolationSigma);
429  smootherPtr->SetNumberOfWorkUnits(m_NumberOfThreads);
430 
431  smootherPtr->Update();
432 
433  typename FieldType::Pointer smoothedField = smootherPtr->GetOutput();
434  smoothedField->DisconnectPipeline();
435  smootherPtr = 0;
436 
437  // Now remove outliers
438  FieldPixelType curTrsf;
439 
440  unsigned int nbPts = this->GetInputRegions().size();
441  std::vector < double > residuals(nbPts);
442  double averageResidual = 0, varResidual = 0;
443  for (unsigned int i = 0;i < nbPts;++i)
444  {
445  double weightSmoothed = smoothedWeights->GetPixel(posIndexes[i]);
446  if (weightSmoothed > 0)
447  {
448  curTrsf = smoothedField->GetPixel(posIndexes[i]);
449  curTrsf /= weightSmoothed;
450  }
451  else
452  curTrsf = zeroTrsf;
453 
454  double residual = 0;
455 
456  for (unsigned int j = 0;j < NDegreesOfFreedom;++j)
457  residual += (curTrsf[j] - curTrsfs[i][j]) * (curTrsf[j] - curTrsfs[i][j]);
458 
459  varResidual += residual;
460  residual = sqrt(residual);
461  averageResidual += residual;
462  residuals[i] = residual;
463  }
464 
465  smoothedField = 0;
466  smoothedWeights = 0;
467 
468  varResidual = sqrt((varResidual - averageResidual * averageResidual / nbPts) / (nbPts - 1.0));
469  averageResidual /= nbPts;
470 
471  for (unsigned int i = 0;i < nbPts;++i)
472  {
473  if (residuals[i] > averageResidual + m_OutlierRejectionSigma * varResidual)
474  {
475  output->SetPixel(posIndexes[i],zeroTrsf);
476  weights->SetPixel(posIndexes[i],m_ZeroWeight);
477  }
478  }
479 
480  weightSmooth = WeightSmootherType::New();
481 
482  weightSmooth->SetInput(weights);
483  weightSmooth->SetSigma(m_ExtrapolationSigma);
484  weightSmooth->SetNumberOfWorkUnits(m_NumberOfThreads);
485 
486  weightSmooth->Update();
487 
488  smoothedWeights = weightSmooth->GetOutput();
489  smoothedWeights->DisconnectPipeline();
490 
491  smootherPtr = SVFSmoothingFilterType::New();
492 
493  smootherPtr->SetInput(output);
494  smootherPtr->SetSigma(m_ExtrapolationSigma);
495  smootherPtr->SetNumberOfWorkUnits(m_NumberOfThreads);
496 
497  smootherPtr->Update();
498 
499  output = smootherPtr->GetOutput();
500  output->DisconnectPipeline();
501 
503  typename ExtrapolateFilterType::Pointer extrapolateFilter = ExtrapolateFilterType::New();
504  extrapolateFilter->SetInput(output);
505  extrapolateFilter->SetExtrapolationSigma(m_ExtrapolationSigma);
506  extrapolateFilter->SetNumberOfWorkUnits(m_NumberOfThreads);
507  extrapolateFilter->SetWeightImage(smoothedWeights);
508  extrapolateFilter->Update();
509 
510  output = extrapolateFilter->GetOutput();
511  output->DisconnectPipeline();
512 }
513 
514 } // end of namespace anima
VelocityFieldType::IndexType VelocityFieldIndexType
BaseInputTransformType * GetInputTransform(unsigned int i)
std::vector< BaseInputTransformPointer > & GetInputTransforms()
std::vector< RegionType > & GetInputRegions()
std::vector< InternalScalarType > & GetInputWeights()
itk::MatrixOffsetTransformBase< InternalScalarType, NDimensions, NDimensions > BaseMatrixTransformType
void SetInput(InputType &input)
VelocityFieldType::PixelType VelocityFieldPixelType
PointType & GetInputOrigin(unsigned int i)
VelocityFieldType::PointType VelocityFieldPointType
void SetOutput(BaseOutputTransformType *output)
Class to compute many log-vectors in a multi-threaded way.
InternalScalarType GetInputWeight(unsigned int i)
BaseMatrixTransformType::ParametersType ParametersType
itk::Image< ScalarType, NDimensions > WeightImageType