From 69a03a1914d6d2b1c872aac94ace103cb3f177b3 Mon Sep 17 00:00:00 2001 From: David Sarrut Date: Thu, 17 Apr 2014 14:30:05 +0200 Subject: [PATCH] Allow to correct for dicom with negative spacing (dcm to mhd) --- tools/clitkImageConvert.cxx | 2 +- tools/clitkImageConvert.ggo | 1 + tools/clitkImageConvertGenericFilter.cxx | 92 ++++++++++++++++++++++-- tools/clitkImageConvertGenericFilter.h | 57 +++++++-------- 4 files changed, 118 insertions(+), 34 deletions(-) diff --git a/tools/clitkImageConvert.cxx b/tools/clitkImageConvert.cxx index 3a9beaf..8138682 100644 --- a/tools/clitkImageConvert.cxx +++ b/tools/clitkImageConvert.cxx @@ -68,6 +68,7 @@ int main(int argc, char * argv[]) filter->SetIOVerbose(args_info.verbose_flag); filter->SetOutputFilename(output); filter->SetVV(args_info.vv_flag); + filter->SetCorrectNegativeSpacingFlag(args_info.correct_flag); filter->EnableWriteCompression(args_info.compression_flag); if (args_info.type_given) filter->SetOutputPixelType(args_info.type_arg); @@ -80,4 +81,3 @@ int main(int argc, char * argv[]) //-------------------------------------------------------------------= #endif /* end #define CLITKIMAGECONVERT_CXX */ - diff --git a/tools/clitkImageConvert.ggo b/tools/clitkImageConvert.ggo index b6f003c..6d74318 100644 --- a/tools/clitkImageConvert.ggo +++ b/tools/clitkImageConvert.ggo @@ -10,3 +10,4 @@ option "type" t "Output type (float, ushort ...)" option "verbose" v "Verbose" flag off option "compression" c "Compress output" flag off option "vv" - "Read image as in vv and save transform in meta information" flag off +option "correct" - "Correct dicom with negative Z spacing" flag off diff --git a/tools/clitkImageConvertGenericFilter.cxx b/tools/clitkImageConvertGenericFilter.cxx index 2783053..a603385 100644 --- a/tools/clitkImageConvertGenericFilter.cxx +++ b/tools/clitkImageConvertGenericFilter.cxx @@ -15,12 +15,21 @@ - BSD See included LICENSE.txt file - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html ===========================================================================**/ + #ifndef CLITKIMAGECONVERTGENERICFILTER_CXX #define CLITKIMAGECONVERTGENERICFILTER_CXX #include "clitkImageConvertGenericFilter.h" #include "vvImageReader.h" #include "vvImageWriter.h" +#include "itkFlipImageFilter.h" +#include "itkGDCMImageIO.h" + +#include "gdcmReader.h" +#include "gdcmAttribute.h" +#include "gdcmPrinter.h" +#include "gdcmDict.h" +#include "gdcmStringFilter.h" //-------------------------------------------------------------------- clitk::ImageConvertGenericFilter::ImageConvertGenericFilter(): @@ -30,7 +39,8 @@ clitk::ImageConvertGenericFilter::ImageConvertGenericFilter(): mDisplayWarning = true; mWarning = ""; mWarningOccur = false; - + SetCorrectNegativeSpacingFlag(false); + InitializeImageType<2>(); InitializeImageType<3>(); InitializeImageType<4>(); @@ -90,12 +100,85 @@ void clitk::ImageConvertGenericFilter::UpdateWithInputImageType() return; } else if ((m_PixelTypeName == mOutputPixelTypeName) || (mOutputPixelTypeName == "NotSpecified")) { + + // Get input image typename InputImageType::Pointer input = this->template GetInput(0); - this->SetNextOutput(input); + + if (mCorrectNegativeSpacingFlag) { + // Read dicom + gdcm::Reader reader; + reader.SetFileName(m_InputFilenames[0].c_str()); + // if (!reader.CanReadFile(m_InputFilenames[0])) { + // std::cout << "Error: " << m_InputFilenames[0] << " is not a dicom file. Abort." << std::endl; + // exit(0); + // } + reader.Read(); + + // the dataset is the the set of element we are interested in: + gdcm::DataSet & ds = reader.GetFile().GetDataSet(); + + // Read the attribute SpacingBetweenSlices, check if negative and replace + gdcm::Attribute<0x0018,0x0088> SpacingBetweenSlices; + SpacingBetweenSlices.SetFromDataSet(ds); + double s = SpacingBetweenSlices.GetValue(); + if (s >=0) { + std::cout << "Error: no negative spacing found SpacingBetweenSlices = " << s << " Abort. " << std::endl; + exit(0); + } + s = -s; + + // Set spacing + typename InputImageType::SpacingType spacing = input->GetSpacing(); + spacing[2] = s; + input->SetSpacing(spacing); + + // Flip + typedef itk::FlipImageFilter< InputImageType > FilterType; + typename FilterType::Pointer filter = FilterType::New(); + typedef typename FilterType::FlipAxesArrayType FlipAxesArrayType; + FlipAxesArrayType flipArray; + flipArray[0] = false; + flipArray[1] = false; + flipArray[2] = true; + filter->SetFlipAxes(flipArray); + filter->SetInput(input); + filter->Update(); + + // Read the attribute Image Position (Patient) + gdcm::Tag DetectorInformationSequenceTag(0x0054,0x0022); + const gdcm::DataElement & DIS = ds.GetDataElement(DetectorInformationSequenceTag); + gdcm::SmartPointer sqf = DIS.GetValueAsSQ(); + gdcm::Item & item = sqf->GetItem(1); + gdcm::DataSet & ds_position = item.GetNestedDataSet(); + gdcm::Attribute<0x0020,0x0032> ImagePositionPatient; + ImagePositionPatient.SetFromDataSet(ds_position); + double x = ImagePositionPatient.GetValue(0); + double y = ImagePositionPatient.GetValue(1); + double z = ImagePositionPatient.GetValue(2); + + // Set offset + typename InputImageType::PointType origin = input->GetOrigin(); + origin[0] = x; + origin[1] = y; + origin[2] = z; + input->SetOrigin(origin); + + // Orientation + typename InputImageType::DirectionType direction = input->GetDirection(); + direction[2][2] = -1; + input->SetDirection(direction); + + // Empty meta info + itk::MetaDataDictionary dict;// = new itk::MetaDataDictionary; + input->SetMetaDataDictionary(dict); + + this->SetNextOutput(input); + } + } else { - // "trick" to call independent versions of update according to the + // "trick" to call independent versions of update according to the // pixel type (vector or scalar), using partial specializations - if (!UpdateWithSelectiveOutputType::IS_VECTOR>::Run(*this, mOutputPixelTypeName)) + if (!UpdateWithSelectiveOutputType::IS_VECTOR>::Run(*this, mOutputPixelTypeName)) exit(-1); } } @@ -143,4 +226,3 @@ void clitk::ImageConvertGenericFilter::CheckTypes( #endif /* end #define CLITKIMAGECONVERTGENERICFILTER_CXX */ - diff --git a/tools/clitkImageConvertGenericFilter.h b/tools/clitkImageConvertGenericFilter.h index 8ffb360..aa8b2ba 100644 --- a/tools/clitkImageConvertGenericFilter.h +++ b/tools/clitkImageConvertGenericFilter.h @@ -1,7 +1,7 @@ /*========================================================================= Program: vv http://www.creatis.insa-lyon.fr/rio/vv - Authors belong to: + 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 @@ -23,7 +23,7 @@ * @author David Sarrut * @date 05 May 2008 10:40:24 - * @brief + * @brief ===================================================================*/ @@ -36,7 +36,7 @@ namespace clitk { - + template class ImageConvertTraits { @@ -47,17 +47,17 @@ namespace clitk { } }; - template < class TPixel, unsigned int Comp > - class ImageConvertTraits< itk::Vector > - { - public: - enum { IS_VECTOR = true }; + template < class TPixel, unsigned int Comp > + class ImageConvertTraits< itk::Vector > + { + public: + enum { IS_VECTOR = true }; }; - class ImageConvertGenericFilter: + class ImageConvertGenericFilter: public clitk::ImageToImageGenericFilter { - - public: + + public: // constructor - destructor ImageConvertGenericFilter(); @@ -68,7 +68,7 @@ namespace clitk { // New itkNewMacro(Self); - + // Members functions std::string GetInputPixelTypeName() { return m_PixelTypeName; } std::string GetOutputPixelTypeName() { return mOutputPixelTypeName; } @@ -77,15 +77,16 @@ namespace clitk { bool IsWarningOccur() { return mWarningOccur; } std::string & GetWarning() { return mWarning; } void EnableDisplayWarning(bool b) { mDisplayWarning = b; } + void SetCorrectNegativeSpacingFlag(bool b) { mCorrectNegativeSpacingFlag = b; } //-------------------------------------------------------------------- // Main function called each time the filter is updated - template + template void UpdateWithInputImageType(); template void CheckTypes(std::string inType, std::string outType); - + protected: template void InitializeImageType(); @@ -94,6 +95,7 @@ namespace clitk { bool mWarningOccur; bool mDisplayWarning; bool mVV; + bool mCorrectNegativeSpacingFlag; private: template @@ -119,17 +121,17 @@ namespace clitk { else { std::string list = CreateListOfTypes(); - std::cerr << "Error, I don't know the vector output type '" << outputPixelType + std::cerr << "Error, I don't know the vector output type '" << outputPixelType << "'. " << std::endl << "Known types are " << list << "." << std::endl; return false; } - + return true; } private: - - template + + template static void UpdateWithOutputType(ImageConvertGenericFilter& filter) { // Read @@ -152,7 +154,7 @@ namespace clitk { filter.SetNextOutput(cast_filter->GetOutput()); } }; - + template class UpdateWithSelectiveOutputType { @@ -160,7 +162,7 @@ namespace clitk { static bool Run(ImageConvertGenericFilter& filter, std::string outputPixelType) { /* - // RP: future conversions? + // RP: future conversions? if (IsSameType(outputPixelType)) UpdateWithOutputVectorType(); else if (IsSameType(outputPixelType)) @@ -171,7 +173,7 @@ namespace clitk { UpdateWithOutputVectorType(); else if (IsSameType(outputPixelType)) UpdateWithOutputVectorType(); - else + else */ if (IsSameType(outputPixelType)) UpdateWithOutputVectorType(filter); @@ -180,17 +182,17 @@ namespace clitk { else { std::string list = CreateListOfTypes(); - std::cerr << "Error, I don't know the vector output type '" << outputPixelType + std::cerr << "Error, I don't know the vector output type '" << outputPixelType << "'. " << std::endl << "Known types are " << list << "." << std::endl; return false; } - + return true; } - + private: - - template + + template static void UpdateWithOutputVectorType(ImageConvertGenericFilter& filter) { // Read @@ -201,7 +203,7 @@ namespace clitk { // Warning filter.CheckTypes(filter.GetInputPixelTypeName(), filter.GetOutputPixelTypeName()); - + // Cast typedef itk::Image, InputImageType::ImageDimension> OutputImageType; typedef itk::VectorCastImageFilter FilterType; @@ -220,4 +222,3 @@ namespace clitk { } // end namespace #endif /* end #define CLITKIMAGECONVERTGENERICFILTER_H */ - -- 2.45.1