1 #ifndef _clitkVectorBSplineDecompositionImageFilter_txx
2 #define _clitkVectorBSplineDecompositionImageFilter_txx
4 #include "clitkVectorBSplineDecompositionImageFilter.h"
5 #include "itkImageRegionConstIteratorWithIndex.h"
6 #include "itkImageRegionIterator.h"
7 #include "itkProgressReporter.h"
16 template <class TInputImage, class TOutputImage>
17 VectorBSplineDecompositionImageFilter<TInputImage, TOutputImage>
18 ::VectorBSplineDecompositionImageFilter()
22 m_Tolerance = 1e-10; // Need some guidance on this one...what is reasonable?
23 m_IteratorDirection = 0;
24 this->SetSplineOrder(SplineOrder);
29 * Standard "PrintSelf" method
31 template <class TInputImage, class TOutputImage>
33 VectorBSplineDecompositionImageFilter<TInputImage, TOutputImage>
36 itk::Indent indent) const
38 Superclass::PrintSelf( os, indent );
39 os << indent << "Spline Order: " << m_SplineOrder << std::endl;
44 template <class TInputImage, class TOutputImage>
46 VectorBSplineDecompositionImageFilter<TInputImage, TOutputImage>
47 ::DataToCoefficients1D()
50 // See Unser, 1993, Part II, Equation 2.5,
51 // or Unser, 1999, Box 2. for an explaination.
55 if (m_DataLength[m_IteratorDirection] == 1) //Required by mirror boundaries
60 // Compute overall gain
61 for (int k = 0; k < m_NumberOfPoles; k++)
63 // Note for cubic splines lambda = 6
64 c0 = c0 * (1.0 - m_SplinePoles[k]) * (1.0 - 1.0 / m_SplinePoles[k]);
68 for (unsigned int n = 0; n < m_DataLength[m_IteratorDirection]; n++)
73 // loop over all poles
74 for (int k = 0; k < m_NumberOfPoles; k++)
76 // causal initialization
77 this->SetInitialCausalCoefficient(m_SplinePoles[k]);
79 for (unsigned int n = 1; n < m_DataLength[m_IteratorDirection]; n++)
81 m_Scratch[n] += m_SplinePoles[k] * m_Scratch[n - 1];
84 // anticausal initialization
85 this->SetInitialAntiCausalCoefficient(m_SplinePoles[k]);
86 // anticausal recursion
87 for ( int n = m_DataLength[m_IteratorDirection] - 2; 0 <= n; n--)
89 m_Scratch[n] = m_SplinePoles[k] * (m_Scratch[n + 1] - m_Scratch[n]);
97 template <class TInputImage, class TOutputImage>
99 VectorBSplineDecompositionImageFilter<TInputImage, TOutputImage>
100 ::SetSplineOrder(unsigned int SplineOrder)
102 if (SplineOrder == m_SplineOrder)
106 m_SplineOrder = SplineOrder;
113 template <class TInputImage, class TOutputImage>
115 VectorBSplineDecompositionImageFilter<TInputImage, TOutputImage>
118 /* See Unser, 1997. Part II, Table I for Pole values */
119 // See also, Handbook of Medical Imaging, Processing and Analysis, Ed. Isaac N. Bankman,
121 switch (m_SplineOrder)
125 m_SplinePoles[0] = vcl_sqrt(3.0) - 2.0;
135 m_SplinePoles[0] = vcl_sqrt(8.0) - 3.0;
139 m_SplinePoles[0] = vcl_sqrt(664.0 - vcl_sqrt(438976.0)) + vcl_sqrt(304.0) - 19.0;
140 m_SplinePoles[1] = vcl_sqrt(664.0 + vcl_sqrt(438976.0)) - vcl_sqrt(304.0) - 19.0;
144 m_SplinePoles[0] = vcl_sqrt(135.0 / 2.0 - vcl_sqrt(17745.0 / 4.0)) + vcl_sqrt(105.0 / 4.0)
146 m_SplinePoles[1] = vcl_sqrt(135.0 / 2.0 + vcl_sqrt(17745.0 / 4.0)) - vcl_sqrt(105.0 / 4.0)
150 // SplineOrder not implemented yet.
151 itk::ExceptionObject err(__FILE__, __LINE__);
152 err.SetLocation( ITK_LOCATION);
153 err.SetDescription( "SplineOrder must be between 0 and 5. Requested spline order has not been implemented yet." );
160 template <class TInputImage, class TOutputImage>
162 VectorBSplineDecompositionImageFilter<TInputImage, TOutputImage>
163 ::SetInitialCausalCoefficient(double z)
165 /* begining InitialCausalCoefficient */
166 /* See Unser, 1999, Box 2 for explaination */
168 itk::Vector<double, VectorDimension> sum;
169 double zn, z2n, iz; //sum
170 unsigned long horizon;
172 /* this initialization corresponds to mirror boundaries */
173 horizon = m_DataLength[m_IteratorDirection];
175 if (m_Tolerance > 0.0)
177 horizon = (long)vcl_ceil(log(m_Tolerance) / vcl_log(fabs(z)));
179 if (horizon < m_DataLength[m_IteratorDirection])
181 /* accelerated loop */
182 sum = m_Scratch[0]; // verify this
183 for (unsigned int n = 1; n < horizon; n++)
185 sum += zn * m_Scratch[n];
193 z2n = vcl_pow(z, (double)(m_DataLength[m_IteratorDirection] - 1L));
194 sum = m_Scratch[0] + z2n * m_Scratch[m_DataLength[m_IteratorDirection] - 1L];
196 for (unsigned int n = 1; n <= (m_DataLength[m_IteratorDirection] - 2); n++)
198 sum += (zn + z2n) * m_Scratch[n];
202 m_Scratch[0] = sum / (1.0 - zn * zn);
207 template <class TInputImage, class TOutputImage>
209 VectorBSplineDecompositionImageFilter<TInputImage, TOutputImage>
210 ::SetInitialAntiCausalCoefficient(double z)
212 // this initialization corresponds to mirror boundaries
213 /* See Unser, 1999, Box 2 for explaination */
214 // Also see erratum at http://bigwww.epfl.ch/publications/unser9902.html
215 m_Scratch[m_DataLength[m_IteratorDirection] - 1] =
216 (z / (z * z - 1.0)) *
217 (z * m_Scratch[m_DataLength[m_IteratorDirection] - 2] + m_Scratch[m_DataLength[m_IteratorDirection] - 1]);
221 template <class TInputImage, class TOutputImage>
223 VectorBSplineDecompositionImageFilter<TInputImage, TOutputImage>
224 ::DataToCoefficientsND()
226 OutputImagePointer output = this->GetOutput();
228 itk::Size<ImageDimension> size = output->GetBufferedRegion().GetSize();
230 unsigned int count = output->GetBufferedRegion().GetNumberOfPixels() / size[0] * ImageDimension;
232 itk::ProgressReporter progress(this, 0, count, 10);
234 // Initialize coeffient array
235 this->CopyImageToImage(); // Coefficients are initialized to the input data
237 for (unsigned int n=0; n < ImageDimension; n++)
239 m_IteratorDirection = n;
240 // Loop through each dimension
242 // Initialize iterators
243 OutputLinearIterator CIterator( output, output->GetBufferedRegion() );
244 CIterator.SetDirection( m_IteratorDirection );
245 // For each data vector
246 while ( !CIterator.IsAtEnd() )
248 // Copy coefficients to scratch
249 this->CopyCoefficientsToScratch( CIterator );
252 // Perform 1D BSpline calculations
253 this->DataToCoefficients1D();
255 // Copy scratch back to coefficients.
256 // Brings us back to the end of the line we were working on.
257 CIterator.GoToBeginOfLine();
258 this->CopyScratchToCoefficients( CIterator ); // m_Scratch = m_Image;
259 CIterator.NextLine();
260 progress.CompletedPixel();
267 * Copy the input image into the output image
269 template <class TInputImage, class TOutputImage>
271 VectorBSplineDecompositionImageFilter<TInputImage, TOutputImage>
275 typedef itk::ImageRegionConstIteratorWithIndex< TInputImage > InputIterator;
276 typedef itk::ImageRegionIterator< TOutputImage > OutputIterator;
277 typedef typename TOutputImage::PixelType OutputPixelType;
279 InputIterator inIt( this->GetInput(), this->GetInput()->GetBufferedRegion() );
280 OutputIterator outIt( this->GetOutput(), this->GetOutput()->GetBufferedRegion() );
283 outIt = outIt.Begin();
285 while ( !outIt.IsAtEnd() )
287 for (unsigned int i=0; i< VectorDimension;i++)
289 v[i]= static_cast<typename OutputPixelType::ComponentType>( inIt.Get()[i] );
300 * Copy the scratch to one line of the output image
302 template <class TInputImage, class TOutputImage>
304 VectorBSplineDecompositionImageFilter<TInputImage, TOutputImage>
305 ::CopyScratchToCoefficients(OutputLinearIterator & Iter)
307 typedef typename TOutputImage::PixelType OutputPixelType;
310 while ( !Iter.IsAtEndOfLine() )
312 for(unsigned int i=0; i<VectorDimension; i++) v[i]=static_cast<typename OutputPixelType::ComponentType>( m_Scratch[j][i]);
322 * Copy one line of the output image to the scratch
324 template <class TInputImage, class TOutputImage>
326 VectorBSplineDecompositionImageFilter<TInputImage, TOutputImage>
327 ::CopyCoefficientsToScratch(OutputLinearIterator & Iter)
330 itk::Vector<double, VectorDimension> v;
331 while ( !Iter.IsAtEndOfLine() )
333 for(unsigned int i=0; i<VectorDimension; i++)v[i]=static_cast<double>( Iter.Get()[i] );
342 * GenerateInputRequestedRegion method.
344 template <class TInputImage, class TOutputImage>
346 VectorBSplineDecompositionImageFilter<TInputImage, TOutputImage>
347 ::GenerateInputRequestedRegion()
349 // this filter requires the all of the input image to be in
351 InputImagePointer inputPtr = const_cast< TInputImage * > ( this->GetInput() );
354 inputPtr->SetRequestedRegionToLargestPossibleRegion();
360 * EnlargeOutputRequestedRegion method.
362 template <class TInputImage, class TOutputImage>
364 VectorBSplineDecompositionImageFilter<TInputImage, TOutputImage>
365 ::EnlargeOutputRequestedRegion( itk::DataObject *output )
368 // this filter requires the all of the output image to be in
370 TOutputImage *imgData;
371 imgData = dynamic_cast<TOutputImage*>( output );
374 imgData->SetRequestedRegionToLargestPossibleRegion();
382 template <class TInputImage, class TOutputImage>
384 VectorBSplineDecompositionImageFilter<TInputImage, TOutputImage>
387 DD("VectorBSplineDecompositionImageFilter GenerateData()");
388 // Allocate scratch memory
389 InputImageConstPointer inputPtr = this->GetInput();
390 m_DataLength = inputPtr->GetBufferedRegion().GetSize();
392 unsigned long maxLength = 0;
393 for ( unsigned int n = 0; n < ImageDimension; n++ )
395 if ( m_DataLength[n] > maxLength )
397 maxLength = m_DataLength[n];
400 m_Scratch.resize( maxLength );
402 // Allocate memory for output image
403 OutputImagePointer outputPtr = this->GetOutput();
404 outputPtr->SetBufferedRegion( outputPtr->GetRequestedRegion() );
405 outputPtr->Allocate();
407 // Calculate actual output
408 this->DataToCoefficientsND();