1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
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
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.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
19 #ifndef CLITKIMAGECONVERTGENERICFILTER_CXX
20 #define CLITKIMAGECONVERTGENERICFILTER_CXX
22 #include "clitkImageConvertGenericFilter.h"
23 #include "vvImageReader.h"
24 #include "vvImageWriter.h"
25 #include "itkFlipImageFilter.h"
26 #include "itkGDCMImageIO.h"
27 #include <itkChangeInformationImageFilter.h>
29 #include "gdcmReader.h"
30 #include "gdcmAttribute.h"
31 #include "gdcmPrinter.h"
33 #include "gdcmStringFilter.h"
35 //--------------------------------------------------------------------
36 clitk::ImageConvertGenericFilter::ImageConvertGenericFilter():
37 clitk::ImageToImageGenericFilter<Self>("ImageConvert")
39 mOutputPixelTypeName = "NotSpecified";
40 mDisplayWarning = true;
42 mWarningOccur = false;
43 SetCorrectNegativeSpacingFlag(false);
45 InitializeImageType<2>();
46 InitializeImageType<3>();
47 InitializeImageType<4>();
49 //--------------------------------------------------------------------
52 //--------------------------------------------------------------------
53 template<unsigned int Dim>
54 void clitk::ImageConvertGenericFilter::InitializeImageType()
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);
62 //--------------------------------------------------------------------
65 //--------------------------------------------------------------------
66 template<class InputImageType>
67 void clitk::ImageConvertGenericFilter::UpdateWithInputImageType()
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;
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;
87 if (mOutputPixelTypeName != "NotSpecified" || m_WriteCompression) {
88 std::cerr << "--vv is not compatible with --compression and --type options." << std::endl;
92 vvImageReader::Pointer reader = vvImageReader::New();
93 reader->SetInputFilenames(m_InputFilenames);
94 reader->Update(vvImageReader::IMAGE);
96 vvImageWriter::Pointer writer = vvImageWriter::New();
97 writer->SetOutputFileName(m_OutputFilenames.front());
98 writer->SetSaveTransform(true);
99 writer->SetInput(reader->GetOutput());
103 else if ((m_PixelTypeName == mOutputPixelTypeName) || (mOutputPixelTypeName == "NotSpecified")) {
106 typename InputImageType::Pointer input = this->template GetInput<InputImageType>(0);
108 if (mCorrectNegativeSpacingFlag) {
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;
118 // the dataset is the the set of element we are interested in:
119 gdcm::DataSet & ds = reader.GetFile().GetDataSet();
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();
126 std::cout << "Error: no negative spacing found SpacingBetweenSlices = " << s << " Abort. " << std::endl;
132 typename InputImageType::SpacingType spacing = input->GetSpacing();
134 input->SetSpacing(spacing);
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;
144 filter->SetFlipAxes(flipArray);
145 filter->SetInput(input);
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);
161 typename InputImageType::PointType origin = input->GetOrigin();
165 input->SetOrigin(origin);
168 typename InputImageType::DirectionType direction = input->GetDirection();
169 direction[2][2] = -1;
170 input->SetDirection(direction);
173 itk::MetaDataDictionary dict;// = new itk::MetaDataDictionary;
174 input->SetMetaDataDictionary(dict);
177 typedef itk::ChangeInformationImageFilter<InputImageType> CIType;
178 typename CIType::Pointer changeInfo = CIType::New();
180 changeInfo->SetInput(input);
181 typename CIType::PointType o = input->GetOrigin();
184 typename CIType::DirectionType d = input->GetDirection();
187 changeInfo->ChangeDirectionOn();
188 changeInfo->ChangeOriginOn();
189 changeInfo->SetOutputOrigin(o);
190 changeInfo->SetOutputDirection(d);
191 changeInfo->Update();
192 input = changeInfo->GetOutput();
195 this->SetNextOutput<InputImageType>(input);
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))
204 //====================================================================
206 //====================================================================
208 template<class PixelType, class OutputPixelType>
209 void clitk::ImageConvertGenericFilter::CheckTypes(
210 std::string inType, std::string outType
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 (";
219 if (!std::numeric_limits<PixelType>::is_integer) {
220 if (std::numeric_limits<OutputPixelType>::is_integer) {
221 osstream << "Warning, input type is not integer (";
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 (";
231 if (std::numeric_limits<PixelType>::digits10 > std::numeric_limits<OutputPixelType>::digits10) {
232 osstream << "Warning, possible loss of precision : input type is (" ;
235 if (!osstream.str().empty())
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;
247 #endif /* end #define CLITKIMAGECONVERTGENERICFILTER_CXX */