Orfeo Toolbox  3.16
itkBSplineInterpolateImageFunction.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkBSplineInterpolateImageFunction.txx,v $
5  Language: C++
6  Date: $Date: 2009-10-13 07:39:24 $
7  Version: $Revision: 1.22 $
8 
9  Copyright (c) Insight Software Consortium. All rights reserved.
10  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
11 
12  Portions of this code are covered under the VTK copyright.
13  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details.
14 
15  This software is distributed WITHOUT ANY WARRANTY; without even
16  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
17  PURPOSE. See the above copyright notices for more information.
18 
19 =========================================================================*/
20 #ifndef __itkBSplineInterpolateImageFunction_txx
21 #define __itkBSplineInterpolateImageFunction_txx
22 
23 // First, make sure that we include the configuration file.
24 // This line may be removed once the ThreadSafeTransform gets
25 // integrated into ITK.
26 #include "itkConfigure.h"
27 
28 // Second, redirect to the optimized version if necessary
29 #ifdef ITK_USE_OPTIMIZED_REGISTRATION_METHODS
31 #else
32 
36 #include "itkImageRegionIterator.h"
37 
38 #include "itkVector.h"
39 
40 #include "itkMatrix.h"
41 
42 namespace itk
43 {
44 
48 template <class TImageType, class TCoordRep, class TCoefficientType>
51 {
52  m_SplineOrder = 0;
53  unsigned int SplineOrder = 3;
54  m_CoefficientFilter = CoefficientFilter::New();
55  // ***TODO: Should we store coefficients in a variable or retrieve from filter?
56  m_Coefficients = CoefficientImageType::New();
57  this->SetSplineOrder(SplineOrder);
58 #if defined(ITK_IMAGE_BEHAVES_AS_ORIENTED_IMAGE)
59  this->m_UseImageDirection = true;
60 #else
61  this->m_UseImageDirection = false;
62 #endif
63 }
64 
68 template <class TImageType, class TCoordRep, class TCoefficientType>
69 void
72  std::ostream& os,
73  Indent indent) const
74 {
75  Superclass::PrintSelf( os, indent );
76  os << indent << "Spline Order: " << m_SplineOrder << std::endl;
77  os << indent << "UseImageDirection = "
78  << (this->m_UseImageDirection ? "On" : "Off") << std::endl;
79 
80 }
81 
82 
83 template <class TImageType, class TCoordRep, class TCoefficientType>
84 void
86 ::SetInputImage(const TImageType * inputData)
87 {
88  if ( inputData )
89  {
90  m_CoefficientFilter->SetInput(inputData);
91 
92  // the Coefficient Filter requires that the spline order and the input data be set.
93  // TODO: We need to ensure that this is only run once and only after both input and
94  // spline order have been set. Should we force an update after the
95  // splineOrder has been set also?
96 
97  m_CoefficientFilter->Update();
98  m_Coefficients = m_CoefficientFilter->GetOutput();
99 
100  // Call the Superclass implementation after, in case the filter
101  // pulls in more of the input image
102  Superclass::SetInputImage(inputData);
103 
104  m_DataLength = inputData->GetBufferedRegion().GetSize();
105  }
106  else
107  {
108  m_CoefficientFilter->GetOutput()->DisconnectPipeline();
109  m_Coefficients = NULL;
110  }
111 }
112 
113 
114 template <class TImageType, class TCoordRep, class TCoefficientType>
115 void
117 ::SetSplineOrder(unsigned int SplineOrder)
118 {
119  if (SplineOrder == m_SplineOrder)
120  {
121  return;
122  }
123  m_SplineOrder = SplineOrder;
124  m_CoefficientFilter->SetSplineOrder( SplineOrder );
125 
126  //this->SetPoles();
127  m_MaxNumberInterpolationPoints = 1;
128  for (unsigned int n=0; n < ImageDimension; n++)
129  {
130  m_MaxNumberInterpolationPoints *= ( m_SplineOrder + 1);
131  }
132  this->GeneratePointsToIndex( );
133 }
134 
135 
136 template <class TImageType, class TCoordRep, class TCoefficientType>
137 typename
139 ::OutputType
142 {
143  vnl_matrix<long> EvaluateIndex(ImageDimension, ( m_SplineOrder + 1 ));
144 
145  // compute the interpolation indexes
146  this->DetermineRegionOfSupport(EvaluateIndex, x, m_SplineOrder);
147 
148  // Determine weights
149  vnl_matrix<double> weights(ImageDimension, ( m_SplineOrder + 1 ));
150  SetInterpolationWeights( x, EvaluateIndex, weights, m_SplineOrder );
151 
152  // Modify EvaluateIndex at the boundaries using mirror boundary conditions
153  this->ApplyMirrorBoundaryConditions(EvaluateIndex, m_SplineOrder);
154 
155  // perform interpolation
156  double interpolated = 0.0;
157  IndexType coefficientIndex;
158  // Step through eachpoint in the N-dimensional interpolation cube.
159  for (unsigned int p = 0; p < m_MaxNumberInterpolationPoints; p++)
160  {
161  // translate each step into the N-dimensional index.
162  // IndexType pointIndex = PointToIndex( p );
163 
164  double w = 1.0;
165  for (unsigned int n = 0; n < ImageDimension; n++ )
166  {
167  w *= weights[n][ m_PointsToIndex[p][n] ];
168  coefficientIndex[n] = EvaluateIndex[n][m_PointsToIndex[p][n]]; // Build up ND index for coefficients.
169  }
170  // Convert our step p to the appropriate point in ND space in the
171  // m_Coefficients cube.
172  interpolated += w * (m_Coefficients->GetPixel(coefficientIndex));
173  }
174 
175  return(interpolated);
176 
177 }
178 
179 
180 template <class TImageType, class TCoordRep, class TCoefficientType>
181 typename
183 :: CovariantVectorType
186 {
187  vnl_matrix<long> EvaluateIndex(ImageDimension, ( m_SplineOrder + 1 ));
188 
189  // compute the interpolation indexes
190  // TODO: Do we need to revisit region of support for the derivatives?
191  this->DetermineRegionOfSupport(EvaluateIndex, x, m_SplineOrder);
192 
193  // Determine weights
194  vnl_matrix<double> weights(ImageDimension, ( m_SplineOrder + 1 ));
195  SetInterpolationWeights( x, EvaluateIndex, weights, m_SplineOrder );
196 
197  vnl_matrix<double> weightsDerivative(ImageDimension, ( m_SplineOrder + 1));
198  SetDerivativeWeights( x, EvaluateIndex, weightsDerivative, ( m_SplineOrder ) );
199 
200  // Modify EvaluateIndex at the boundaries using mirror boundary conditions
201  this->ApplyMirrorBoundaryConditions(EvaluateIndex, m_SplineOrder);
202 
203  const InputImageType * inputImage = this->GetInputImage();
204  const typename InputImageType::SpacingType & spacing = inputImage->GetSpacing();
205 
206  // Calculate derivative
207  CovariantVectorType derivativeValue;
208  double tempValue;
209  IndexType coefficientIndex;
210  for (unsigned int n = 0; n < ImageDimension; n++)
211  {
212  derivativeValue[n] = 0.0;
213  for (unsigned int p = 0; p < m_MaxNumberInterpolationPoints; p++)
214  {
215  tempValue = 1.0;
216  for (unsigned int n1 = 0; n1 < ImageDimension; n1++)
217  {
218  //coefficientIndex[n1] = EvaluateIndex[n1][sp];
219  coefficientIndex[n1] = EvaluateIndex[n1][m_PointsToIndex[p][n1]];
220 
221  if (n1 == n)
222  {
223  //w *= weights[n][ m_PointsToIndex[p][n] ];
224  tempValue *= weightsDerivative[n1][ m_PointsToIndex[p][n1] ];
225  }
226  else
227  {
228  tempValue *= weights[n1][ m_PointsToIndex[p][n1] ];
229  }
230  }
231  derivativeValue[n] += m_Coefficients->GetPixel(coefficientIndex) * tempValue;
232  }
233  derivativeValue[n] /= spacing[n]; // take spacing into account
234  }
235 
236 #ifdef ITK_USE_ORIENTED_IMAGE_DIRECTION
237  if( this->m_UseImageDirection )
238  {
239  CovariantVectorType orientedDerivative;
240  inputImage->TransformLocalVectorToPhysicalVector( derivativeValue, orientedDerivative );
241  return orientedDerivative;
242  }
243 #endif
244 
245  return(derivativeValue);
246 }
247 
248 
249 template <class TImageType, class TCoordRep, class TCoefficientType>
250 void
253  vnl_matrix<double> & weights, unsigned int splineOrder ) const
254 {
255  // For speed improvements we could make each case a separate function and use
256  // function pointers to reference the correct weight order.
257  // Left as is for now for readability.
258  double w, w2, w4, t, t0, t1;
259 
260  switch (splineOrder)
261  {
262  case 3:
263  for (unsigned int n = 0; n < ImageDimension; n++)
264  {
265  w = x[n] - (double) EvaluateIndex[n][1];
266  weights[n][3] = (1.0 / 6.0) * w * w * w;
267  weights[n][0] = (1.0 / 6.0) + 0.5 * w * (w - 1.0) - weights[n][3];
268  weights[n][2] = w + weights[n][0] - 2.0 * weights[n][3];
269  weights[n][1] = 1.0 - weights[n][0] - weights[n][2] - weights[n][3];
270  }
271  break;
272  case 0:
273  for (unsigned int n = 0; n < ImageDimension; n++)
274  {
275  weights[n][0] = 1; // implements nearest neighbor
276  }
277  break;
278  case 1:
279  for (unsigned int n = 0; n < ImageDimension; n++)
280  {
281  w = x[n] - (double) EvaluateIndex[n][0];
282  weights[n][1] = w;
283  weights[n][0] = 1.0 - w;
284  }
285  break;
286  case 2:
287  for (unsigned int n = 0; n < ImageDimension; n++)
288  {
289  /* x */
290  w = x[n] - (double)EvaluateIndex[n][1];
291  weights[n][1] = 0.75 - w * w;
292  weights[n][2] = 0.5 * (w - weights[n][1] + 1.0);
293  weights[n][0] = 1.0 - weights[n][1] - weights[n][2];
294  }
295  break;
296  case 4:
297  for (unsigned int n = 0; n < ImageDimension; n++)
298  {
299  /* x */
300  w = x[n] - (double)EvaluateIndex[n][2];
301  w2 = w * w;
302  t = (1.0 / 6.0) * w2;
303  weights[n][0] = 0.5 - w;
304  weights[n][0] *= weights[n][0];
305  weights[n][0] *= (1.0 / 24.0) * weights[n][0];
306  t0 = w * (t - 11.0 / 24.0);
307  t1 = 19.0 / 96.0 + w2 * (0.25 - t);
308  weights[n][1] = t1 + t0;
309  weights[n][3] = t1 - t0;
310  weights[n][4] = weights[n][0] + t0 + 0.5 * w;
311  weights[n][2] = 1.0 - weights[n][0] - weights[n][1] - weights[n][3] - weights[n][4];
312  }
313  break;
314  case 5:
315  for (unsigned int n = 0; n < ImageDimension; n++)
316  {
317  /* x */
318  w = x[n] - (double)EvaluateIndex[n][2];
319  w2 = w * w;
320  weights[n][5] = (1.0 / 120.0) * w * w2 * w2;
321  w2 -= w;
322  w4 = w2 * w2;
323  w -= 0.5;
324  t = w2 * (w2 - 3.0);
325  weights[n][0] = (1.0 / 24.0) * (1.0 / 5.0 + w2 + w4) - weights[n][5];
326  t0 = (1.0 / 24.0) * (w2 * (w2 - 5.0) + 46.0 / 5.0);
327  t1 = (-1.0 / 12.0) * w * (t + 4.0);
328  weights[n][2] = t0 + t1;
329  weights[n][3] = t0 - t1;
330  t0 = (1.0 / 16.0) * (9.0 / 5.0 - t);
331  t1 = (1.0 / 24.0) * w * (w4 - w2 - 5.0);
332  weights[n][1] = t0 + t1;
333  weights[n][4] = t0 - t1;
334  }
335  break;
336  default:
337  // SplineOrder not implemented yet.
338  ExceptionObject err(__FILE__, __LINE__);
339  err.SetLocation( ITK_LOCATION );
340  err.SetDescription( "SplineOrder must be between 0 and 5. Requested spline order has not been implemented yet." );
341  throw err;
342  break;
343  }
344 
345 }
346 
347 template <class TImageType, class TCoordRep, class TCoefficientType>
348 void
351  vnl_matrix<double> & weights, unsigned int splineOrder ) const
352 {
353  // For speed improvements we could make each case a separate function and use
354  // function pointers to reference the correct weight order.
355  // Another possiblity would be to loop inside the case statement (reducing the number
356  // of switch statement executions to one per routine call.
357  // Left as is for now for readability.
358  double w, w1, w2, w3, w4, w5, t, t0, t1, t2;
359  int derivativeSplineOrder = (int) splineOrder -1;
360 
361  switch (derivativeSplineOrder)
362  {
363 
364  // Calculates B(splineOrder) ( (x + 1/2) - xi) - B(splineOrder -1) ( (x - 1/2) - xi)
365  case -1:
366  // Why would we want to do this?
367  for (unsigned int n = 0; n < ImageDimension; n++)
368  {
369  weights[n][0] = 0.0;
370  }
371  break;
372  case 0:
373  for (unsigned int n = 0; n < ImageDimension; n++)
374  {
375  weights[n][0] = -1.0;
376  weights[n][1] = 1.0;
377  }
378  break;
379  case 1:
380  for (unsigned int n = 0; n < ImageDimension; n++)
381  {
382  w = x[n] + 0.5 - (double)EvaluateIndex[n][1];
383  // w2 = w;
384  w1 = 1.0 - w;
385 
386  weights[n][0] = 0.0 - w1;
387  weights[n][1] = w1 - w;
388  weights[n][2] = w;
389  }
390  break;
391  case 2:
392 
393  for (unsigned int n = 0; n < ImageDimension; n++)
394  {
395  w = x[n] + .5 - (double)EvaluateIndex[n][2];
396  w2 = 0.75 - w * w;
397  w3 = 0.5 * (w - w2 + 1.0);
398  w1 = 1.0 - w2 - w3;
399 
400  weights[n][0] = 0.0 - w1;
401  weights[n][1] = w1 - w2;
402  weights[n][2] = w2 - w3;
403  weights[n][3] = w3;
404  }
405  break;
406  case 3:
407 
408  for (unsigned int n = 0; n < ImageDimension; n++)
409  {
410  w = x[n] + 0.5 - (double)EvaluateIndex[n][2];
411  w4 = (1.0 / 6.0) * w * w * w;
412  w1 = (1.0 / 6.0) + 0.5 * w * (w - 1.0) - w4;
413  w3 = w + w1 - 2.0 * w4;
414  w2 = 1.0 - w1 - w3 - w4;
415 
416  weights[n][0] = 0.0 - w1;
417  weights[n][1] = w1 - w2;
418  weights[n][2] = w2 - w3;
419  weights[n][3] = w3 - w4;
420  weights[n][4] = w4;
421  }
422  break;
423  case 4:
424  for (unsigned int n = 0; n < ImageDimension; n++)
425  {
426  w = x[n] + .5 - (double)EvaluateIndex[n][3];
427  t2 = w * w;
428  t = (1.0 / 6.0) * t2;
429  w1 = 0.5 - w;
430  w1 *= w1;
431  w1 *= (1.0 / 24.0) * w1;
432  t0 = w * (t - 11.0 / 24.0);
433  t1 = 19.0 / 96.0 + t2 * (0.25 - t);
434  w2 = t1 + t0;
435  w4 = t1 - t0;
436  w5 = w1 + t0 + 0.5 * w;
437  w3 = 1.0 - w1 - w2 - w4 - w5;
438 
439  weights[n][0] = 0.0 - w1;
440  weights[n][1] = w1 - w2;
441  weights[n][2] = w2 - w3;
442  weights[n][3] = w3 - w4;
443  weights[n][4] = w4 - w5;
444  weights[n][5] = w5;
445  }
446  break;
447 
448  default:
449  // SplineOrder not implemented yet.
450  ExceptionObject err(__FILE__, __LINE__);
451  err.SetLocation( ITK_LOCATION );
452  err.SetDescription( "SplineOrder (for derivatives) must be between 1 and 5. Requested spline order has not been implemented yet." );
453  throw err;
454  break;
455  }
456 
457 }
458 
459 
460 // Generates m_PointsToIndex;
461 template <class TImageType, class TCoordRep, class TCoefficientType>
462 void
465 {
466  // m_PointsToIndex is used to convert a sequential location to an N-dimension
467  // index vector. This is precomputed to save time during the interpolation routine.
468  m_PointsToIndex.resize(m_MaxNumberInterpolationPoints);
469  for (unsigned int p = 0; p < m_MaxNumberInterpolationPoints; p++)
470  {
471  int pp = p;
472  unsigned long indexFactor[ImageDimension];
473  indexFactor[0] = 1;
474  for (int j=1; j< static_cast<int>(ImageDimension); j++)
475  {
476  indexFactor[j] = indexFactor[j-1] * ( m_SplineOrder + 1 );
477  }
478  for (int j = (static_cast<int>(ImageDimension) - 1); j >= 0; j--)
479  {
480  m_PointsToIndex[p][j] = pp / indexFactor[j];
481  pp = pp % indexFactor[j];
482  }
483  }
484 }
485 
486 template <class TImageType, class TCoordRep, class TCoefficientType>
487 void
490  const ContinuousIndexType & x,
491  unsigned int splineOrder ) const
492 {
493  long indx;
494 
495 // compute the interpolation indexes
496  for (unsigned int n = 0; n< ImageDimension; n++)
497  {
498  if (splineOrder & 1) // Use this index calculation for odd splineOrder
499  {
500  indx = (long)vcl_floor((float)x[n]) - splineOrder / 2;
501  for (unsigned int k = 0; k <= splineOrder; k++)
502  {
503  evaluateIndex[n][k] = indx++;
504  }
505  }
506  else // Use this index calculation for even splineOrder
507  {
508  indx = (long)vcl_floor((float)(x[n] + 0.5)) - splineOrder / 2;
509  for (unsigned int k = 0; k <= splineOrder; k++)
510  {
511  evaluateIndex[n][k] = indx++;
512  }
513  }
514  }
515 }
516 
517 template <class TImageType, class TCoordRep, class TCoefficientType>
518 void
521  unsigned int splineOrder) const
522 {
523  for (unsigned int n = 0; n < ImageDimension; n++)
524  {
525  long dataLength2 = 2 * m_DataLength[n] - 2;
526 
527  // apply the mirror boundary conditions
528  // TODO: We could implement other boundary options beside mirror
529  if (m_DataLength[n] == 1)
530  {
531  for (unsigned int k = 0; k <= splineOrder; k++)
532  {
533  evaluateIndex[n][k] = 0;
534  }
535  }
536  else
537  {
538  for (unsigned int k = 0; k <= splineOrder; k++)
539  {
540  // btw - Think about this couldn't this be replaced with a more elagent modulus method?
541  evaluateIndex[n][k] = (evaluateIndex[n][k] < 0L) ? (-evaluateIndex[n][k] - dataLength2 * ((-evaluateIndex[n][k]) / dataLength2))
542  : (evaluateIndex[n][k] - dataLength2 * (evaluateIndex[n][k] / dataLength2));
543  if ((long) m_DataLength[n] <= evaluateIndex[n][k])
544  {
545  evaluateIndex[n][k] = dataLength2 - evaluateIndex[n][k];
546  }
547  }
548  }
549  }
550 }
551 
552 } // namespace itk
553 
554 #endif
555 
556 #endif

Generated at Sat Feb 2 2013 23:30:58 for Orfeo Toolbox with doxygen 1.8.1.1