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