1 #ifndef _clitkVectorBSplineDecompositionImageFilterWithOBD_txx
2 #define _clitkVectorBSplineDecompositionImageFilterWithOBD_txx
3 #include "clitkVectorBSplineDecompositionImageFilterWithOBD.h"
4 #include "itkImageRegionConstIteratorWithIndex.h"
5 #include "itkImageRegionIterator.h"
6 #include "itkProgressReporter.h"
15 template <class TInputImage, class TOutputImage>
16 VectorBSplineDecompositionImageFilterWithOBD<TInputImage, TOutputImage>
17 ::VectorBSplineDecompositionImageFilterWithOBD()
21 m_Tolerance = 1e-10; // Need some guidance on this one...what is reasonable?
22 m_IteratorDirection = 0;
23 this->SetSplineOrder(SplineOrder);
28 * Standard "PrintSelf" method
30 template <class TInputImage, class TOutputImage>
32 VectorBSplineDecompositionImageFilterWithOBD<TInputImage, TOutputImage>
35 itk::Indent indent) const
37 Superclass::PrintSelf( os, indent );
38 os << indent << "Spline Order: " << m_SplineOrder << std::endl;
43 template <class TInputImage, class TOutputImage>
45 VectorBSplineDecompositionImageFilterWithOBD<TInputImage, TOutputImage>
46 ::DataToCoefficients1D()
49 // See Unser, 1993, Part II, Equation 2.5,
50 // or Unser, 1999, Box 2. for an explaination.
54 if (m_DataLength[m_IteratorDirection] == 1) //Required by mirror boundaries
59 // Compute overall gain
60 for (int k = 0; k < m_NumberOfPoles; k++)
62 // Note for cubic splines lambda = 6
63 c0 = c0 * (1.0 - m_SplinePoles[k]) * (1.0 - 1.0 / m_SplinePoles[k]);
67 for (unsigned int n = 0; n < m_DataLength[m_IteratorDirection]; n++)
72 // loop over all poles
73 for (int k = 0; k < m_NumberOfPoles; k++)
75 // causal initialization
76 this->SetInitialCausalCoefficient(m_SplinePoles[k]);
78 for (unsigned int n = 1; n < m_DataLength[m_IteratorDirection]; n++)
80 m_Scratch[n] += m_SplinePoles[k] * m_Scratch[n - 1];
83 // anticausal initialization
84 this->SetInitialAntiCausalCoefficient(m_SplinePoles[k]);
85 // anticausal recursion
86 for ( int n = m_DataLength[m_IteratorDirection] - 2; 0 <= n; n--)
88 m_Scratch[n] = m_SplinePoles[k] * (m_Scratch[n + 1] - m_Scratch[n]);
96 template <class TInputImage, class TOutputImage>
98 VectorBSplineDecompositionImageFilterWithOBD<TInputImage, TOutputImage>
99 ::SetSplineOrder(unsigned int SplineOrder)
101 if (SplineOrder == m_SplineOrder)
105 m_SplineOrder = SplineOrder;
112 template <class TInputImage, class TOutputImage>
114 VectorBSplineDecompositionImageFilterWithOBD<TInputImage, TOutputImage>
115 ::SetSplineOrders(SizeType SplineOrders)
117 m_SplineOrders=SplineOrders;
120 template <class TInputImage, class TOutputImage>
122 VectorBSplineDecompositionImageFilterWithOBD<TInputImage, TOutputImage>
125 /* See Unser, 1997. Part II, Table I for Pole values */
126 // See also, Handbook of Medical Imaging, Processing and Analysis, Ed. Isaac N. Bankman,
128 switch (m_SplineOrder)
132 m_SplinePoles[0] = vcl_sqrt(3.0) - 2.0;
142 m_SplinePoles[0] = vcl_sqrt(8.0) - 3.0;
146 m_SplinePoles[0] = vcl_sqrt(664.0 - vcl_sqrt(438976.0)) + vcl_sqrt(304.0) - 19.0;
147 m_SplinePoles[1] = vcl_sqrt(664.0 + vcl_sqrt(438976.0)) - vcl_sqrt(304.0) - 19.0;
151 m_SplinePoles[0] = vcl_sqrt(135.0 / 2.0 - vcl_sqrt(17745.0 / 4.0)) + vcl_sqrt(105.0 / 4.0)
153 m_SplinePoles[1] = vcl_sqrt(135.0 / 2.0 + vcl_sqrt(17745.0 / 4.0)) - vcl_sqrt(105.0 / 4.0)
157 // SplineOrder not implemented yet.
158 itk::ExceptionObject err(__FILE__, __LINE__);
159 err.SetLocation( ITK_LOCATION);
160 err.SetDescription( "SplineOrder must be between 0 and 5. Requested spline order has not been implemented yet." );
167 template <class TInputImage, class TOutputImage>
169 VectorBSplineDecompositionImageFilterWithOBD<TInputImage, TOutputImage>
170 ::SetInitialCausalCoefficient(double z)
172 /* begining InitialCausalCoefficient */
173 /* See Unser, 1999, Box 2 for explaination */
175 itk::Vector<double, VectorDimension> sum;
176 double zn, z2n, iz; //sum
177 unsigned long horizon;
179 /* this initialization corresponds to mirror boundaries */
180 horizon = m_DataLength[m_IteratorDirection];
182 if (m_Tolerance > 0.0)
184 horizon = (long)vcl_ceil(log(m_Tolerance) / vcl_log(fabs(z)));
186 if (horizon < m_DataLength[m_IteratorDirection])
188 /* accelerated loop */
189 sum = m_Scratch[0]; // verify this
190 for (unsigned int n = 1; n < horizon; n++)
192 sum += zn * m_Scratch[n];
200 z2n = vcl_pow(z, (double)(m_DataLength[m_IteratorDirection] - 1L));
201 sum = m_Scratch[0] + z2n * m_Scratch[m_DataLength[m_IteratorDirection] - 1L];
203 for (unsigned int n = 1; n <= (m_DataLength[m_IteratorDirection] - 2); n++)
205 sum += (zn + z2n) * m_Scratch[n];
209 m_Scratch[0] = sum / (1.0 - zn * zn);
214 template <class TInputImage, class TOutputImage>
216 VectorBSplineDecompositionImageFilterWithOBD<TInputImage, TOutputImage>
217 ::SetInitialAntiCausalCoefficient(double z)
219 // this initialization corresponds to mirror boundaries
220 /* See Unser, 1999, Box 2 for explaination */
221 // Also see erratum at http://bigwww.epfl.ch/publications/unser9902.html
222 m_Scratch[m_DataLength[m_IteratorDirection] - 1] =
223 (z / (z * z - 1.0)) *
224 (z * m_Scratch[m_DataLength[m_IteratorDirection] - 2] + m_Scratch[m_DataLength[m_IteratorDirection] - 1]);
228 template <class TInputImage, class TOutputImage>
230 VectorBSplineDecompositionImageFilterWithOBD<TInputImage, TOutputImage>
231 ::DataToCoefficientsND()
233 OutputImagePointer output = this->GetOutput();
235 itk::Size<ImageDimension> size = output->GetBufferedRegion().GetSize();
237 unsigned int count = output->GetBufferedRegion().GetNumberOfPixels() / size[0] * ImageDimension;
239 itk::ProgressReporter progress(this, 0, count, 10);
241 // Initialize coeffient array
242 this->CopyImageToImage(); // Coefficients are initialized to the input data
244 for (unsigned int n=0; n < ImageDimension; n++)
246 m_IteratorDirection = n;
247 // Loop through each dimension
249 //JV Set the correct order by dimension!
250 SetSplineOrder(m_SplineOrders[n]);
252 // Initialize iterators
253 OutputLinearIterator CIterator( output, output->GetBufferedRegion() );
254 CIterator.SetDirection( m_IteratorDirection );
255 // For each data vector
256 while ( !CIterator.IsAtEnd() )
258 // Copy coefficients to scratch
259 this->CopyCoefficientsToScratch( CIterator );
262 // Perform 1D BSpline calculations
263 this->DataToCoefficients1D();
265 // Copy scratch back to coefficients.
266 // Brings us back to the end of the line we were working on.
267 CIterator.GoToBeginOfLine();
268 this->CopyScratchToCoefficients( CIterator ); // m_Scratch = m_Image;
269 CIterator.NextLine();
270 progress.CompletedPixel();
277 * Copy the input image into the output image
279 template <class TInputImage, class TOutputImage>
281 VectorBSplineDecompositionImageFilterWithOBD<TInputImage, TOutputImage>
285 typedef itk::ImageRegionConstIteratorWithIndex< TInputImage > InputIterator;
286 typedef itk::ImageRegionIterator< TOutputImage > OutputIterator;
287 typedef typename TOutputImage::PixelType OutputPixelType;
289 InputIterator inIt( this->GetInput(), this->GetInput()->GetBufferedRegion() );
290 OutputIterator outIt( this->GetOutput(), this->GetOutput()->GetBufferedRegion() );
293 outIt = outIt.Begin();
295 while ( !outIt.IsAtEnd() )
297 for (unsigned int i=0; i< VectorDimension;i++)
299 v[i]= static_cast<typename OutputPixelType::ComponentType>( inIt.Get()[i] );
310 * Copy the scratch to one line of the output image
312 template <class TInputImage, class TOutputImage>
314 VectorBSplineDecompositionImageFilterWithOBD<TInputImage, TOutputImage>
315 ::CopyScratchToCoefficients(OutputLinearIterator & Iter)
317 typedef typename TOutputImage::PixelType OutputPixelType;
320 while ( !Iter.IsAtEndOfLine() )
322 for(unsigned int i=0; i<VectorDimension; i++) v[i]=static_cast<typename OutputPixelType::ComponentType>( m_Scratch[j][i]);
332 * Copy one line of the output image to the scratch
334 template <class TInputImage, class TOutputImage>
336 VectorBSplineDecompositionImageFilterWithOBD<TInputImage, TOutputImage>
337 ::CopyCoefficientsToScratch(OutputLinearIterator & Iter)
340 itk::Vector<double, VectorDimension> v;
341 while ( !Iter.IsAtEndOfLine() )
343 for(unsigned int i=0; i<VectorDimension; i++)v[i]=static_cast<double>( Iter.Get()[i] );
352 * GenerateInputRequestedRegion method.
354 template <class TInputImage, class TOutputImage>
356 VectorBSplineDecompositionImageFilterWithOBD<TInputImage, TOutputImage>
357 ::GenerateInputRequestedRegion()
359 // this filter requires the all of the input image to be in
361 InputImagePointer inputPtr = const_cast< TInputImage * > ( this->GetInput() );
364 inputPtr->SetRequestedRegionToLargestPossibleRegion();
370 * EnlargeOutputRequestedRegion method.
372 template <class TInputImage, class TOutputImage>
374 VectorBSplineDecompositionImageFilterWithOBD<TInputImage, TOutputImage>
375 ::EnlargeOutputRequestedRegion( itk::DataObject *output )
378 // this filter requires the all of the output image to be in
380 TOutputImage *imgData;
381 imgData = dynamic_cast<TOutputImage*>( output );
384 imgData->SetRequestedRegionToLargestPossibleRegion();
392 template <class TInputImage, class TOutputImage>
394 VectorBSplineDecompositionImageFilterWithOBD<TInputImage, TOutputImage>
397 DD("VectorBSplineDecompositionImageFilterWithOBD GenerateData()");
398 // Allocate scratch memory
399 InputImageConstPointer inputPtr = this->GetInput();
400 m_DataLength = inputPtr->GetBufferedRegion().GetSize();
402 unsigned long maxLength = 0;
403 for ( unsigned int n = 0; n < ImageDimension; n++ )
405 if ( m_DataLength[n] > maxLength )
407 maxLength = m_DataLength[n];
410 m_Scratch.resize( maxLength );
412 // Allocate memory for output image
413 OutputImagePointer outputPtr = this->GetOutput();
414 outputPtr->SetBufferedRegion( outputPtr->GetRequestedRegion() );
415 outputPtr->Allocate();
417 // Calculate actual output
418 this->DataToCoefficientsND();