From: tbaudier Date: Thu, 1 Jun 2017 13:25:52 +0000 (+0200) Subject: Add clitkImage2DicomDose tool X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=5ee60b899362a5e87914ae9a46a7c8ea4116219b;p=clitk.git Add clitkImage2DicomDose tool --- diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 999b48a..b0751e6 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -64,7 +64,8 @@ if(CLITK_BUILD_TOOLS) add_executable(clitkBinarizeImage clitkBinarizeImage.cxx) target_link_libraries(clitkBinarizeImage clitkBinarizeImageLib clitkCommon) set(TOOLS_INSTALL ${TOOLS_INSTALL} clitkBinarizeImage) - + + add_executable(clitkProfileImage clitkProfileImage.cxx) target_link_libraries(clitkProfileImage clitkProfileImageLib clitkCommon) set(TOOLS_INSTALL ${TOOLS_INSTALL} clitkProfileImage) @@ -104,6 +105,11 @@ if(CLITK_BUILD_TOOLS) target_link_libraries(clitkGateSimulation2Dicom clitkCommon ) set(TOOLS_INSTALL ${TOOLS_INSTALL} clitkGateSimulation2Dicom) + WRAP_GGO(clitkImage2DicomDose_GGO_C clitkImage2DicomDose.ggo) + add_executable(clitkImage2DicomDose clitkImage2DicomDose.cxx ${clitkImage2DicomDose_GGO_C}) + target_link_libraries(clitkImage2DicomDose clitkCommon) + set(TOOLS_INSTALL ${TOOLS_INSTALL} clitkImage2DicomDose) + WRAP_GGO(clitkMedianTemporalDimension_GGO_C clitkMedianTemporalDimension.ggo) add_executable(clitkMedianTemporalDimension clitkMedianTemporalDimension.cxx ${clitkMedianTemporalDimension_GGO_C}) diff --git a/tools/clitkImage2DicomDose.cxx b/tools/clitkImage2DicomDose.cxx new file mode 100644 index 0000000..6347489 --- /dev/null +++ b/tools/clitkImage2DicomDose.cxx @@ -0,0 +1,53 @@ +/*========================================================================= + Program: vv http://www.creatis.insa-lyon.fr/rio/vv + + Authors belong to: + - University of LYON http://www.universite-lyon.fr/ + - Léon Bérard cancer center http://www.centreleonberard.fr + - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the copyright notices for more information. + + It is distributed under dual licence + + - BSD See included LICENSE.txt file + - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html +===========================================================================**/ + +/* ================================================= + * @file clitkImage2DicomDose.cxx + * @author Jef Vandemeulebroucke + * @date 4th of August + * + * @brief Write a volume into a dicom with the header of another dicom + * + ===================================================*/ + + +// clitk +#include "clitkImage2DicomDose_ggo.h" +#include "clitkIO.h" +#include "clitkImage2DicomDoseGenericFilter.h" +#include "clitkCommon.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) +{ + + // Init command line + GGO(clitkImage2DicomDose, args_info); + CLITK_INIT; + + // Filter + typedef clitk::Image2DicomDoseGenericFilter FilterType; + FilterType::Pointer genericFilter = FilterType::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/tools/clitkImage2DicomDose.ggo b/tools/clitkImage2DicomDose.ggo new file mode 100644 index 0000000..04c7f56 --- /dev/null +++ b/tools/clitkImage2DicomDose.ggo @@ -0,0 +1,11 @@ +#File clitkImage2DicomDose.ggo +package "clitkImage2DicomDose" +version "1.0" +purpose "Convert mhd file into Dicom RTDose fil using a model" + +option "config" - "Config file" string no +option "input" i "inputfile name" string yes +option "DicomInputFile" m "dicom model name" string no +option "output" o "output directory/filename" string yes +option "verbose" v "Verbose" flag off + diff --git a/tools/clitkImage2DicomDoseGenericFilter.cxx b/tools/clitkImage2DicomDoseGenericFilter.cxx new file mode 100644 index 0000000..f7ce6b6 --- /dev/null +++ b/tools/clitkImage2DicomDoseGenericFilter.cxx @@ -0,0 +1,39 @@ +/*========================================================================= + Program: vv http://www.creatis.insa-lyon.fr/rio/vv + + Authors belong to: + - University of LYON http://www.universite-lyon.fr/ + - Léon Bérard cancer center http://www.centreleonberard.fr + - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the copyright notices for more information. + + It is distributed under dual licence + + - BSD See included LICENSE.txt file + - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html +===========================================================================**/ +#ifndef clitkImage2DicomDoseGenericFilter_cxx +#define clitkImage2DicomDoseGenericFilter_cxx + +/* ================================================= + * @file clitkImage2DicomDoseGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkImage2DicomDoseGenericFilter.h" + + +namespace clitk +{ + + +} //end clitk + +#endif //#define clitkImage2DicomDoseGenericFilter_cxx diff --git a/tools/clitkImage2DicomDoseGenericFilter.h b/tools/clitkImage2DicomDoseGenericFilter.h new file mode 100644 index 0000000..b1c1193 --- /dev/null +++ b/tools/clitkImage2DicomDoseGenericFilter.h @@ -0,0 +1,119 @@ +/*========================================================================= + Program: vv http://www.creatis.insa-lyon.fr/rio/vv + + Authors belong to: + - University of LYON http://www.universite-lyon.fr/ + - Léon Bérard cancer center http://www.centreleonberard.fr + - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the copyright notices for more information. + + It is distributed under dual licence + + - BSD See included LICENSE.txt file + - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html +===========================================================================**/ +#ifndef clitkImage2DicomDoseGenericFilter_h +#define clitkImage2DicomDoseGenericFilter_h + +/* ================================================= + * @file clitkImage2DicomDoseGenericFilter.h + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk include +#include "clitkIO.h" +#include "clitkImageCommon.h" +#include "clitkImage2DicomDose_ggo.h" + +//itk include +#include "itkLightObject.h" +#include "itkGDCMImageIO.h" +#include "itkMetaDataDictionary.h" +#include "itkGDCMSeriesFileNames.h" +#include "itkImageSeriesReader.h" +#include "itkImageSeriesWriter.h" +#include "itkImageFileReader.h" +#include "itkImageFileWriter.h" +#include +#include + +namespace clitk +{ + template + class ITK_EXPORT Image2DicomDoseGenericFilter : public itk::LightObject + { + + public: + //---------------------------------------- + // ITK + //---------------------------------------- + typedef Image2DicomDoseGenericFilter Self; + typedef itk::LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( Image2DicomDoseGenericFilter, LightObject ); + + //methods + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_type & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + m_InputFileName=m_ArgsInfo.input_arg; + } + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + Image2DicomDoseGenericFilter(); + ~Image2DicomDoseGenericFilter() {}; + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void UpdateWithDim(std::string PixelType); + template void UpdateWithDimAndPixelType(); + + + gdcm::File * mDCMFile; + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_type m_ArgsInfo; + bool m_Verbose; + std::string m_InputFileName; + + }; + + //Usefull functions + void CopyDictionary (itk::MetaDataDictionary &fromDict, itk::MetaDataDictionary &toDict); + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkImage2DicomDoseGenericFilter.txx" +#endif + +#endif // #define clitkImage2DicomDoseGenericFilter_h diff --git a/tools/clitkImage2DicomDoseGenericFilter.txx b/tools/clitkImage2DicomDoseGenericFilter.txx new file mode 100644 index 0000000..b4fe968 --- /dev/null +++ b/tools/clitkImage2DicomDoseGenericFilter.txx @@ -0,0 +1,587 @@ +/*========================================================================= + Program: vv http://www.creatis.insa-lyon.fr/rio/vv + + Authors belong to: + - University of LYON http://www.universite-lyon.fr/ + - Léon Bérard cancer center http://www.centreleonberard.fr + - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the copyright notices for more information. + + It is distributed under dual licence + + - BSD See included LICENSE.txt file + - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html +===========================================================================**/ +#ifndef clitkImage2DicomDoseGenericFilter_txx +#define clitkImage2DicomDoseGenericFilter_txx + +/* ================================================= + * @file clitkImage2DicomDosemGenericFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "math.h" + +#include "clitkImageToDICOMRTDose.h" +#include "clitkImageToDICOMRTDose_ggo.h" +#if GDCM_MAJOR_VERSION >= 2 +#include "gdcmUIDGenerator.h" +#include +#include +#include +#include +#else +#include "gdcmFile.h" +#include "gdcmUtil.h" +#endif + +//#include "gdcmBase.h" +//#include "gdcmDocEntry.h" + + + +namespace clitk +{ + + +//----------------------------------------------------------- +// Constructor +//----------------------------------------------------------- +template +Image2DicomDoseGenericFilter::Image2DicomDoseGenericFilter() +{ + m_Verbose=false; + m_InputFileName=""; +} + + +//----------------------------------------------------------- +// Update +//----------------------------------------------------------- +template +void Image2DicomDoseGenericFilter::Update() +{ + // Read the Dimension and PixelType + int Dimension; + std::string PixelType; + ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType); + + + // Call UpdateWithDim + if(Dimension==2) UpdateWithDim<2>(PixelType); + else if(Dimension==3) UpdateWithDim<3>(PixelType); + // else if (Dimension==4)UpdateWithDim<4>(PixelType); + else { + std::cout<<"Error, Only for 2 or 3 Dimensions!!!"< +template +void +Image2DicomDoseGenericFilter::UpdateWithDim(std::string PixelType) +{ + if (m_Verbose) std::cout << "Image was detected to be "<(); + } + else if(PixelType == "unsigned_short"){ + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl; + UpdateWithDimAndPixelType(); + } + + else if (PixelType == "unsigned_char") { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl; + UpdateWithDimAndPixelType(); + } + + // else if (PixelType == "char"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + else if (PixelType == "double") { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and double..." << std::endl; + UpdateWithDimAndPixelType(); + } + else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl; + UpdateWithDimAndPixelType(); + } +} + +//------------------------------------------------------------------- +// Update with the number of dimensions and the pixeltype read from +// the dicom files. The MHD files may be resampled to match the +// dicom spacing (and number of slices). Rounding errors in resampling +// are handled by removing files when generating the output dicom +// series. +//------------------------------------------------------------------- +template +template +void +Image2DicomDoseGenericFilter::UpdateWithDimAndPixelType() +{ + +#if GDCM_MAJOR_VERSION == 2 + // ImageTypes + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + typedef itk::ImageFileReader< InputImageType > ReaderType; + typedef itk::ImageSeriesReader< InputImageType > ReaderSeriesType; + typedef itk::ImageRegionIterator< InputImageType > IteratorType; + typedef itk::GDCMImageIO ImageIOType; + + // Read Dicom model file + typename ReaderSeriesType::Pointer readerSeries = ReaderSeriesType::New(); + ImageIOType::Pointer gdcmIO = ImageIOType::New(); + std::string filename_out = m_ArgsInfo.output_arg; + gdcmIO->LoadPrivateTagsOn(); + gdcmIO->KeepOriginalUIDOn(); + typename ReaderSeriesType::FileNamesContainer fileNames; + fileNames.push_back(m_ArgsInfo.DicomInputFile_arg); + readerSeries->SetImageIO( gdcmIO ); + readerSeries->SetFileNames( fileNames ); + try { + readerSeries->Update(); + } catch (itk::ExceptionObject &excp) { + std::cerr << "Error: Exception thrown while reading the DICOM model file !!" << std::endl; + std::cerr << excp << std::endl; + } + + + +//----------------------------------------------------------------------------------- +// opening dicom input file + gdcm::Reader reader2; + reader2.SetFileName( m_ArgsInfo.DicomInputFile_arg ); + reader2.Read(); + gdcm::File &mDCMFile = reader2.GetFile(); + gdcm::DataSet &ds = mDCMFile.GetDataSet(); +//mDCMFile.SetMaxSizeLoadEntry(1006384); // important size required, otherwise some data are not loaded +//mDCMFile.AddForceLoadElement(0x7fe0,0x0010); //Load pixel data no matter its size + +std::cout << "File: "<< m_ArgsInfo.DicomInputFile_arg << " loaded !"<< std::endl; + + + +//----------------------------------------------------------------------------- +// opening image input file +typename ReaderType::Pointer reader = ReaderType::New(); +const char * filename = m_ArgsInfo.input_arg; +reader->SetFileName( filename ); +reader->Update(); +typename InputImageType::Pointer image = reader->GetOutput(); + +// origin +typename InputImageType::PointType origin = image->GetOrigin(); +DD(origin); + +// size +typename InputImageType::SizeType imageSize = image->GetLargestPossibleRegion().GetSize(); +//DD(imageSize); +int NbCols=imageSize[0]; // col +int NbRows=imageSize[1]; // row +int NbFrames=imageSize[2]; // frame +DD(NbCols); +DD(NbRows); +DD(NbFrames); + +// spacing +typename InputImageType::SpacingType Spacing = image->GetSpacing(); +DD(Spacing); + +// scaling +float highestValue=pow(10,-10); +IteratorType out( image, image->GetRequestedRegion() ); +for (out.GoToBegin(); !out.IsAtEnd(); ++out){ +//DD(out.Get()); + if (out.Get()>highestValue) highestValue=out.Get(); +} +double doseScaling = highestValue/(pow(2,16)-1); +DD(doseScaling); + +// image data +std::vector ImageData; +typename InputImageType::IndexType pixelIndex; +int l=0; +unsigned short int pixelValue; +//DD(highestValue); +for (int i=0; iGetPixel(pixelIndex)/doseScaling; +if(float(image->GetPixel(pixelIndex)/doseScaling)>(pow(2,16)-1.)) { +std::cout<<"\n!!!!! WARNING !!!!! pixel index: "< Highest value may become 0"<GetPixel(pixelIndex)); +//DD(image->GetPixel(pixelIndex)/doseScaling); +DD(pixelValue); +std::cout<<"Pixel Value should be equal to "<<(pow(2,16)-1)<<" but should not be 0"<GetMetaDataDictionaryArray()))[0]; + typename ReaderSeriesType::DictionaryArrayType outputArray; + typename ReaderSeriesType::DictionaryRawPointer outputDict = new typename ReaderSeriesType::DictionaryType; + CopyDictionary (*inputDict, *outputDict); + outputArray.push_back(outputDict); + + // Output directory and filenames + typedef itk::ImageSeriesWriter WriterSerieType; + typename WriterSerieType::Pointer writerSerie = WriterSerieType::New(); + writerSerie->SetInput( image ); + writerSerie->SetImageIO( gdcmIO ); + typename ReaderSeriesType::FileNamesContainer fileNamesOutput; + fileNamesOutput.push_back(filename_out); + writerSerie->SetFileNames( fileNamesOutput ); + writerSerie->SetMetaDataDictionaryArray(&outputArray); + + + + + + + + + + + + + + + + + +//-------------------------------------------------------------- +std::cout<<"\nECRITURE DU FICHIER DICOM !"<GetValEntry(0x0028,0x0011); +Value<SetValue(Value.str()); +DD(Value.str()); +Value.str(""); + +// NbRows +b = ((gdcm::SQItem*)mDCMFile)->GetValEntry(0x0028,0x0010); +Value<SetValue(Value.str()); +DD(Value.str()); +Value.str(""); +//DD(Value.str()); + +// NbFrames +b = ((gdcm::SQItem*)mDCMFile)->GetValEntry(0x0028,0x0008); +Value<SetValue(Value.str()); +DD(Value.str()); +Value.str(""); + +// doseScaling +b = ((gdcm::SQItem*)mDCMFile)->GetValEntry(0x3004,0x000e); +Value<SetValue(Value.str()); +DD(Value.str()); +Value.str(""); + +// Spacing X Y +b = ((gdcm::SQItem*)mDCMFile)->GetValEntry(0x0028, 0x0030); +Value<SetValue(Value.str()); +DD(Value.str()); +Value.str(""); + +// Spacing Z ([Grid Frame Offset Vector]) +b = ((gdcm::SQItem*)mDCMFile)->GetValEntry(0x3004, 0x000c); +float offset=0.; +Value<SetValue(Value.str()); +DD(Value.str()); +Value.str(""); +*/ +//ImageData +//bool data = mDCMFile->SetBinEntry(reinterpret_cast( &(ImageData[0]) ) , (int)(sizeof(unsigned short int) * ImageData.size()) , 0x7fe0, 0x0010); +//if (data) std::cout<<"\n DICOM dose data written !"<GetFileType(); +//type=(gdcm::FileType)2; +bool ecriture = mDCMFile->Write (args_info.OutputFile_arg, type); +if (ecriture) std::cout<<"\n DICOM File written !"<GetImageDataRawSize(); + imageData = fh->GetImageDataRaw();// somewhat important : Loads the Pixels in memory ! + + fh->SetWriteModeToRaw(); + fh->SetWriteTypeToDcmExplVR(); + + bool res = fh->Write(args_info.OutputFile_arg); + + if(!res) + std::cout <<"Fail to write [" << args_info.OutputFile_arg << "]" <Delete(); + +//--------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------- +// Jean-Pierre Roux help for DICOM-RT-DOSE writting +//--------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------- + +// de Jean-Pierre Roux +// répondre à jpr@creatis.insa-lyon.fr +// à Loic Grevillot +// cc jpr@creatis.insa-lyon.fr, +// Joël Schaerer , +// David Sarrut , +// Joel Schaerer +// date 12 juillet 2010 12:23 +// objet Re: DICOM RT DOSE +// +// masquer les détails 12:23 (Il y a 21 heures) +// +// Bonjour, +// +// J'aurais écrit à peut prèt la même chose. +// (Ci après un extrait de mon code -Example/ReWrite.cxx-) +// +// 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. +// Je décompresse, et réécrit non compressé. +// +// ============================ +// gdcm::File *f = new gdcm::File(); +// f->SetMaxSizeLoadEntry(0x7fffffff); +// f->SetFileName( fileName ); +// bool res = f->Load(); +// if ( !res ) +// { +// delete f; +// return 0; +// } +// +// if (!f->IsReadable()) +// { +// std::cerr << "Sorry, not a Readable DICOM / ACR File" <GetImageDataRawSize(); +// imageData = fh->GetImageDataRaw();// somewhat important : Loads the Pixels in memory ! +// +// fh->SetWriteModeToRaw(); +// fh->SetWriteTypeToDcmExplVR(); +// res = fh->Write(outputFileName); +// +// if(!res) +// std::cout <<"Fail to write [" << outputFileName << "]" <Delete(); +// fh->Delete(); + +//--------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------- +// pour supprimer des tags: +//--------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------- +// SOLUCE 1 QUI MARCHE POUR UN SQItem SIMPLE +/* +gdcm::DocEntry *a; +//a= ((gdcm::SQItem*)mDCMFile)->GetDocEntry(0xfffe,0xe00d); +a= ((gdcm::SQItem*)mDCMFile)->GetDocEntry(0x3004,0x000e); +((gdcm::SQItem*)mDCMFile)->RemoveEntry(a); +mDCMFile->Write (args_info.OutputFile_arg, type); +*/ + +// SOLUCE 2 QUI MARCHE POUR UNE SeqEntry->SQItem +/* +std::cout<<"\ntest correction fichier apres ecriture\n"<GetSeqEntry(0x300c,0x0002); +gdcm::SQItem* currentItem = seqEntry->GetFirstSQItem(); +gdcm::DocEntry *a; +//a= currentItem->GetDocEntry(0x0008,0x1155); +a= currentItem->GetDocEntry(0xfffe,0xe00d); +currentItem->RemoveEntry(a); +mDCMFile->Write (args_info.OutputFile_arg, type); +*/ + +//gdcm::DocEntry *a; +//a=GetDocEntry(0x7fe0,0x0000); +//((gdcm::SQItem*)mDCMFile)->RemoveEntry(a); + +//----------------------------------------------------------------------------------- +std::cout <<"\n## DICOM Image to RT DOSE application is ended..."< MetaDataStringType; + + while( itr != end ) + { + itk::MetaDataObjectBase::Pointer entry = itr->second; + + MetaDataStringType::Pointer entryvalue = + dynamic_cast( entry.GetPointer() ) ; + if( entryvalue ) + { + std::string tagkey = itr->first; + std::string tagvalue = entryvalue->GetMetaDataObjectValue(); + itk::EncapsulateMetaData(toDict, tagkey, tagvalue); + } + ++itr; + } +} +//--------------------------------------------------------------------------- +}//end clitk + +#endif //#define clitkImage2DicomDoseGenericFilter_txx