]> Creatis software - clitk.git/blob - itk/clitkResampleImageWithOptionsFilter.txx
87f34ddccaa1c81a58ccfc3721643ebae0c8d18c
[clitk.git] / itk / clitkResampleImageWithOptionsFilter.txx
1 /*=========================================================================
2   Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
3
4   Authors belong to: 
5   - University of LYON              http://www.universite-lyon.fr/
6   - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
7   - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
8
9   This software is distributed WITHOUT ANY WARRANTY; without even
10   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11   PURPOSE.  See the copyright notices for more information.
12
13   It is distributed under dual licence
14
15   - BSD        See included LICENSE.txt file
16   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17   ======================================================================-====*/
18
19 // clitk
20 #include "clitkCommon.h"
21
22 // itk include
23 #include "itkImage.h"
24 #include "itkImageFileReader.h"
25 #include "itkImageSeriesReader.h"
26 #include "itkImageFileWriter.h"
27 #include "itkRecursiveGaussianImageFilter.h"
28 #include "itkResampleImageFilter.h"
29 #include "itkAffineTransform.h"
30 #include "itkNearestNeighborInterpolateImageFunction.h"
31 #include "itkLinearInterpolateImageFunction.h"
32 #include "itkBSplineInterpolateImageFunction.h"
33 #include "itkBSplineInterpolateImageFunctionWithLUT.h"
34 #include "itkCommand.h"
35
36 namespace clitk {
37
38   //--------------------------------------------------------------------
39   template <class TInputImage, class TOutputImage>
40   ResampleImageWithOptionsFilter<TInputImage, TOutputImage>::
41   ResampleImageWithOptionsFilter():itk::ImageToImageFilter<TInputImage, TOutputImage>() {
42     static const unsigned int dim = InputImageType::ImageDimension;
43     this->SetNumberOfRequiredInputs(1);
44     m_IsoSpacing = -1;
45     m_InterpolationType = NearestNeighbor;
46     m_GaussianFilteringEnabled = true;
47     m_BSplineOrder = 3;
48     m_BLUTSamplingFactor = 20;
49     m_LastDimensionIsTime = false;
50     m_Transform =  TransformType::New();
51     if (dim == 4) m_LastDimensionIsTime = true; // by default 4D is 3D+t
52     for(unsigned int i=0; i<dim; i++) {
53       m_OutputSize[i] = 0;
54       m_OutputSpacing[i] = -1;
55       m_GaussianSigma[i] = -1;
56     }
57     m_VerboseOptions = false;
58   }
59   //--------------------------------------------------------------------
60
61
62   //--------------------------------------------------------------------
63   template <class TInputImage, class TOutputImage>
64   void 
65   ResampleImageWithOptionsFilter<TInputImage, TOutputImage>::
66   SetInput(const InputImageType * image) {
67     // Process object is not const-correct so the const casting is required.
68     this->SetNthInput(0, const_cast<InputImageType *>(image));
69   }
70   //--------------------------------------------------------------------
71   
72
73   //--------------------------------------------------------------------
74   template <class TInputImage, class TOutputImage>
75   void 
76   ResampleImageWithOptionsFilter<TInputImage, TOutputImage>::
77   GenerateInputRequestedRegion() {
78     // call the superclass's implementation of this method
79     Superclass::GenerateInputRequestedRegion();
80     
81     // get pointers to the input and output
82     InputImagePointer  inputPtr  = 
83       const_cast< TInputImage *>( this->GetInput() );
84     
85     // Request the entire input image
86     InputImageRegionType inputRegion;
87     inputRegion = inputPtr->GetLargestPossibleRegion();
88     inputPtr->SetRequestedRegion(inputRegion);
89    }
90   //--------------------------------------------------------------------
91
92
93   //--------------------------------------------------------------------
94   template <class TInputImage, class TOutputImage>
95   void 
96   ResampleImageWithOptionsFilter<TInputImage, TOutputImage>::
97   GenerateOutputInformation() { 
98     static const unsigned int dim = InputImageType::ImageDimension;
99
100     // Warning
101     if (!std::numeric_limits<InputImagePixelType>::is_signed) {
102       if ((m_InterpolationType == BSpline) || 
103           (m_InterpolationType == B_LUT)) {
104         std::cerr << "Warning : input pixel type is not signed, use bspline interpolation at your own risk ..." << std::endl;
105       }
106     }
107
108     // Get input pointer
109     InputImagePointer input = dynamic_cast<InputImageType*>(itk::ProcessObject::GetInput(0));
110      
111     // Perform default implementation
112     Superclass::GenerateOutputInformation();
113
114     // Compute sizes 
115     InputImageSpacingType inputSpacing = input->GetSpacing();
116     InputImageSizeType inputSize = input->GetLargestPossibleRegion().GetSize();
117
118     if (m_IsoSpacing != -1) { // apply isoSpacing
119       for(unsigned int i=0; i<dim; i++) {
120         m_OutputSpacing[i] = m_IsoSpacing;
121         m_OutputSize[i] = (int)lrint(inputSize[i]*inputSpacing[i]/m_OutputSpacing[i]);
122       }
123     }
124     else {
125       if (m_OutputSpacing[0] != -1) { // apply spacing, compute size
126         for(unsigned int i=0; i<dim; i++) {
127           m_OutputSize[i] = (int)lrint(inputSize[i]*inputSpacing[i]/m_OutputSpacing[i]);
128         }
129       }
130       else {
131         if (m_OutputSize[0] != 0) { // apply size, compute spacing
132           for(unsigned int i=0; i<dim; i++) {
133             m_OutputSpacing[i] = (double)inputSize[i]*inputSpacing[i]/(double)m_OutputSize[i];
134           }
135         }
136         else { // copy input size/spacing ... (no resampling)
137           m_OutputSize = inputSize;
138           m_OutputSpacing = inputSpacing;
139         }
140       }
141     }
142
143     // Special case for temporal image 2D+t or 3D+t
144     if (m_LastDimensionIsTime) {
145       int l = dim-1;
146       m_OutputSize[l] = inputSize[l];
147       m_OutputSpacing[l] = inputSpacing[l];
148     }
149     
150     // Set Size/Spacing
151     OutputImagePointer outputImage = this->GetOutput(0);
152     OutputImageRegionType region;
153     region.SetSize(m_OutputSize);
154     region.SetIndex(input->GetLargestPossibleRegion().GetIndex());
155     outputImage->SetLargestPossibleRegion(region);
156
157     // Init Gaussian sigma
158     if (m_GaussianSigma[0] != -1) { // Gaussian filter set by user
159       m_GaussianFilteringEnabled = true;
160     }
161     else {
162       if (m_GaussianFilteringEnabled) { // Automated sigma when downsample
163         for(unsigned int i=0; i<dim; i++) {
164           if (m_OutputSpacing[i] > inputSpacing[i]) { // downsample
165             m_GaussianSigma[i] = 0.5*m_OutputSpacing[i];// / inputSpacing[i]);
166           }
167           else m_GaussianSigma[i] = 0; // will be ignore after
168         }
169       }
170     }
171     if (m_GaussianFilteringEnabled && m_LastDimensionIsTime) {
172       m_GaussianSigma[dim-1] = 0;
173     }
174   }
175   //--------------------------------------------------------------------
176
177
178   //--------------------------------------------------------------------
179    template <class TInputImage, class TOutputImage>
180   void 
181   ResampleImageWithOptionsFilter<TInputImage, TOutputImage>::
182   GenerateData() {
183    
184     // Get input pointer
185     InputImagePointer input = dynamic_cast<InputImageType*>(itk::ProcessObject::GetInput(0));
186     static const unsigned int dim = InputImageType::ImageDimension;
187
188      // Create main Resample Image Filter
189     typedef itk::ResampleImageFilter<InputImageType,OutputImageType> FilterType;
190     typename FilterType::Pointer filter = FilterType::New();
191     filter->GraftOutput(this->GetOutput());
192
193     // Print options if needed
194     if (m_VerboseOptions) {
195       std::cout << "Output Spacing = " << m_OutputSpacing << std::endl
196                 << "Output Size    = " << m_OutputSize << std::endl
197                 << "Gaussian       = " << m_GaussianFilteringEnabled << std::endl;
198       if (m_GaussianFilteringEnabled) 
199         std::cout << "Sigma          = " << m_GaussianSigma << std::endl;
200       std::cout << "Interpol       = ";
201       switch (m_InterpolationType) {
202       case NearestNeighbor: std::cout << "NearestNeighbor" << std::endl; break;
203       case Linear:          std::cout << "Linear" << std::endl; break;
204       case BSpline:         std::cout << "BSpline " << m_BSplineOrder << std::endl; break;
205       case B_LUT:           std::cout << "B-LUT " << m_BSplineOrder << " " << m_BLUTSamplingFactor << std::endl; break;
206       }
207       std::cout << "Threads        = " << this->GetNumberOfThreads() << std::endl;
208       std::cout << "LastDimIsTime  = " << m_LastDimensionIsTime << std::endl;
209     }
210
211     // Instance of the transform object to be passed to the resample
212     // filter. By default, identity transform is applied
213     filter->SetTransform(m_Transform);
214     filter->SetSize(m_OutputSize);
215     filter->SetOutputSpacing(m_OutputSpacing);
216     filter->SetOutputOrigin(input->GetOrigin());
217     filter->SetDefaultPixelValue(m_DefaultPixelValue);
218     filter->SetNumberOfThreads(this->GetNumberOfThreads()); 
219
220     // Select interpolator
221     switch (m_InterpolationType) {
222     case NearestNeighbor: 
223       {
224         typedef itk::NearestNeighborInterpolateImageFunction<InputImageType, double> InterpolatorType;     
225         typename InterpolatorType::Pointer interpolator = InterpolatorType::New();
226         filter->SetInterpolator(interpolator);
227         break;
228       }
229     case Linear: 
230       {
231         typedef itk::LinearInterpolateImageFunction<InputImageType, double> InterpolatorType;     
232         typename InterpolatorType::Pointer interpolator =  InterpolatorType::New();
233         filter->SetInterpolator(interpolator);
234         break;
235       }
236     case BSpline: 
237       {
238         typedef itk::BSplineInterpolateImageFunction<InputImageType, double> InterpolatorType; 
239         typename InterpolatorType::Pointer interpolator = InterpolatorType::New();
240         interpolator->SetSplineOrder(m_BSplineOrder);
241         filter->SetInterpolator(interpolator);
242       break;
243       }
244     case B_LUT: 
245       {
246         typedef itk::BSplineInterpolateImageFunctionWithLUT<InputImageType, double> InterpolatorType; 
247         typename InterpolatorType::Pointer interpolator = InterpolatorType::New();
248         interpolator->SetSplineOrder(m_BSplineOrder);
249         interpolator->SetLUTSamplingFactor(m_BLUTSamplingFactor);
250         filter->SetInterpolator(interpolator);
251         break;
252       }
253     }
254     
255     // Initial Gaussian blurring if needed
256     typedef itk::RecursiveGaussianImageFilter<InputImageType, InputImageType> GaussianFilterType;
257     std::vector<typename GaussianFilterType::Pointer> gaussianFilters;
258     if (m_GaussianFilteringEnabled) {
259       for(unsigned int i=0; i<dim; i++) {
260         if (m_GaussianSigma[i] != 0) {
261           gaussianFilters.push_back(GaussianFilterType::New());
262           gaussianFilters[i]->SetDirection(i);
263           gaussianFilters[i]->SetOrder(GaussianFilterType::ZeroOrder);
264           gaussianFilters[i]->SetNormalizeAcrossScale(false);
265           gaussianFilters[i]->SetSigma(m_GaussianSigma[i]); // in millimeter !
266           if (gaussianFilters.size() == 1) { // first
267             gaussianFilters[0]->SetInput(input);
268           }
269           else {
270             gaussianFilters[i]->SetInput(gaussianFilters[i-1]->GetOutput());
271           }
272         }
273       }
274       if (gaussianFilters.size() > 0) {
275         filter->SetInput(gaussianFilters[gaussianFilters.size()-1]->GetOutput());
276       }
277       else filter->SetInput(input);
278     }
279     else filter->SetInput(input);
280
281     // Go ! 
282     filter->Update();
283     
284     // Set output
285     this->GraftOutput(filter->GetOutput());
286   }
287   //--------------------------------------------------------------------
288   
289 }//end clitk
290