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 ===========================================================================**/
18 #ifndef clitkWriteDicomSeriesGenericFilter_txx
19 #define clitkWriteDicomSeriesGenericFilter_txx
21 /* =================================================
22 * @file clitkWriteDicomSeriesGenericFilter.txx
28 ===================================================*/
31 #include "clitkResampleImageWithOptionsFilter.h"
38 //-----------------------------------------------------------
40 //-----------------------------------------------------------
41 template<class args_info_type>
42 WriteDicomSeriesGenericFilter<args_info_type>::WriteDicomSeriesGenericFilter()
49 //-----------------------------------------------------------
51 //-----------------------------------------------------------
52 template<class args_info_type>
53 void WriteDicomSeriesGenericFilter<args_info_type>::Update()
55 // Read the Dimension and PixelType
57 std::string PixelType;
58 ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType);
62 if(Dimension==2) UpdateWithDim<2>(PixelType);
63 else if(Dimension==3) UpdateWithDim<3>(PixelType);
64 // else if (Dimension==4)UpdateWithDim<4>(PixelType);
66 std::cout<<"Error, Only for 2 or 3 Dimensions!!!"<<std::endl ;
71 //-------------------------------------------------------------------
72 // Update with the number of dimensions
73 //-------------------------------------------------------------------
74 template<class args_info_type>
75 template<unsigned int Dimension>
77 WriteDicomSeriesGenericFilter<args_info_type>::UpdateWithDim(std::string PixelType)
79 if (m_Verbose) std::cout << "Image was detected to be "<<Dimension<<"D and "<< PixelType<<"..."<<std::endl;
81 if(PixelType == "short") {
82 if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed short..." << std::endl;
83 UpdateWithDimAndPixelType<Dimension, signed short>();
85 else if(PixelType == "unsigned_short"){
86 if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl;
87 UpdateWithDimAndPixelType<Dimension, unsigned short>();
90 else if (PixelType == "unsigned_char") {
91 if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl;
92 UpdateWithDimAndPixelType<Dimension, unsigned char>();
95 // else if (PixelType == "char"){
96 // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl;
97 // UpdateWithDimAndPixelType<Dimension, signed char>();
99 else if (PixelType == "double") {
100 if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and double..." << std::endl;
101 UpdateWithDimAndPixelType<Dimension, double>();
104 if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl;
105 UpdateWithDimAndPixelType<Dimension, float>();
109 //-------------------------------------------------------------------
110 // Update with the number of dimensions and the pixeltype read from
111 // the dicom files. The MHD files may be resampled to match the
112 // dicom spacing (and number of slices). Rounding errors in resampling
113 // are handled by removing files when generating the output dicom
115 //-------------------------------------------------------------------
116 template<class args_info_type>
117 template <unsigned int Dimension, class PixelType>
119 WriteDicomSeriesGenericFilter<args_info_type>::UpdateWithDimAndPixelType()
123 typedef itk::Image<PixelType, Dimension> InputImageType;
124 typedef itk::Image<PixelType, 2> OutputImageType;
126 // Read the dicom directory
127 typedef itk::ImageSeriesReader< InputImageType > ReaderType;
128 typedef itk::GDCMImageIO ImageIOType;
129 typedef itk::GDCMSeriesFileNames NamesGeneratorType;
131 ImageIOType::Pointer gdcmIO = ImageIOType::New();
132 NamesGeneratorType::Pointer namesGenerator = NamesGeneratorType::New();
133 namesGenerator->SetInputDirectory( m_ArgsInfo.inputDir_arg );
134 namesGenerator->SetOutputDirectory( m_ArgsInfo.outputDir_arg );
135 typename ReaderType::FileNamesContainer filenames_in = namesGenerator->GetInputFileNames();
136 typename ReaderType::FileNamesContainer filenames_out = namesGenerator->GetOutputFileNames();
138 // Output the dicom files
139 unsigned int numberOfFilenames = filenames_in.size();
141 std::cout << numberOfFilenames <<" were read in the directory "<<m_ArgsInfo.inputDir_arg<<"..."<<std::endl<<std::endl;
142 for(unsigned int fni = 0; fni<numberOfFilenames; fni++) {
143 std::cout << "filename # " << fni << " = ";
144 std::cout << filenames_in[fni] << std::endl;
149 typename ReaderType::Pointer reader = ReaderType::New();
150 reader->SetImageIO( gdcmIO );
151 reader->SetFileNames( filenames_in );
154 } catch (itk::ExceptionObject &excp) {
155 std::cerr << "Error: Exception thrown while reading the DICOM series!!" << std::endl;
156 std::cerr << excp << std::endl;
159 // Read the input (MHD file)
160 typedef typename InputImageType::RegionType RegionType;
161 typedef typename RegionType::SizeType SizeType;
162 typedef itk::ImageFileReader<InputImageType> InputReaderType;
163 typename InputReaderType::Pointer volumeReader = InputReaderType::New();
164 volumeReader->SetFileName( m_InputFileName);
165 volumeReader->Update();
167 typename InputImageType::Pointer input = volumeReader->GetOutput();
168 if ((!m_ArgsInfo.useSizeAsReference_flag && (input->GetSpacing() != reader->GetOutput()->GetSpacing())) ||
169 (m_ArgsInfo.useSizeAsReference_flag && (input->GetLargestPossibleRegion().GetSize() != reader->GetOutput()->GetLargestPossibleRegion().GetSize()))) {
171 // resampling is carried out on the fly if resolution or size between
172 // the input mhd and input dicom series is different
175 typedef clitk::ResampleImageWithOptionsFilter<InputImageType, InputImageType> ResampleImageFilterType;
176 typename ResampleImageFilterType::Pointer filter = ResampleImageFilterType::New();
177 filter->SetInput(input);
178 filter->SetVerboseOptions(m_Verbose);
179 filter->SetGaussianFilteringEnabled(false);
180 filter->SetDefaultPixelValue(0);
182 if (!m_ArgsInfo.useSizeAsReference_flag) {
183 filter->SetOutputSpacing(reader->GetOutput()->GetSpacing());
185 std::cout << "Warning: The image spacing differs between the MHD file and the input dicom series. Performing resampling with default options using spacing as reference (for advanced options, use clitkResampleImage)." << std::endl;
186 std::cout << "MHD -> " << input->GetSpacing() << std::endl;
187 std::cout << "dicom -> " << reader->GetOutput()->GetSpacing() << std::endl;
191 const SizeType& dicom_size = reader->GetOutput()->GetLargestPossibleRegion().GetSize();
192 SizeType output_size;
193 for (unsigned int i = 0; i < Dimension; i++)
194 output_size[i] = dicom_size[i];
195 filter->SetOutputSize(output_size);
197 std::cout << "Warning: The image size differs between the MHD file and the input dicom series. Performing resampling with default options using size as reference (for advanced options, use clitkResampleImage)." << std::endl;
198 std::cout << "MHD -> " << input->GetLargestPossibleRegion().GetSize() << std::endl;
199 std::cout << "dicom -> " << reader->GetOutput()->GetLargestPossibleRegion().GetSize() << std::endl;
205 input = filter->GetOutput();
206 } catch( itk::ExceptionObject & excp ) {
207 std::cerr << "Error: Exception thrown while resampling!!" << std::endl;
208 std::cerr << excp << std::endl;
212 // In some cases, due to resampling approximation issues,
213 // the number of slices in the MHD file may be different (smaller)
214 // from the number of files in the template dicom directory.
215 // To avoid ITK generating an exception, we reduce the number
216 // of DCM files to be considered, and a warning is printed
218 const RegionType volumeRegion = input->GetLargestPossibleRegion();
219 const SizeType& volumeSize = volumeRegion.GetSize();
221 std::cout << volumeRegion << volumeSize << std::endl;
223 if (Dimension == 3 && volumeSize[2] < numberOfFilenames) {
225 std::cout << "Warning: The number of files in " << m_ArgsInfo.inputDir_arg << " (" << filenames_in.size() << " files) is greater than the number of slices in MHD (" << volumeSize[2] << " slices). Using only " << volumeSize[2] << " files." << std::endl;
227 filenames_in.resize(volumeSize[2]);
228 filenames_out.resize(filenames_in.size());
229 numberOfFilenames = filenames_in.size();
232 // Modify the meta dictionary
233 typedef itk::MetaDataDictionary DictionaryType;
234 const std::vector<DictionaryType*>* dictionary = reader->GetMetaDataDictionaryArray();
237 unsigned int numberOfKeysGiven=m_ArgsInfo.key_given;
239 for (unsigned int i = 0; i < numberOfKeysGiven; i++) {
240 std::string entryId(m_ArgsInfo.key_arg[i] );
241 std::string value( m_ArgsInfo.tag_arg[i] );
242 std::cout << entryId << " " << value << std::endl;
243 for(unsigned int fni = 0; fni<numberOfFilenames; fni++)
244 itk::EncapsulateMetaData<std::string>( *((*dictionary)[fni]), entryId, value );
248 // Output directory and filenames
249 itksys::SystemTools::MakeDirectory( m_ArgsInfo.outputDir_arg ); // create if it doesn't exist
250 typedef itk::ImageSeriesWriter<InputImageType, OutputImageType > SeriesWriterType;
251 typename SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();
253 seriesWriter->SetInput( input );
254 seriesWriter->SetImageIO( gdcmIO );
256 seriesWriter->SetFileNames( filenames_out );
257 seriesWriter->SetMetaDataDictionaryArray( dictionary );
261 seriesWriter->Update();
262 } catch( itk::ExceptionObject & excp ) {
263 std::cerr << "Error: Exception thrown while writing the series!!" << std::endl;
264 std::cerr << excp << std::endl;
270 //-------------------------------------------------------------------
271 // Update with the number of dimensions and the pixeltype
272 //-------------------------------------------------------------------
273 template<class args_info_type>
274 template <unsigned int Dimension, class PixelType>
276 WriteDicomSeriesGenericFilter<args_info_type>::UpdateWithDimAndPixelType()
280 typedef itk::Image<PixelType, Dimension> InputImageType;
281 typedef itk::Image<PixelType, 2> OutputImageType;
283 // Read the input (volumetric)
284 typedef itk::ImageFileReader<InputImageType> InputReaderType;
285 typename InputReaderType::Pointer volumeReader = InputReaderType::New();
286 volumeReader->SetFileName( m_InputFileName);
287 volumeReader->Update();
288 typename InputImageType::Pointer input= volumeReader->GetOutput();
290 // Read the dicom directory
291 typedef itk::ImageSeriesReader< InputImageType > ReaderType;
292 typedef itk::GDCMImageIO ImageIOType;
293 typedef itk::GDCMSeriesFileNames NamesGeneratorType;
295 ImageIOType::Pointer gdcmIO = ImageIOType::New();
296 NamesGeneratorType::Pointer namesGenerator = NamesGeneratorType::New();
297 namesGenerator->SetInputDirectory( m_ArgsInfo.inputDir_arg );
298 namesGenerator->SetOutputDirectory( m_ArgsInfo.outputDir_arg );
299 typename ReaderType::FileNamesContainer filenames_in = namesGenerator->GetInputFileNames();
300 typename ReaderType::FileNamesContainer filenames_out = namesGenerator->GetOutputFileNames();
302 // Output the dicom files
303 unsigned int numberOfFilenames = filenames_in.size();
305 std::cout << numberOfFilenames <<" were read in the directory "<<m_ArgsInfo.inputDir_arg<<"..."<<std::endl<<std::endl;
306 for(unsigned int fni = 0; fni<numberOfFilenames; fni++) {
307 std::cout << "filename # " << fni << " = ";
308 std::cout << filenames_in[fni] << std::endl;
313 // In some cases, due to resampling approximation issues,
314 // the number of slices in the MHD file may be different
315 // from the number of slices in the template DCM directory.
316 // To avoid ITK generating an exception, we reduce the number
317 // of DCM files to be considered, provided the --force
319 typedef typename InputImageType::RegionType RegionType;
320 typedef typename RegionType::SizeType SizeType;
321 const RegionType volumeRegion = input->GetLargestPossibleRegion();
322 const SizeType& volumeSize = volumeRegion.GetSize();
323 if (m_ArgsInfo.force_given && Dimension == 3 && volumeSize[2] < numberOfFilenames)
325 std::cout << "Warning: Number of files in " << m_ArgsInfo.inputDir_arg << " is greater than the number of slices in MHD. Using only " << volumeSize[2] << " files." << std::endl;
326 filenames_in.resize(volumeSize[2]);
327 filenames_out.resize(filenames_in.size());
328 numberOfFilenames = filenames_in.size();
332 typename ReaderType::Pointer reader = ReaderType::New();
333 reader->SetImageIO( gdcmIO );
334 reader->SetFileNames( filenames_in );
337 } catch (itk::ExceptionObject &excp) {
338 std::cerr << "Error: Exception thrown while reading the DICOM series!!" << std::endl;
339 std::cerr << excp << std::endl;
343 // Modify the meta dictionary
344 typedef itk::MetaDataDictionary DictionaryType;
345 const std::vector<DictionaryType*>* dictionary = reader->GetMetaDataDictionaryArray();
348 unsigned int numberOfKeysGiven=0;
349 if(m_ArgsInfo.midP_flag && m_ArgsInfo.key_given)
350 std::cerr<<"Error: both keys and midP option are given"<<std::endl;
351 else if (m_ArgsInfo.midP_flag)
354 numberOfKeysGiven=m_ArgsInfo.key_given;
356 for (unsigned int i = 0; i < numberOfKeysGiven; i++) {
357 std::string entryId(m_ArgsInfo.key_arg[i] );
358 std::string value( m_ArgsInfo.tag_arg[i] );
359 for(unsigned int fni = 0; fni<numberOfFilenames; fni++)
360 itk::EncapsulateMetaData<std::string>( *((*dictionary)[fni]), entryId, value );
363 // Output directory and filenames
364 itksys::SystemTools::MakeDirectory( m_ArgsInfo.outputDir_arg ); // create if it doesn't exist
365 typedef itk::ImageSeriesWriter<InputImageType, OutputImageType > SeriesWriterType;
366 typename SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();
368 seriesWriter->SetInput( volumeReader->GetOutput() );
369 seriesWriter->SetImageIO( gdcmIO );
371 seriesWriter->SetFileNames( filenames_out );
372 seriesWriter->SetMetaDataDictionaryArray( dictionary );
376 seriesWriter->Update();
377 } catch( itk::ExceptionObject & excp ) {
378 std::cerr << "Error: Exception thrown while writing the series!!" << std::endl;
379 std::cerr << excp << std::endl;
387 #endif //#define clitkWriteDicomSeriesGenericFilter_txx