]> Creatis software - clitk.git/blob - filters/clitkImageArithmGenericFilter.txx
- correct bug: string pixeltype is different in ITK and VTK
[clitk.git] / filters / clitkImageArithmGenericFilter.txx
1 /*-------------------------------------------------------------------------
2                                                                                 
3   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
4   l'Image). All rights reserved. See Doc/License.txt or
5   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
6                                                                                 
7   This software is distributed WITHOUT ANY WARRANTY; without even
8   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
9   PURPOSE.  See the above copyright notices for more information.
10                                                                              
11   -------------------------------------------------------------------------*/
12
13 #ifndef CLITKIMAGEARITHMGENERICFILTER_TXX
14 #define CLITKIMAGEARITHMGENERICFILTER_TXX
15
16 namespace clitk
17 {
18   
19   //--------------------------------------------------------------------
20   template<class args_info_type>
21   ImageArithmGenericFilter<args_info_type>::ImageArithmGenericFilter()
22     :ImageToImageGenericFilter<Self>("ImageArithmGenericFilter"),mTypeOfOperation(0) {
23     InitializeImageType<2>();
24     InitializeImageType<3>();
25     InitializeImageType<4>();  
26     mIsOperationUseASecondImage = false;
27     mOverwriteInputImage = true;
28   }
29   //--------------------------------------------------------------------
30
31
32   //--------------------------------------------------------------------
33   template<class args_info_type>
34   template<unsigned int Dim>
35   void ImageArithmGenericFilter<args_info_type>::InitializeImageType() {      
36     ADD_IMAGE_TYPE(Dim, char);
37     ADD_IMAGE_TYPE(Dim, uchar);
38     ADD_IMAGE_TYPE(Dim, short);
39     ADD_IMAGE_TYPE(Dim, float);
40   }
41   //--------------------------------------------------------------------
42
43
44   //--------------------------------------------------------------------
45   template<class args_info_type>
46   void ImageArithmGenericFilter<args_info_type>::EnableOverwriteInputImage(bool b) {      
47     mOverwriteInputImage = b;
48   }
49   //--------------------------------------------------------------------
50
51
52   //--------------------------------------------------------------------
53   template<class args_info_type>
54   void ImageArithmGenericFilter<args_info_type>::SetArgsInfo(const args_info_type & a) {
55     mArgsInfo=a;
56
57     // Set value
58     SetIOVerbose(mArgsInfo.verbose_flag);
59     mTypeOfOperation = mArgsInfo.operation_arg;
60     mDefaultPixelValue = mArgsInfo.pixelValue_arg;
61     mScalar = mArgsInfo.scalar_arg;
62     mOutputIsFloat = mArgsInfo.setFloatOutput_flag;
63
64     if (mArgsInfo.imagetypes_flag) this->PrintAvailableImageTypes();
65
66     if (mArgsInfo.input1_given) AddInputFilename(mArgsInfo.input1_arg);
67     if (mArgsInfo.input2_given) {
68       mIsOperationUseASecondImage = true;
69       AddInputFilename(mArgsInfo.input2_arg);
70     }
71     
72     if (mArgsInfo.output_given) SetOutputFilename(mArgsInfo.output_arg);
73
74     // Check type of operation (with scalar or with other image)
75     if ((mArgsInfo.input2_given) && (mArgsInfo.scalar_given)) {
76       std::cerr << "ERROR : you cannot provide both --scalar and --input2 option" << std::endl;
77       exit(-1);
78     }
79     if ((!mArgsInfo.input2_given) && (!mArgsInfo.scalar_given)) {
80       if (mArgsInfo.operation_arg < 5) {
81         std::cerr << "Such operation need the --scalar option." << std::endl;
82         exit(-1);
83       }
84     }
85   }
86   //--------------------------------------------------------------------
87
88
89   //--------------------------------------------------------------------
90   template<class args_info_type>
91   template<class ImageType>
92   void ImageArithmGenericFilter<args_info_type>::UpdateWithInputImageType() {
93     // Read input1
94     typename ImageType::Pointer input1 = this->template GetInput<ImageType>(0);
95     typename ImageType::PixelType PixelType;
96
97     // Set input image iterator
98     typedef itk::ImageRegionIterator<ImageType> IteratorType;
99     IteratorType it(input1, input1->GetLargestPossibleRegion());
100
101     // typedef input2
102     typename ImageType::Pointer input2 = this->template GetInput<ImageType>(1);
103     IteratorType it2;
104
105     if (mIsOperationUseASecondImage) {
106       // Read input2
107       input2 = this->template GetInput<ImageType>(1);
108       // Set input image iterator
109       it2 = IteratorType(input2, input2->GetLargestPossibleRegion());  
110     }
111
112     // Check if overwrite and outputisfloat and pixeltype is not float -> do not overwrite
113     if (mOverwriteInputImage && mOutputIsFloat && (typeid(PixelType) != typeid(float))) {
114       // std::cerr << "Warning. Could not use both mOverwriteInputImage and mOutputIsFloat, because input is " 
115       //                     << typeid(PixelType).name()
116       //                     << std::endl;
117       mOverwriteInputImage = false;
118     }
119
120     // ---------------- Overwrite input Image ---------------------
121     if (mOverwriteInputImage) {
122       // Set output iterator (to input1)
123       IteratorType ito = IteratorType(input1, input1->GetLargestPossibleRegion());
124       if (mIsOperationUseASecondImage) ComputeImage(it, it2, ito);
125       else ComputeImage(it, ito);
126       this->template SetNextOutput<ImageType>(input1);
127     }
128     
129     // ---------------- Create new output Image ---------------------
130     else {
131       if (mOutputIsFloat) {
132         // Create output image
133         typedef itk::Image<float,ImageType::ImageDimension> OutputImageType;
134         typename OutputImageType::Pointer output = OutputImageType::New();
135         output->SetRegions(input1->GetLargestPossibleRegion());
136         output->SetOrigin(input1->GetOrigin());
137         output->SetSpacing(input1->GetSpacing());
138         output->Allocate();
139         // Set output iterator
140         typedef itk::ImageRegionIterator<OutputImageType> IteratorOutputType;
141         IteratorOutputType ito = IteratorOutputType(output, output->GetLargestPossibleRegion());
142         if (mIsOperationUseASecondImage) ComputeImage(it, it2, ito);
143         else ComputeImage(it, ito);
144         this->template SetNextOutput<OutputImageType>(output);
145       }
146       else {
147         // Create output image
148         typedef ImageType OutputImageType;
149         typename OutputImageType::Pointer output = OutputImageType::New();
150         output->SetRegions(input1->GetLargestPossibleRegion());
151         output->SetOrigin(input1->GetOrigin());
152         output->SetSpacing(input1->GetSpacing());
153         output->Allocate();
154         // Set output iterator
155         typedef itk::ImageRegionIterator<OutputImageType> IteratorOutputType;
156         IteratorOutputType ito = IteratorOutputType(output, output->GetLargestPossibleRegion());
157         if (mIsOperationUseASecondImage) ComputeImage(it, it2, ito);
158         else ComputeImage(it, ito);
159         this->template SetNextOutput<OutputImageType>(output);
160       }
161     }
162   }
163   //--------------------------------------------------------------------
164
165   //--------------------------------------------------------------------
166   template<class args_info_type>
167   template<class Iter1, class Iter2, class Iter3>
168   void  ImageArithmGenericFilter<args_info_type>::ComputeImage(Iter1 it1, Iter2 it2, Iter3 ito) {
169     it1.GoToBegin();  
170     it2.GoToBegin();  
171     ito.GoToBegin();
172     typedef typename Iter3::PixelType PixelType;
173     
174     switch (mTypeOfOperation) {
175     case 0: // Addition
176       while (!ito.IsAtEnd()) {
177         ito.Set(PixelTypeDownCast<double, PixelType>((double)it1.Get() + (double)it2.Get()) ); 
178         ++it1; ++it2; ++ito;
179       }
180       break;
181     case 1: // Multiply
182       while (!ito.IsAtEnd()) {
183         ito.Set(PixelTypeDownCast<double, PixelType>((double)it1.Get() * (double)it2.Get()) ); 
184         ++it1; ++it2; ++ito;
185       }
186       break;
187     case 2: // Divide
188       while (!ito.IsAtEnd()) {
189         if (it1.Get() != 0)
190           ito.Set(PixelTypeDownCast<double, PixelType>((double)it1.Get() / (double)it2.Get())); 
191         else ito.Set(mDefaultPixelValue);
192         ++it1; ++it2; ++ito;
193       }
194       break;
195     case 3: // Max 
196       while (!ito.IsAtEnd()) {
197         if (it1.Get() < it2.Get()) ito.Set(PixelTypeDownCast<double, PixelType>(it2.Get())); 
198         ++it1; ++it2; ++ito;
199       }
200       break;
201     case 4: // Min
202       while (!ito.IsAtEnd()) {
203         if (it1.Get() > it2.Get()) ito.Set(PixelTypeDownCast<double, PixelType>(it2.Get())); 
204         ++it1; ++it2; ++ito;
205       }
206       break;
207     case 5: // Absolute difference
208       while (!ito.IsAtEnd()) {
209         ito.Set(PixelTypeDownCast<double, PixelType>(fabs(it2.Get()-it1.Get()))); 
210         ++it1; ++it2; ++ito;
211       }
212       break;
213     case 6: // Squared differences
214       while (!ito.IsAtEnd()) {
215         ito.Set(PixelTypeDownCast<double, PixelType>(pow((double)it1.Get()-(double)it2.Get(),2))); 
216         ++it1; ++it2; ++ito;
217       }
218       break;
219     case 7: // Difference
220       while (!ito.IsAtEnd()) {
221         ito.Set(PixelTypeDownCast<double, PixelType>((double)it1.Get()-(double)it2.Get())); 
222         ++it1; ++it2; ++ito;
223       }
224       break;
225     case 8: // Relative Difference
226       while (!ito.IsAtEnd()) {
227         if (it1.Get() != 0) ito.Set(PixelTypeDownCast<double, PixelType>(((double)it1.Get()-(double)it2.Get()))/(double)it1.Get()); 
228         else ito.Set(0.0);
229         ++it1; ++it2; ++ito;
230       }
231       break;
232     default: // error ?
233       std::cerr << "ERROR : the operation number (" << mTypeOfOperation << ") is not known." << std::endl;
234       exit(-1);
235     }
236   }
237   //--------------------------------------------------------------------
238
239
240   //--------------------------------------------------------------------
241   template<class args_info_type>
242   template<class Iter1, class Iter2>
243   void clitk::ImageArithmGenericFilter<args_info_type>::ComputeImage(Iter1 it, Iter2 ito) {
244     ito.GoToBegin();
245     it.GoToBegin();  
246     typedef typename Iter2::PixelType PixelType;
247
248     // Perform operation
249     switch (mTypeOfOperation) {
250     case 0: // Addition
251       while (!it.IsAtEnd()) {
252         ito.Set(clitk::PixelTypeDownCast<double, PixelType>((double)it.Get() + mScalar) ); 
253         ++it; ++ito;
254       }
255       break;
256     case 1: // Multiply
257       while (!it.IsAtEnd()) {
258         ito.Set(PixelTypeDownCast<double, PixelType>((double)it.Get() * mScalar) ); 
259         ++it; ++ito;
260       }
261       break;
262     case 2: // Inverse
263       while (!it.IsAtEnd()) {
264         if (it.Get() != 0)
265           ito.Set(PixelTypeDownCast<double, PixelType>(mScalar / (double)it.Get())); 
266         else ito.Set(mDefaultPixelValue);
267         ++it; ++ito;
268       }
269       break;
270     case 3: // Max 
271       while (!it.IsAtEnd()) {
272         if (it.Get() < mScalar) ito.Set(PixelTypeDownCast<double, PixelType>(mScalar)); 
273         else ito.Set(PixelTypeDownCast<double, PixelType>(it.Get()));
274         ++it; ++ito;
275       }
276       break;
277     case 4: // Min
278       while (!it.IsAtEnd()) {
279         if (it.Get() > mScalar) ito.Set(PixelTypeDownCast<double, PixelType>(mScalar)); 
280         else ito.Set(PixelTypeDownCast<double, PixelType>(it.Get()));
281         ++it; ++ito;
282       }
283       break;
284     case 5: // Absolute value 
285       while (!it.IsAtEnd()) {
286         if (it.Get() <= 0) ito.Set(PixelTypeDownCast<double, PixelType>(-it.Get())); 
287         // <= zero to avoid warning for unsigned types
288         else ito.Set(PixelTypeDownCast<double, PixelType>(it.Get()));
289         ++it; ++ito;
290       }
291       break;
292     case 6: // Squared value
293       while (!it.IsAtEnd()) {
294         ito.Set(PixelTypeDownCast<double, PixelType>((double)it.Get()*(double)it.Get())); 
295         ++it; ++ito;
296       }
297       break;
298     case 7: // Log
299       while (!it.IsAtEnd()) {
300         if (it.Get() > 0) 
301           ito.Set(PixelTypeDownCast<double, PixelType>(log((double)it.Get()))); 
302         else ito.Set(mDefaultPixelValue);
303         ++it; ++ito;
304       }
305       break;
306     case 8: // exp
307       while (!it.IsAtEnd()) {
308         ito.Set(PixelTypeDownCast<double, PixelType>(exp((double)it.Get()))); 
309         ++it; ++ito;
310       }
311       break;
312     case 9: // sqrt
313       while (!it.IsAtEnd()) {
314         if (it.Get() > 0) 
315           ito.Set(PixelTypeDownCast<double, PixelType>(sqrt((double)it.Get()))); 
316         else {
317           if (it.Get() ==0) ito.Set(0);
318           else ito.Set(mDefaultPixelValue);
319         }
320         ++it; ++ito;
321       }
322       break;
323     default: // error ?
324       std::cerr << "ERROR : the operation number (" << mTypeOfOperation << ") is not known." << std::endl;
325       exit(-1);
326     }
327   }
328   //--------------------------------------------------------------------
329
330 } // end namespace
331
332 #endif  //#define CLITKIMAGEARITHMGENERICFILTER_TXX