]> Creatis software - clitk.git/blob - tools/clitkImageArithmGenericFilter.txx
Merge branch 'master' of git.creatis.insa-lyon.fr:clitk
[clitk.git] / tools / clitkImageArithmGenericFilter.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://www.centreleonberard.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 #ifndef CLITKIMAGEARITHMGENERICFILTER_TXX
19 #define CLITKIMAGEARITHMGENERICFILTER_TXX
20
21 #include "clitkImageCommon.h"
22
23 #include "itkMinimumMaximumImageCalculator.h"
24
25 namespace clitk
26 {
27
28 //--------------------------------------------------------------------
29 template<class args_info_type>
30 ImageArithmGenericFilter<args_info_type>::ImageArithmGenericFilter()
31   :ImageToImageGenericFilter<Self>("ImageArithmGenericFilter"),mTypeOfOperation(0)
32 {
33   InitializeImageType<2>();
34   InitializeImageType<3>();
35   InitializeImageType<4>();
36   mIsOperationUseASecondImage = false;
37   mOverwriteInputImage = true;
38 }
39 //--------------------------------------------------------------------
40
41
42 //--------------------------------------------------------------------
43 template<class args_info_type>
44 template<unsigned int Dim>
45 void ImageArithmGenericFilter<args_info_type>::InitializeImageType()
46 {
47   ADD_DEFAULT_IMAGE_TYPES(Dim);
48   ADD_VEC_IMAGE_TYPE(3u,3u,float);
49 }
50 //--------------------------------------------------------------------
51
52
53 //--------------------------------------------------------------------
54 template<class args_info_type>
55 void ImageArithmGenericFilter<args_info_type>::EnableOverwriteInputImage(bool b)
56 {
57   mOverwriteInputImage = b;
58 }
59 //--------------------------------------------------------------------
60
61
62 //--------------------------------------------------------------------
63 template<class args_info_type>
64 void ImageArithmGenericFilter<args_info_type>::SetArgsInfo(const args_info_type & a)
65 {
66   mArgsInfo=a;
67
68   // Set value
69   SetIOVerbose(mArgsInfo.verbose_flag);
70   mTypeOfOperation = mArgsInfo.operation_arg;
71   mDefaultPixelValue = mArgsInfo.pixelValue_arg;
72   mScalar = mArgsInfo.scalar_arg;
73   mOutputIsFloat = mArgsInfo.setFloatOutput_flag;
74
75   if (mArgsInfo.imagetypes_flag) this->PrintAvailableImageTypes();
76
77   if (mArgsInfo.input1_given) AddInputFilename(mArgsInfo.input1_arg);
78   if (mArgsInfo.input2_given) {
79     mIsOperationUseASecondImage = true;
80     AddInputFilename(mArgsInfo.input2_arg);
81   }
82
83   if (mArgsInfo.output_given) SetOutputFilename(mArgsInfo.output_arg);
84
85   // Check type of operation (with scalar or with other image)
86   if ((mArgsInfo.input2_given) && (mArgsInfo.scalar_given)) {
87     std::cerr << "ERROR : you cannot provide both --scalar and --input2 option" << std::endl;
88     exit(-1);
89   }
90   if ((!mArgsInfo.input2_given) && (!mArgsInfo.scalar_given)) {
91     if (mArgsInfo.operation_arg < 5) {
92       std::cerr << "Such operation need the --scalar option." << std::endl;
93       exit(-1);
94     }
95   }
96 }
97 //--------------------------------------------------------------------
98
99
100 //--------------------------------------------------------------------
101 template<class args_info_type>
102 template<class ImageType>
103 void ImageArithmGenericFilter<args_info_type>::UpdateWithInputImageType()
104 {
105   // Read input1
106   typename ImageType::Pointer input1 = this->template GetInput<ImageType>(0);
107
108   // Set input image iterator
109   typedef itk::ImageRegionIterator<ImageType> IteratorType;
110   IteratorType it(input1, input1->GetLargestPossibleRegion());
111
112   // typedef input2
113   typename ImageType::Pointer input2 = NULL;
114   IteratorType it2;
115
116   // Special case for normalisation
117   if (mTypeOfOperation == 12) {
118     typedef itk::MinimumMaximumImageCalculator<ImageType> MinMaxFilterType;
119     typename MinMaxFilterType::Pointer ff = MinMaxFilterType::New();
120     ff->SetImage(input1);
121     ff->ComputeMaximum();
122     mScalar = ff->GetMaximum();
123     mTypeOfOperation = 11; // divide
124   }
125
126   if (mIsOperationUseASecondImage) {
127       // Read input2
128       input2 = this->template GetInput<ImageType>(1);
129       // Set input image iterator
130       it2 = IteratorType(input2, input2->GetLargestPossibleRegion());
131       // Check dimension
132       if (!clitk::HaveSameSize<ImageType, ImageType>(input1, input2)) {
133         itkExceptionMacro(<< "The images (input and input2) must have the same size");
134       }
135       if(!clitk::HaveSameSpacing<ImageType, ImageType>(input1, input2)) {
136         itkWarningMacro(<< "The images (input and input2) do not have the same spacing. "
137                         << "Using first input's information.");
138       }
139   }
140
141   // Check if overwrite and outputisfloat and pixeltype is not float -> do not overwrite
142   if (mOverwriteInputImage && mOutputIsFloat && (typeid(typename ImageType::PixelType) != typeid(float))) {
143     // std::cerr << "Warning. Could not use both mOverwriteInputImage and mOutputIsFloat, because input is "
144     //                     << typeid(PixelType).name()
145     //                     << std::endl;
146     mOverwriteInputImage = false;
147   }
148
149   // ---------------- Overwrite input Image ---------------------
150   if (mOverwriteInputImage) {
151     // Set output iterator (to input1)
152     IteratorType ito = IteratorType(input1, input1->GetLargestPossibleRegion());
153     if (mIsOperationUseASecondImage) ComputeImage(it, it2, ito);
154     else ComputeImage(it, ito);
155     this->template SetNextOutput<ImageType>(input1);
156   }
157
158   // ---------------- Create new output Image ---------------------
159   else {
160     if (mOutputIsFloat) {
161       // Create output image
162       typedef itk::Image<float,ImageType::ImageDimension> OutputImageType;
163       typename OutputImageType::Pointer output = OutputImageType::New();
164       output->SetRegions(input1->GetLargestPossibleRegion());
165       output->SetOrigin(input1->GetOrigin());
166       output->SetSpacing(input1->GetSpacing());
167       output->Allocate();
168       // Set output iterator
169       typedef itk::ImageRegionIterator<OutputImageType> IteratorOutputType;
170       IteratorOutputType ito = IteratorOutputType(output, output->GetLargestPossibleRegion());
171       if (mIsOperationUseASecondImage) ComputeImage(it, it2, ito);
172       else ComputeImage(it, ito);
173       this->template SetNextOutput<OutputImageType>(output);
174     } else {
175       // Create output image
176       typedef ImageType OutputImageType;
177       typename OutputImageType::Pointer output = OutputImageType::New();
178       output->SetRegions(input1->GetLargestPossibleRegion());
179       output->SetOrigin(input1->GetOrigin());
180       output->SetSpacing(input1->GetSpacing());
181       output->Allocate();
182       // Set output iterator
183       typedef itk::ImageRegionIterator<OutputImageType> IteratorOutputType;
184       IteratorOutputType ito = IteratorOutputType(output, output->GetLargestPossibleRegion());
185       if (mIsOperationUseASecondImage) ComputeImage(it, it2, ito);
186       else ComputeImage(it, ito);
187       this->template SetNextOutput<OutputImageType>(output);
188     }
189   }
190 }
191 //--------------------------------------------------------------------
192
193 //--------------------------------------------------------------------
194 template<class args_info_type>
195 template<class Iter1, class Iter2, class Iter3>
196 void  ImageArithmGenericFilter<args_info_type>::ComputeImage(Iter1 it1, Iter2 it2, Iter3 ito)
197 {
198   it1.GoToBegin();
199   it2.GoToBegin();
200   ito.GoToBegin();
201   typedef typename Iter3::PixelType PixelType;
202
203   switch (mTypeOfOperation) {
204   case 0: // Addition
205     while (!ito.IsAtEnd()) {
206       ito.Set(PixelTypeDownCast<double, PixelType>((double)it1.Get() + (double)it2.Get()) );
207       ++it1;
208       ++it2;
209       ++ito;
210     }
211     break;
212   case 1: // Multiply
213     while (!ito.IsAtEnd()) {
214       ito.Set(PixelTypeDownCast<double, PixelType>((double)it1.Get() * (double)it2.Get()) );
215       ++it1;
216       ++it2;
217       ++ito;
218     }
219     break;
220   case 2: // Divide
221     while (!ito.IsAtEnd()) {
222       if (it1.Get() != 0)
223         ito.Set(PixelTypeDownCast<double, PixelType>((double)it1.Get() / (double)it2.Get()));
224       else ito.Set(mDefaultPixelValue);
225       ++it1;
226       ++it2;
227       ++ito;
228     }
229     break;
230   case 3: // Max
231     while (!ito.IsAtEnd()) {
232       if (it1.Get() < it2.Get()) ito.Set(PixelTypeDownCast<double, PixelType>(it2.Get()));
233       ++it1;
234       ++it2;
235       ++ito;
236     }
237     break;
238   case 4: // Min
239     while (!ito.IsAtEnd()) {
240       if (it1.Get() > it2.Get()) ito.Set(PixelTypeDownCast<double, PixelType>(it2.Get()));
241       ++it1;
242       ++it2;
243       ++ito;
244     }
245     break;
246   case 5: // Absolute difference
247     while (!ito.IsAtEnd()) {
248       ito.Set(PixelTypeDownCast<double, PixelType>(fabs((double)it2.Get()-(double)it1.Get())));
249       ++it1;
250       ++it2;
251       ++ito;
252     }
253     break;
254   case 6: // Squared differences
255     while (!ito.IsAtEnd()) {
256       ito.Set(PixelTypeDownCast<double, PixelType>(pow((double)it1.Get()-(double)it2.Get(),2)));
257       ++it1;
258       ++it2;
259       ++ito;
260     }
261     break;
262   case 7: // Difference
263     while (!ito.IsAtEnd()) {
264       ito.Set(PixelTypeDownCast<double, PixelType>((double)it1.Get()-(double)it2.Get()));
265       ++it1;
266       ++it2;
267       ++ito;
268     }
269     break;
270   case 8: // Relative Difference
271     while (!ito.IsAtEnd()) {
272       if (it1.Get() != 0) ito.Set(PixelTypeDownCast<double, PixelType>(((double)it1.Get()-(double)it2.Get()))/(double)it1.Get());
273       else ito.Set(0.0);
274       ++it1;
275       ++it2;
276       ++ito;
277     }
278     break;
279   default: // error ?
280     std::cerr << "ERROR : the operation number (" << mTypeOfOperation << ") is not known." << std::endl;
281     exit(-1);
282   }
283 }
284 //--------------------------------------------------------------------
285
286
287 //--------------------------------------------------------------------
288 template<class args_info_type>
289 template<class Iter1, class Iter2>
290 void clitk::ImageArithmGenericFilter<args_info_type>::ComputeImage(Iter1 it, Iter2 ito)
291 {
292   ito.GoToBegin();
293   it.GoToBegin();
294   typedef typename Iter2::PixelType PixelType;
295
296   // Perform operation
297   switch (mTypeOfOperation) {
298   case 0: // Addition
299     while (!it.IsAtEnd()) {
300       ito.Set(clitk::PixelTypeDownCast<double, PixelType>((double)it.Get() + mScalar) );
301       ++it;
302       ++ito;
303     }
304     break;
305   case 1: // Multiply
306     while (!it.IsAtEnd()) {
307       ito.Set(PixelTypeDownCast<double, PixelType>((double)it.Get() * mScalar) );
308       ++it;
309       ++ito;
310     }
311     break;
312   case 2: // Inverse
313     while (!it.IsAtEnd()) {
314       if (it.Get() != 0)
315         ito.Set(PixelTypeDownCast<double, PixelType>(mScalar / (double)it.Get()));
316       else ito.Set(mDefaultPixelValue);
317       ++it;
318       ++ito;
319     }
320     break;
321   case 3: // Max
322     while (!it.IsAtEnd()) {
323       if (it.Get() < mScalar) ito.Set(PixelTypeDownCast<double, PixelType>(mScalar));
324       else ito.Set(PixelTypeDownCast<double, PixelType>(it.Get()));
325       ++it;
326       ++ito;
327     }
328     break;
329   case 4: // Min
330     while (!it.IsAtEnd()) {
331       if (it.Get() > mScalar) ito.Set(PixelTypeDownCast<double, PixelType>(mScalar));
332       else ito.Set(PixelTypeDownCast<double, PixelType>(it.Get()));
333       ++it;
334       ++ito;
335     }
336     break;
337   case 5: // Absolute value
338     while (!it.IsAtEnd()) {
339       if (it.Get() <= 0) ito.Set(PixelTypeDownCast<double, PixelType>(-it.Get()));
340       // <= zero to avoid warning for unsigned types
341       else ito.Set(PixelTypeDownCast<double, PixelType>(it.Get()));
342       ++it;
343       ++ito;
344     }
345     break;
346   case 6: // Squared value
347     while (!it.IsAtEnd()) {
348       ito.Set(PixelTypeDownCast<double, PixelType>((double)it.Get()*(double)it.Get()));
349       ++it;
350       ++ito;
351     }
352     break;
353   case 7: // Log
354     while (!it.IsAtEnd()) {
355       if (it.Get() > 0)
356         ito.Set(PixelTypeDownCast<double, PixelType>(log((double)it.Get())));
357       else ito.Set(mDefaultPixelValue);
358       ++it;
359       ++ito;
360     }
361     break;
362   case 8: // exp
363     while (!it.IsAtEnd()) {
364       ito.Set(PixelTypeDownCast<double, PixelType>(exp((double)it.Get())));
365       ++it;
366       ++ito;
367     }
368     break;
369   case 9: // sqrt
370     while (!it.IsAtEnd()) {
371       if (it.Get() > 0)
372         ito.Set(PixelTypeDownCast<double, PixelType>(sqrt((double)it.Get())));
373       else {
374         if (it.Get() ==0) ito.Set(0);
375         else ito.Set(mDefaultPixelValue);
376       }
377       ++it;
378       ++ito;
379     }
380     break;
381   case 10: // exp
382     while (!it.IsAtEnd()) {
383       ito.Set(PixelTypeDownCast<double, PixelType>((0x10000 - (double)it.Get())/mScalar));
384       ++it;
385       ++ito;
386     }
387     break;
388   case 11: // divide
389     while (!it.IsAtEnd()) {
390       ito.Set(PixelTypeDownCast<double, PixelType>((double)it.Get() / mScalar) );
391       ++it;
392       ++ito;
393     }
394     break;
395   default: // error ?
396     std::cerr << "ERROR : the operation number (" << mTypeOfOperation << ") is not known." << std::endl;
397     exit(-1);
398   }
399 }
400 //--------------------------------------------------------------------
401
402
403
404 } // end namespace
405
406 #endif  //#define CLITKIMAGEARITHMGENERICFILTER_TXX