]> Creatis software - clitk.git/blob - tools/clitkImage2DicomDoseGenericFilter.txx
Precision on clitkBlurImage help
[clitk.git] / tools / clitkImage2DicomDoseGenericFilter.txx
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 #ifndef clitkImage2DicomDoseGenericFilter_txx
19 #define clitkImage2DicomDoseGenericFilter_txx
20
21 /* =================================================
22  * @file   clitkImage2DicomDosemGenericFilter.txx
23  * @author
24  * @date
25  *
26  * @brief
27  *
28  ===================================================*/
29
30 #include "math.h"
31
32 #include "clitkImage2DicomDoseGenericFilter.h"
33 #include "clitkCommon.h"
34 #if GDCM_MAJOR_VERSION >= 2
35 #include "gdcmUIDGenerator.h"
36 #include <gdcmImageHelper.h>
37 #include <gdcmAttribute.h>
38 #include <gdcmReader.h>
39 #include <gdcmWriter.h>
40 #else
41 #include "gdcmFile.h"
42 #include "gdcmUtil.h"
43 #endif
44
45 //#include "gdcmBase.h"
46 //#include "gdcmDocEntry.h"
47
48
49
50 namespace clitk
51 {
52
53
54 //-----------------------------------------------------------
55 // Constructor
56 //-----------------------------------------------------------
57 template<class args_info_type>
58 Image2DicomDoseGenericFilter<args_info_type>::Image2DicomDoseGenericFilter()
59 {
60   m_Verbose=false;
61   m_InputFileName="";
62 }
63
64
65 //-----------------------------------------------------------
66 // Update
67 //-----------------------------------------------------------
68 template<class args_info_type>
69 void Image2DicomDoseGenericFilter<args_info_type>::Update()
70 {
71   // Read the Dimension and PixelType
72   int Dimension;
73   std::string PixelType;
74   ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType);
75
76
77   // Call UpdateWithDim
78   if(Dimension==2) UpdateWithDim<2>(PixelType);
79   else if(Dimension==3) UpdateWithDim<3>(PixelType);
80   // else if (Dimension==4)UpdateWithDim<4>(PixelType);
81   else {
82     std::cout<<"Error, Only for 2 or 3  Dimensions!!!"<<std::endl ;
83     return;
84   }
85 }
86
87 //-------------------------------------------------------------------
88 // Update with the number of dimensions
89 //-------------------------------------------------------------------
90 template<class args_info_type>
91 template<unsigned int Dimension>
92 void
93 Image2DicomDoseGenericFilter<args_info_type>::UpdateWithDim(std::string PixelType)
94 {
95   if (m_Verbose) std::cout << "Image was detected to be "<<Dimension<<"D and "<< PixelType<<"..."<<std::endl;
96
97   if(PixelType == "short") {
98     if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed short..." << std::endl;
99     UpdateWithDimAndPixelType<Dimension, signed short>();
100   }
101   else if(PixelType == "unsigned_short"){
102     if (m_Verbose) std::cout  << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl;
103     UpdateWithDimAndPixelType<Dimension, unsigned short>();
104   }
105
106   else if (PixelType == "unsigned_char") {
107     if (m_Verbose) std::cout  << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl;
108     UpdateWithDimAndPixelType<Dimension, unsigned char>();
109   }
110
111   //     else if (PixelType == "char"){
112   //       if (m_Verbose) std::cout  << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl;
113   //       UpdateWithDimAndPixelType<Dimension, signed char>();
114   //     }
115   else if (PixelType == "double") {
116     if (m_Verbose) std::cout  << "Launching filter in "<< Dimension <<"D and double..." << std::endl;
117     UpdateWithDimAndPixelType<Dimension, double>();
118   }
119   else {
120     if (m_Verbose) std::cout  << "Launching filter in "<< Dimension <<"D and float..." << std::endl;
121     UpdateWithDimAndPixelType<Dimension, float>();
122   }
123 }
124
125 //-------------------------------------------------------------------
126 // Update with the number of dimensions and the pixeltype read from
127 // the dicom files. The MHD files may be resampled to match the
128 // dicom spacing (and number of slices). Rounding errors in resampling
129 // are handled by removing files when generating the output dicom
130 // series.
131 //-------------------------------------------------------------------
132 template<class args_info_type>
133 template <unsigned int Dimension, class  PixelType>
134 void
135 Image2DicomDoseGenericFilter<args_info_type>::UpdateWithDimAndPixelType()
136 {
137
138 #if GDCM_MAJOR_VERSION == 2
139   // ImageTypes
140   typedef itk::Image<PixelType, Dimension> InputImageType;
141   typedef itk::Image<PixelType, Dimension> OutputImageType;
142   typedef itk::ImageFileReader< InputImageType >     ReaderType;
143   typedef itk::ImageSeriesReader< InputImageType >     ReaderSeriesType;
144   typedef itk::ImageRegionIterator< InputImageType > IteratorType;
145   typedef itk::GDCMImageIO ImageIOType;
146
147   // Read Dicom model file
148   typename ReaderSeriesType::Pointer readerSeries = ReaderSeriesType::New();
149   ImageIOType::Pointer gdcmIO = ImageIOType::New();
150   std::string filename_out = m_ArgsInfo.output_arg;
151   gdcmIO->LoadPrivateTagsOn();
152   gdcmIO->KeepOriginalUIDOn();
153   typename ReaderSeriesType::FileNamesContainer fileNames;
154   fileNames.push_back(m_ArgsInfo.DicomInputFile_arg);
155   readerSeries->SetImageIO( gdcmIO );
156   readerSeries->SetFileNames( fileNames );
157   try {
158     readerSeries->Update();
159   } catch (itk::ExceptionObject &excp) {
160     std::cerr << "Error: Exception thrown while reading the DICOM model file !!" << std::endl;
161     std::cerr << excp << std::endl;
162   }
163
164
165
166 //-----------------------------------------------------------------------------------
167 // opening dicom input file
168   gdcm::Reader reader2;
169   reader2.SetFileName( m_ArgsInfo.DicomInputFile_arg );
170   reader2.Read();
171   gdcm::File &mDCMFile = reader2.GetFile();
172   gdcm::DataSet &ds = mDCMFile.GetDataSet();
173 //mDCMFile.SetMaxSizeLoadEntry(1006384); // important size required, otherwise some data are not loaded
174 //mDCMFile.AddForceLoadElement(0x7fe0,0x0010); //Load pixel data no matter its size
175
176 std::cout << "File:   "<< m_ArgsInfo.DicomInputFile_arg << "   loaded !"<< std::endl;
177
178
179
180 //-----------------------------------------------------------------------------
181 // opening image input file
182 typename ReaderType::Pointer reader = ReaderType::New();
183 const char * filename = m_ArgsInfo.input_arg;
184 reader->SetFileName( filename );
185 reader->Update();
186 typename InputImageType::Pointer image = reader->GetOutput();
187
188 // origin
189 typename InputImageType::PointType origin = image->GetOrigin();
190 DD(origin);
191
192 // size
193 typename InputImageType::SizeType imageSize = image->GetLargestPossibleRegion().GetSize();
194 //DD(imageSize);
195 int NbCols=imageSize[0];        // col
196 int NbRows=imageSize[1];        // row
197 int NbFrames=imageSize[2];      // frame
198 DD(NbCols);
199 DD(NbRows);
200 DD(NbFrames);
201
202 // spacing
203 typename InputImageType::SpacingType Spacing = image->GetSpacing();
204 DD(Spacing);
205
206 // scaling
207 float highestValue=pow(10,-10);
208 IteratorType out( image, image->GetRequestedRegion() );
209 for (out.GoToBegin(); !out.IsAtEnd(); ++out){
210 //DD(out.Get());
211   if (out.Get()>highestValue) highestValue=out.Get();
212 }
213 double doseScaling = highestValue/(pow(2,16)-1);
214 DD(doseScaling);
215
216 // image data
217 std::vector<unsigned short int> ImageData;
218 typename InputImageType::IndexType pixelIndex;
219 int l=0;
220 unsigned short int pixelValue;
221 //DD(highestValue);
222 for (int i=0; i<NbFrames; i++){
223   pixelIndex[2] = i;
224   for (int j=0; j<NbRows; j++){
225     pixelIndex[1] = j;
226     for (int k=0; k<NbCols; k++){
227         pixelIndex[0] = k;
228         pixelValue=image->GetPixel(pixelIndex)/doseScaling;
229 if(float(image->GetPixel(pixelIndex)/doseScaling)>(pow(2,16)-1.)) {
230 std::cout<<"\n!!!!! WARNING !!!!! pixel index: "<<pixelIndex<<"unsigned short int capacity ful or overfuled => Highest value may become 0"<<std::endl;
231 DD(pixelIndex);
232 DD(image->GetPixel(pixelIndex));
233 //DD(image->GetPixel(pixelIndex)/doseScaling);
234 DD(pixelValue);
235 std::cout<<"Pixel Value should be equal to "<<(pow(2,16)-1)<<" but should not be 0"<<std::endl;
236 std::cout<<"\n"<<std::endl;
237 //assert(pixelValue<=(pow(2,16)-1));    should work, but do not...
238 }
239 //DD(pixelValue);
240         ImageData.push_back(pixelValue);
241         l++;
242     }
243   }
244 }
245 DD(ImageData.size());
246
247 // Relevant parameters inserted in the new dicom file
248 /*
249 ImagePosition
250 NbCols
251 NbRows
252 NbFrames
253 Spacing
254 ImageData
255 doseScaling
256 */
257
258   typename ReaderSeriesType::DictionaryRawPointer inputDict = (*(readerSeries->GetMetaDataDictionaryArray()))[0];
259   typename ReaderSeriesType::DictionaryArrayType outputArray;
260   typename ReaderSeriesType::DictionaryRawPointer outputDict = new typename ReaderSeriesType::DictionaryType;
261   CopyDictionary (*inputDict, *outputDict);
262   outputArray.push_back(outputDict);
263
264   // Output directory and filenames
265   typedef itk::ImageSeriesWriter<OutputImageType, OutputImageType>  WriterSerieType;
266   typename WriterSerieType::Pointer writerSerie = WriterSerieType::New();
267   writerSerie->SetInput( image );
268   writerSerie->SetImageIO( gdcmIO );
269   typename ReaderSeriesType::FileNamesContainer fileNamesOutput;
270   fileNamesOutput.push_back(filename_out);
271   writerSerie->SetFileNames( fileNamesOutput );
272   writerSerie->SetMetaDataDictionaryArray(&outputArray);
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290 //--------------------------------------------------------------
291 std::cout<<"\nECRITURE DU FICHIER DICOM !"<<std::endl;
292
293 //gdcm::ValEntry *b;
294 std::string Value("");
295
296
297 gdcm::DataElement DE;
298
299 DE = gdcm::Tag(0x20, 0x32);
300 Value = origin[0];
301 Value += "\\";
302 Value += origin[1];
303 Value += "\\";
304 Value += origin[2];
305 DE.SetVR( gdcm::VR::US );
306 DE.SetByteValue(Value.c_str(), 1);
307 ds.Insert(DE);
308 DD(Value);
309 Value = "";
310
311 DE = gdcm::Tag(0x28, 0x11);
312 Value = NbCols;
313 DE.SetVR( gdcm::VR::US );
314 DE.SetByteValue(Value.c_str(), 1);
315 ds.Insert(DE);
316 DD(Value);
317 Value = "";
318
319 DE = gdcm::Tag(0x28, 0x10);
320 Value = NbRows;
321 DE.SetVR( gdcm::VR::US );
322 DE.SetByteValue(Value.c_str(), 1);
323 ds.Insert(DE);
324 DD(Value);
325 Value = "";
326
327 DE = gdcm::Tag(0x28, 0x08);
328 Value = NbFrames;
329 DE.SetVR( gdcm::VR::US );
330 DE.SetByteValue(Value.c_str(), 1);
331 ds.Insert(DE);
332 DD(Value);
333 Value = "";
334
335 DE = gdcm::Tag(0x3004, 0x0e);
336 Value = doseScaling;
337 DE.SetVR( gdcm::VR::US );
338 DE.SetByteValue(Value.c_str(), 1);
339 ds.Insert(DE);
340 DD(Value);
341 Value = "";
342
343 DE = gdcm::Tag(0x28, 0x30);
344 Value = Spacing[0];
345 Value += "\\";
346 Value += Spacing[1];
347 DE.SetVR( gdcm::VR::US );
348 DE.SetByteValue(Value.c_str(), 1);
349 ds.Insert(DE);
350 DD(Value);
351 Value = "";
352
353 DE = gdcm::Tag(0x3004, 0x000c);
354 float offset = 0.;
355 Value = offset;
356   for (int i=1; i<NbFrames ; i++){
357     offset+=Spacing[2];
358     Value += "\\";
359     Value += offset;
360   }
361
362 DE.SetVR( gdcm::VR::US );
363 DE.SetByteValue(Value.c_str(), 1);
364 ds.Insert(DE);
365 DD(Value);
366 Value = "";
367
368 /*
369 // NbCols
370 b = ((gdcm::SQItem*)mDCMFile)->GetValEntry(0x0028,0x0011);
371 Value<<NbCols;
372 b->SetValue(Value.str());
373 DD(Value.str());
374 Value.str("");
375
376 // NbRows
377 b = ((gdcm::SQItem*)mDCMFile)->GetValEntry(0x0028,0x0010);
378 Value<<NbRows;
379 b->SetValue(Value.str());
380 DD(Value.str());
381 Value.str("");
382 //DD(Value.str());
383
384 // NbFrames
385 b = ((gdcm::SQItem*)mDCMFile)->GetValEntry(0x0028,0x0008);
386 Value<<NbFrames;
387 b->SetValue(Value.str());
388 DD(Value.str());
389 Value.str("");
390
391 // doseScaling
392 b = ((gdcm::SQItem*)mDCMFile)->GetValEntry(0x3004,0x000e);
393 Value<<doseScaling;
394 b->SetValue(Value.str());
395 DD(Value.str());
396 Value.str("");
397
398 // Spacing X Y
399 b = ((gdcm::SQItem*)mDCMFile)->GetValEntry(0x0028, 0x0030);
400 Value<<Spacing[0]<<'\\'<<Spacing[1];
401 b->SetValue(Value.str());
402 DD(Value.str());
403 Value.str("");
404
405 // Spacing Z ([Grid Frame Offset Vector])
406 b = ((gdcm::SQItem*)mDCMFile)->GetValEntry(0x3004, 0x000c);
407 float offset=0.;
408 Value<<offset;
409   for (int i=1; i<NbFrames ; i++){
410     offset+=Spacing[2];
411     Value<<'\\'<<offset;
412   }
413 b->SetValue(Value.str());
414 DD(Value.str());
415 Value.str("");  
416 */
417 //ImageData
418 //bool data = mDCMFile->SetBinEntry(reinterpret_cast<uint8_t*>( &(ImageData[0]) ) , (int)(sizeof(unsigned short int) * ImageData.size()) , 0x7fe0, 0x0010);
419 //if (data)  std::cout<<"\n DICOM dose data written !"<<std::endl;
420
421 //---------------------------------------------------------------------------------------
422 //WRITE DICOM
423 /*gdcm::FileType type = mDCMFile->GetFileType();
424 //type=(gdcm::FileType)2;
425 bool ecriture = mDCMFile->Write (args_info.OutputFile_arg, type);
426 if (ecriture) std::cout<<"\n DICOM File written !"<<std::endl;
427 */
428 //---------------------------------------------------------------------------------------
429 //WRITE DICOM BIS
430 // The previous way of writting DICOM-RT-DOSE works only for ITK
431 // and resulting RT-DOSE files are not readable by commercial systems.
432 // The nex step is to copy again the output file with another syntax, allowing to make RT-DOSE files readable by commercial systems.
433 // see Jean-Pierre Roux comment below.
434
435 /*gdcm::FileHelper *fh = new gdcm::FileHelper(args_info.OutputFile_arg);
436    void *imageData;
437    int dataSize;
438   
439    dataSize  = fh->GetImageDataRawSize();
440    imageData = fh->GetImageDataRaw();// somewhat important : Loads the Pixels in memory !
441   
442    fh->SetWriteModeToRaw();
443    fh->SetWriteTypeToDcmExplVR();
444
445    bool res = fh->Write(args_info.OutputFile_arg);
446
447    if(!res)
448       std::cout <<"Fail to write [" << args_info.OutputFile_arg << "]" <<std::endl;   
449    else std::cout<<"\n DICOM File re-written, using the FileHelper syntax, in order to be processed by commercial systems !"<<std::endl;
450
451 delete fh; */
452   gdcm::Writer w;
453   w.SetFile(mDCMFile);
454   w.SetFileName(m_ArgsInfo.output_arg);
455   w.Write();
456 //   fh->Delete();
457
458 //---------------------------------------------------------------------------------------
459 //---------------------------------------------------------------------------------------
460 // Jean-Pierre Roux help for DICOM-RT-DOSE writting
461 //---------------------------------------------------------------------------------------
462 //---------------------------------------------------------------------------------------
463
464 //      de      Jean-Pierre Roux <jpr@creatis.insa-lyon.fr>
465 // répondre à jpr@creatis.insa-lyon.fr
466 // à   Loic Grevillot <loic.grevillot@gmail.com>
467 // cc   jpr@creatis.insa-lyon.fr,
468 // Joël Schaerer <joel.schaerer@gmail.com>,
469 // David Sarrut <David.Sarrut@creatis.insa-lyon.fr>,
470 // Joel Schaerer <joel.schaerer@creatis.insa-lyon.fr>
471 // date 12 juillet 2010 12:23
472 // objet        Re: DICOM RT DOSE
473 //      
474 // masquer les détails 12:23 (Il y a 21 heures)
475 //      
476 // Bonjour,
477 // 
478 // J'aurais écrit à peut prèt la même chose.
479 // (Ci après un extrait de mon code -Example/ReWrite.cxx-)
480 // 
481 // L'utilisation d'un FileHelper (qui ne changera rien dans ce cas précis) est une mesure de précaution, car,  l'élément 7FE0|0010 peut être compressé (ce qui n'est pas le cas pour tes images), que la manière de stocker les pixels ainsi compressés était parfois un peu ... curieuse.
482 // Je décompresse, et réécrit non compressé.
483 // 
484 // ============================
485 //    gdcm::File *f = new gdcm::File();
486 //    f->SetMaxSizeLoadEntry(0x7fffffff);
487 //    f->SetFileName( fileName );
488 //    bool res = f->Load(); 
489 //    if ( !res )
490 //    {
491 //       delete f;
492 //       return 0;
493 //    }
494 // 
495 //    if (!f->IsReadable())
496 //    {
497 //        std::cerr << "Sorry, not a Readable DICOM / ACR File"  <<std::endl;
498 //        delete f;
499 //        return 0;
500 //    }
501 // 
502 //    gdcm::FileHelper *fh = new gdcm::FileHelper(f);
503 //    void *imageData;
504 //    int dataSize;
505 //   
506 //    dataSize  = fh->GetImageDataRawSize();
507 //    imageData = fh->GetImageDataRaw();// somewhat important : Loads the Pixels in memory !
508 //   
509 //    fh->SetWriteModeToRaw();
510 //    fh->SetWriteTypeToDcmExplVR();
511 //    res = fh->Write(outputFileName);
512 //   
513 //    if(!res)
514 //       std::cout <<"Fail to write [" << outputFileName << "]" <<std::endl;   
515 // 
516 //    f->Delete();
517 //    fh->Delete();
518
519 //---------------------------------------------------------------------------------------
520 //---------------------------------------------------------------------------------------
521 // pour supprimer des tags:
522 //---------------------------------------------------------------------------------------
523 //---------------------------------------------------------------------------------------
524 //      SOLUCE 1 QUI MARCHE POUR UN SQItem SIMPLE
525 /*
526 gdcm::DocEntry *a;
527 //a= ((gdcm::SQItem*)mDCMFile)->GetDocEntry(0xfffe,0xe00d);
528 a= ((gdcm::SQItem*)mDCMFile)->GetDocEntry(0x3004,0x000e);
529 ((gdcm::SQItem*)mDCMFile)->RemoveEntry(a);
530 mDCMFile->Write (args_info.OutputFile_arg, type);
531 */
532
533 //      SOLUCE 2 QUI MARCHE POUR UNE SeqEntry->SQItem 
534 /*
535 std::cout<<"\ntest correction fichier apres ecriture\n"<<std::endl;
536 gdcm::SeqEntry *seqEntry = mDCMFile->GetSeqEntry(0x300c,0x0002);
537 gdcm::SQItem* currentItem = seqEntry->GetFirstSQItem();
538 gdcm::DocEntry *a;
539 //a= currentItem->GetDocEntry(0x0008,0x1155);
540 a= currentItem->GetDocEntry(0xfffe,0xe00d);
541 currentItem->RemoveEntry(a);
542 mDCMFile->Write (args_info.OutputFile_arg, type);
543 */
544
545 //gdcm::DocEntry *a;
546 //a=GetDocEntry(0x7fe0,0x0000);
547 //((gdcm::SQItem*)mDCMFile)->RemoveEntry(a);
548
549 //-----------------------------------------------------------------------------------
550 std::cout <<"\n## DICOM Image to RT DOSE application is ended..."<<std::endl;
551 std::cout <<"#########################################################\n" << std::endl;
552
553 #else
554   std::cout << "Use GDCM2" << std::endl;
555 #endif
556 }
557 //---------------------------------------------------------------------------
558
559
560 //---------------------------------------------------------------------------
561 void CopyDictionary (itk::MetaDataDictionary &fromDict, itk::MetaDataDictionary &toDict)
562 {
563   typedef itk::MetaDataDictionary DictionaryType;
564
565   DictionaryType::ConstIterator itr = fromDict.Begin();
566   DictionaryType::ConstIterator end = fromDict.End();
567   typedef itk::MetaDataObject< std::string > MetaDataStringType;
568
569   while( itr != end )
570     {
571     itk::MetaDataObjectBase::Pointer  entry = itr->second;
572
573     MetaDataStringType::Pointer entryvalue =
574       dynamic_cast<MetaDataStringType *>( entry.GetPointer() ) ;
575     if( entryvalue )
576       {
577       std::string tagkey   = itr->first;
578       std::string tagvalue = entryvalue->GetMetaDataObjectValue();
579       itk::EncapsulateMetaData<std::string>(toDict, tagkey, tagvalue);
580       }
581     ++itr;
582     }
583 }
584 //---------------------------------------------------------------------------
585 }//end clitk
586
587 #endif //#define clitkImage2DicomDoseGenericFilter_txx