]> Creatis software - clitk.git/blob - tools/clitkImageConvertGenericFilter.cxx
Precision on clitkBlurImage help
[clitk.git] / tools / clitkImageConvertGenericFilter.cxx
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
19 #ifndef CLITKIMAGECONVERTGENERICFILTER_CXX
20 #define CLITKIMAGECONVERTGENERICFILTER_CXX
21
22 #include "clitkImageConvertGenericFilter.h"
23 #include "vvImageReader.h"
24 #include "vvImageWriter.h"
25 #include "itkFlipImageFilter.h"
26 #include "itkGDCMImageIO.h"
27 #include <itkChangeInformationImageFilter.h>
28
29 #include "gdcmReader.h"
30 #include "gdcmAttribute.h"
31 #include "gdcmPrinter.h"
32 #include "gdcmDict.h"
33 #include "gdcmStringFilter.h"
34
35 //--------------------------------------------------------------------
36 clitk::ImageConvertGenericFilter::ImageConvertGenericFilter():
37   clitk::ImageToImageGenericFilter<Self>("ImageConvert")
38 {
39   mOutputPixelTypeName = "NotSpecified";
40   mDisplayWarning = true;
41   mWarning = "";
42   mWarningOccur = false;
43   SetCorrectNegativeSpacingFlag(false);
44
45   InitializeImageType<2>();
46   InitializeImageType<3>();
47   InitializeImageType<4>();
48 }
49 //--------------------------------------------------------------------
50
51
52 //--------------------------------------------------------------------
53 template<unsigned int Dim>
54 void clitk::ImageConvertGenericFilter::InitializeImageType()
55 {
56   ADD_DEFAULT_IMAGE_TYPES(Dim);
57   ADD_VEC_IMAGE_TYPE(Dim, 2, float);
58   ADD_VEC_IMAGE_TYPE(Dim, 3, float);
59   ADD_VEC_IMAGE_TYPE(Dim, 2, double);
60   ADD_VEC_IMAGE_TYPE(Dim, 3, double);
61 }
62 //--------------------------------------------------------------------
63
64
65 //--------------------------------------------------------------------
66 template<class InputImageType>
67 void clitk::ImageConvertGenericFilter::UpdateWithInputImageType()
68 {
69   // Verbose stuff
70   if (m_IOVerbose) {
71     if (m_InputFilenames.size() == 1) {
72       std::cout << "Input image <" << m_InputFilenames[0] << "> is ";
73       itk::ImageIOBase::Pointer header = clitk::readImageHeader(m_InputFilenames[0]);
74       printImageHeader(header, std::cout);
75       std::cout << std::endl;
76     } else {
77       for(unsigned int i=0; i<m_InputFilenames.size(); i++) {
78         std::cout << "Input image " << i << " <" << m_InputFilenames[i] << "> is ";
79         itk::ImageIOBase::Pointer h = clitk::readImageHeader(m_InputFilenames[i]);
80         printImageHeader(h, std::cout);
81         std::cout << std::endl;
82       }
83     }
84   }
85
86   if(mVV) {
87     if (mOutputPixelTypeName != "NotSpecified" || m_WriteCompression) {
88       std::cerr << "--vv is not compatible with --compression and --type options." << std::endl;
89       exit(-1);
90     }
91
92     vvImageReader::Pointer reader = vvImageReader::New();
93     reader->SetInputFilenames(m_InputFilenames);
94     reader->Update(vvImageReader::IMAGE);
95
96     vvImageWriter::Pointer writer = vvImageWriter::New();
97     writer->SetOutputFileName(m_OutputFilenames.front());
98     writer->SetSaveTransform(true);
99     writer->SetInput(reader->GetOutput());
100     writer->Update();
101     return;
102   }
103   else if ((m_PixelTypeName == mOutputPixelTypeName) || (mOutputPixelTypeName == "NotSpecified")) {
104
105     // Get input image
106     typename InputImageType::Pointer input = this->template GetInput<InputImageType>(0);
107
108     if (mCorrectNegativeSpacingFlag) {
109       // Read dicom
110       gdcm::Reader reader;
111       reader.SetFileName(m_InputFilenames[0].c_str());
112       // if (!reader.CanReadFile(m_InputFilenames[0])) {
113       //   std::cout << "Error: " << m_InputFilenames[0] << " is not a dicom file. Abort." << std::endl;
114       //   exit(0);
115       // }
116       reader.Read();
117
118       // the dataset is the the set of element we are interested in:
119       gdcm::DataSet & ds = reader.GetFile().GetDataSet();
120
121       // Read the attribute SpacingBetweenSlices, check if negative and replace
122       gdcm::Attribute<0x0018,0x0088> SpacingBetweenSlices;
123       SpacingBetweenSlices.SetFromDataSet(ds);
124       double s = SpacingBetweenSlices.GetValue();
125       if (s >=0) {
126         std::cout << "Error: no negative spacing found SpacingBetweenSlices = " << s << " Abort. " << std::endl;
127         exit(0);
128       }
129       s = -s;
130
131       // Set spacing
132       typename InputImageType::SpacingType spacing = input->GetSpacing();
133       spacing[2] = s;
134       input->SetSpacing(spacing);
135
136       // Flip
137       typedef itk::FlipImageFilter< InputImageType >  FilterType;
138       typename FilterType::Pointer filter = FilterType::New();
139       typedef typename FilterType::FlipAxesArrayType     FlipAxesArrayType;
140       FlipAxesArrayType flipArray;
141       flipArray[0] = false;
142       flipArray[1] = false;
143       flipArray[2] = true;
144       filter->SetFlipAxes(flipArray);
145       filter->SetInput(input);
146       filter->Update();
147
148       // Read the attribute  Image Position (Patient)
149       gdcm::Tag  DetectorInformationSequenceTag(0x0054,0x0022);
150       const gdcm::DataElement & DIS = ds.GetDataElement(DetectorInformationSequenceTag);
151       gdcm::SmartPointer<gdcm::SequenceOfItems> sqf = DIS.GetValueAsSQ();
152       gdcm::Item & item = sqf->GetItem(1);
153       gdcm::DataSet & ds_position = item.GetNestedDataSet();
154       gdcm::Attribute<0x0020,0x0032> ImagePositionPatient;
155       ImagePositionPatient.SetFromDataSet(ds_position);
156       double x = ImagePositionPatient.GetValue(0);
157       double y = ImagePositionPatient.GetValue(1);
158       double z = ImagePositionPatient.GetValue(2);
159
160       // Set offset
161       typename InputImageType::PointType origin = input->GetOrigin();
162       origin[0] = x;
163       origin[1] = y;
164       origin[2] = z;
165       input->SetOrigin(origin);
166
167       // Orientation
168       typename InputImageType::DirectionType direction = input->GetDirection();
169       direction[2][2] = -1;
170       input->SetDirection(direction);
171
172       // Empty meta info
173       itk::MetaDataDictionary dict;// = new itk::MetaDataDictionary;
174       input->SetMetaDataDictionary(dict);
175     }
176
177     typedef itk::ChangeInformationImageFilter<InputImageType> CIType;
178     typename CIType::Pointer changeInfo = CIType::New();
179     if(mNoNiiMeta) {
180       changeInfo->SetInput(input);
181       typename CIType::PointType o = input->GetOrigin();
182       o[0] *= -1.;
183       o[1] *= -1.;
184       typename CIType::DirectionType d = input->GetDirection();
185       d[0][0] *= -1.;
186       d[1][1] *= -1.;
187       changeInfo->ChangeDirectionOn();
188       changeInfo->ChangeOriginOn();
189       changeInfo->SetOutputOrigin(o);
190       changeInfo->SetOutputDirection(d);
191       changeInfo->Update();
192       input = changeInfo->GetOutput();
193     }
194
195     this->SetNextOutput<InputImageType>(input);
196
197   } else {
198     // "trick" to call independent versions of update according to the
199     // pixel type (vector or scalar), using partial specializations
200     if (!UpdateWithSelectiveOutputType<InputImageType, ImageConvertTraits<typename InputImageType::PixelType>::IS_VECTOR>::Run(*this, mOutputPixelTypeName))
201       exit(-1);
202   }
203 }
204 //====================================================================
205
206 //====================================================================
207
208 template<class PixelType, class OutputPixelType>
209 void clitk::ImageConvertGenericFilter::CheckTypes(
210   std::string inType, std::string outType
211 )
212 {
213   std::ostringstream osstream;
214   if (std::numeric_limits<PixelType>::is_signed) {
215     if (!std::numeric_limits<OutputPixelType>::is_signed) {
216       osstream << "Warning, input type is signed (";
217     }
218   }
219   if (!std::numeric_limits<PixelType>::is_integer) {
220     if (std::numeric_limits<OutputPixelType>::is_integer) {
221       osstream << "Warning, input type is not integer (";
222     }
223   }
224   //  DD(std::numeric_limits<PixelType>::digits10);
225   // DD(std::numeric_limits<OutputPixelType>::digits10);
226   if (!std::numeric_limits<PixelType>::is_integer) {
227     if (std::numeric_limits<OutputPixelType>::is_integer) {
228       osstream << "Warning, input type is not integer (";
229     }
230   }
231   if (std::numeric_limits<PixelType>::digits10 > std::numeric_limits<OutputPixelType>::digits10) {
232     osstream << "Warning, possible loss of precision : input type is (" ;
233   }
234
235   if (!osstream.str().empty())
236   {
237     mWarningOccur = true;
238     osstream << inType << ") while output type is (" << outType << "), use at your own responsability." << std::endl;
239     mWarning = osstream.str();
240     if (mDisplayWarning) {
241       std::cerr << mWarning;
242     }
243   }
244 }
245
246
247 #endif /* end #define CLITKIMAGECONVERTGENERICFILTER_CXX */