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 if (!DIS.GetByteValue()) {
152 std::cout << "Error: could not find 0x0054,0x0022 tag. Abort." << std::endl;
155 gdcm::SmartPointer<gdcm::SequenceOfItems> sqf = DIS.GetValueAsSQ();
156 gdcm::Item & item = sqf->GetItem(1);
157 gdcm::DataSet & ds_position = item.GetNestedDataSet();
158 gdcm::Attribute<0x0020,0x0032> ImagePositionPatient;
159 ImagePositionPatient.SetFromDataSet(ds_position);
160 double x = ImagePositionPatient.GetValue(0);
161 double y = ImagePositionPatient.GetValue(1);
162 double z = ImagePositionPatient.GetValue(2);
165 typename InputImageType::PointType origin = input->GetOrigin();
169 input->SetOrigin(origin);
172 typename InputImageType::DirectionType direction = input->GetDirection();
173 direction[2][2] = -1;
174 input->SetDirection(direction);
177 itk::MetaDataDictionary dict;// = new itk::MetaDataDictionary;
178 input->SetMetaDataDictionary(dict);
181 typedef itk::ChangeInformationImageFilter<InputImageType> CIType;
182 typename CIType::Pointer changeInfo = CIType::New();
184 changeInfo->SetInput(input);
185 typename CIType::PointType o = input->GetOrigin();
188 typename CIType::DirectionType d = input->GetDirection();
191 changeInfo->ChangeDirectionOn();
192 changeInfo->ChangeOriginOn();
193 changeInfo->SetOutputOrigin(o);
194 changeInfo->SetOutputDirection(d);
195 changeInfo->Update();
196 input = changeInfo->GetOutput();
199 this->SetNextOutput<InputImageType>(input);
202 // "trick" to call independent versions of update according to the
203 // pixel type (vector or scalar), using partial specializations
204 if (!UpdateWithSelectiveOutputType<InputImageType, ImageConvertTraits<typename InputImageType::PixelType>::IS_VECTOR>::Run(*this, mOutputPixelTypeName))
208 //====================================================================
210 //====================================================================
212 template<class PixelType, class OutputPixelType>
213 void clitk::ImageConvertGenericFilter::CheckTypes(
214 std::string inType, std::string outType
217 std::ostringstream osstream;
218 if (std::numeric_limits<PixelType>::is_signed) {
219 if (!std::numeric_limits<OutputPixelType>::is_signed) {
220 osstream << "Warning, input type is signed (";
223 if (!std::numeric_limits<PixelType>::is_integer) {
224 if (std::numeric_limits<OutputPixelType>::is_integer) {
225 osstream << "Warning, input type is not integer (";
228 // DD(std::numeric_limits<PixelType>::digits10);
229 // DD(std::numeric_limits<OutputPixelType>::digits10);
230 if (!std::numeric_limits<PixelType>::is_integer) {
231 if (std::numeric_limits<OutputPixelType>::is_integer) {
232 osstream << "Warning, input type is not integer (";
235 if (std::numeric_limits<PixelType>::digits10 > std::numeric_limits<OutputPixelType>::digits10) {
236 osstream << "Warning, possible loss of precision : input type is (" ;
239 if (!osstream.str().empty())
241 mWarningOccur = true;
242 osstream << inType << ") while output type is (" << outType << "), use at your own responsability." << std::endl;
243 mWarning = osstream.str();
244 if (mDisplayWarning) {
245 std::cerr << mWarning;
251 #endif /* end #define CLITKIMAGECONVERTGENERICFILTER_CXX */