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"
28 #include "gdcmReader.h"
29 #include "gdcmAttribute.h"
30 #include "gdcmPrinter.h"
32 #include "gdcmStringFilter.h"
34 //--------------------------------------------------------------------
35 clitk::ImageConvertGenericFilter::ImageConvertGenericFilter():
36 clitk::ImageToImageGenericFilter<Self>("ImageConvert")
38 mOutputPixelTypeName = "NotSpecified";
39 mDisplayWarning = true;
41 mWarningOccur = false;
42 SetCorrectNegativeSpacingFlag(false);
44 InitializeImageType<2>();
45 InitializeImageType<3>();
46 InitializeImageType<4>();
48 //--------------------------------------------------------------------
51 //--------------------------------------------------------------------
52 template<unsigned int Dim>
53 void clitk::ImageConvertGenericFilter::InitializeImageType()
55 ADD_DEFAULT_IMAGE_TYPES(Dim);
56 ADD_VEC_IMAGE_TYPE(Dim, 2, float);
57 ADD_VEC_IMAGE_TYPE(Dim, 3, float);
58 ADD_VEC_IMAGE_TYPE(Dim, 2, double);
59 ADD_VEC_IMAGE_TYPE(Dim, 3, double);
61 //--------------------------------------------------------------------
64 //--------------------------------------------------------------------
65 template<class InputImageType>
66 void clitk::ImageConvertGenericFilter::UpdateWithInputImageType()
70 if (m_InputFilenames.size() == 1) {
71 std::cout << "Input image <" << m_InputFilenames[0] << "> is ";
72 itk::ImageIOBase::Pointer header = clitk::readImageHeader(m_InputFilenames[0]);
73 printImageHeader(header, std::cout);
74 std::cout << std::endl;
76 for(unsigned int i=0; i<m_InputFilenames.size(); i++) {
77 std::cout << "Input image " << i << " <" << m_InputFilenames[i] << "> is ";
78 itk::ImageIOBase::Pointer h = clitk::readImageHeader(m_InputFilenames[i]);
79 printImageHeader(h, std::cout);
80 std::cout << std::endl;
86 if (mOutputPixelTypeName != "NotSpecified" || m_WriteCompression) {
87 std::cerr << "--vv is not compatible with --compression and --type options." << std::endl;
91 vvImageReader::Pointer reader = vvImageReader::New();
92 reader->SetInputFilenames(m_InputFilenames);
93 reader->Update(vvImageReader::IMAGE);
95 vvImageWriter::Pointer writer = vvImageWriter::New();
96 writer->SetOutputFileName(m_OutputFilenames.front());
97 writer->SetSaveTransform(true);
98 writer->SetInput(reader->GetOutput());
102 else if ((m_PixelTypeName == mOutputPixelTypeName) || (mOutputPixelTypeName == "NotSpecified")) {
105 typename InputImageType::Pointer input = this->template GetInput<InputImageType>(0);
107 if (mCorrectNegativeSpacingFlag) {
110 reader.SetFileName(m_InputFilenames[0].c_str());
111 // if (!reader.CanReadFile(m_InputFilenames[0])) {
112 // std::cout << "Error: " << m_InputFilenames[0] << " is not a dicom file. Abort." << std::endl;
117 // the dataset is the the set of element we are interested in:
118 gdcm::DataSet & ds = reader.GetFile().GetDataSet();
120 // Read the attribute SpacingBetweenSlices, check if negative and replace
121 gdcm::Attribute<0x0018,0x0088> SpacingBetweenSlices;
122 SpacingBetweenSlices.SetFromDataSet(ds);
123 double s = SpacingBetweenSlices.GetValue();
125 std::cout << "Error: no negative spacing found SpacingBetweenSlices = " << s << " Abort. " << std::endl;
131 typename InputImageType::SpacingType spacing = input->GetSpacing();
133 input->SetSpacing(spacing);
136 typedef itk::FlipImageFilter< InputImageType > FilterType;
137 typename FilterType::Pointer filter = FilterType::New();
138 typedef typename FilterType::FlipAxesArrayType FlipAxesArrayType;
139 FlipAxesArrayType flipArray;
140 flipArray[0] = false;
141 flipArray[1] = false;
143 filter->SetFlipAxes(flipArray);
144 filter->SetInput(input);
147 // Read the attribute Image Position (Patient)
148 gdcm::Tag DetectorInformationSequenceTag(0x0054,0x0022);
149 const gdcm::DataElement & DIS = ds.GetDataElement(DetectorInformationSequenceTag);
150 gdcm::SmartPointer<gdcm::SequenceOfItems> sqf = DIS.GetValueAsSQ();
151 gdcm::Item & item = sqf->GetItem(1);
152 gdcm::DataSet & ds_position = item.GetNestedDataSet();
153 gdcm::Attribute<0x0020,0x0032> ImagePositionPatient;
154 ImagePositionPatient.SetFromDataSet(ds_position);
155 double x = ImagePositionPatient.GetValue(0);
156 double y = ImagePositionPatient.GetValue(1);
157 double z = ImagePositionPatient.GetValue(2);
160 typename InputImageType::PointType origin = input->GetOrigin();
164 input->SetOrigin(origin);
167 typename InputImageType::DirectionType direction = input->GetDirection();
168 direction[2][2] = -1;
169 input->SetDirection(direction);
172 itk::MetaDataDictionary dict;// = new itk::MetaDataDictionary;
173 input->SetMetaDataDictionary(dict);
175 this->SetNextOutput<InputImageType>(input);
179 // "trick" to call independent versions of update according to the
180 // pixel type (vector or scalar), using partial specializations
181 if (!UpdateWithSelectiveOutputType<InputImageType, ImageConvertTraits<typename InputImageType::PixelType>::IS_VECTOR>::Run(*this, mOutputPixelTypeName))
185 //====================================================================
187 //====================================================================
189 template<class PixelType, class OutputPixelType>
190 void clitk::ImageConvertGenericFilter::CheckTypes(
191 std::string inType, std::string outType
194 std::ostringstream osstream;
195 if (std::numeric_limits<PixelType>::is_signed) {
196 if (!std::numeric_limits<OutputPixelType>::is_signed) {
197 osstream << "Warning, input type is signed (";
200 if (!std::numeric_limits<PixelType>::is_integer) {
201 if (std::numeric_limits<OutputPixelType>::is_integer) {
202 osstream << "Warning, input type is not integer (";
205 // DD(std::numeric_limits<PixelType>::digits10);
206 // DD(std::numeric_limits<OutputPixelType>::digits10);
207 if (!std::numeric_limits<PixelType>::is_integer) {
208 if (std::numeric_limits<OutputPixelType>::is_integer) {
209 osstream << "Warning, input type is not integer (";
212 if (std::numeric_limits<PixelType>::digits10 > std::numeric_limits<OutputPixelType>::digits10) {
213 osstream << "Warning, possible loss of precision : input type is (" ;
216 if (!osstream.str().empty())
218 mWarningOccur = true;
219 osstream << inType << ") while output type is (" << outType << "), use at your own responsability." << std::endl;
220 mWarning = osstream.str();
221 if (mDisplayWarning) {
222 std::cerr << mWarning;
228 #endif /* end #define CLITKIMAGECONVERTGENERICFILTER_CXX */