From: delmon Date: Thu, 10 Mar 2011 16:16:15 +0000 (+0000) Subject: Romulo: X-Git-Tag: v1.2.0~183 X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=4af47ddf6c7819cd561e97b454521c29c21ddab8;p=clitk.git Romulo: - Added functionality to transform points based on the BSpline coefficients instead of the vector field - Added new command-line option --coeff (mutual exclusive wrt --vf) --- diff --git a/registration/clitkCalculateTRE.ggo b/registration/clitkCalculateTRE.ggo index e6b42f6..7acbe02 100755 --- a/registration/clitkCalculateTRE.ggo +++ b/registration/clitkCalculateTRE.ggo @@ -11,7 +11,8 @@ section "Input" option "ref" - "List of points in reference" string yes option "input" i "Lists of points in targets" string multiple yes -option "vf" - "Input deformation fields" string multiple yes +option "vf" - "Input deformation fields" string multiple no +option "coeff" - "Input coefficient images" string multiple no option "skip" - "Skip a phase of a 4D DVF" int no section "Interpolation" diff --git a/registration/clitkCalculateTREGenericFilter.cxx b/registration/clitkCalculateTREGenericFilter.cxx index 1da773b..413823d 100755 --- a/registration/clitkCalculateTREGenericFilter.cxx +++ b/registration/clitkCalculateTREGenericFilter.cxx @@ -41,6 +41,9 @@ namespace clitk { m_Verbose=false; m_InputFileName=""; + m_NumberOfFields=0; + m_NumberOfLists=0; + m_NumberOfPoints=0; } @@ -50,39 +53,64 @@ namespace clitk void CalculateTREGenericFilter::Update() { // Read the Dimension and PixelType + if (m_ArgsInfo.vf_given && m_ArgsInfo.coeff_given) + { + std::cout << "Error, You have to supply either vector fields or coefficient images. Supplying both is not allowed. See clitkCalculateTRE --help for details."< 4) + { + std::cout<<"Error, Only for 2, 3 or 4 Dimensions!!!"<(); - else if(Dimension==3) ReadVectorFields<3,3>(); - else if (Dimension==4)ReadVectorFields<4,3>(); - else + if (m_ArgsInfo.vf_given) { - std::cout<<"Error, Only for 2, 3 or 4 Dimensions!!!"<(); + else + if(Dimension==3) ReadVectorFields<3,3>(); + else if (Dimension==4)ReadVectorFields<4,3>(); } + else + { + if(Dimension==2) ReadCoefficientImages<2,2>(); + else + if(Dimension==3) ReadCoefficientImages<3,3>(); + else if (Dimension==4)ReadCoefficientImages<4,3>(); + } } - - //----------------------------- // Process DVF //----------------------------- template< > void - CalculateTREGenericFilter::ProcessVectorFields<4,3>(std::vector, 4>::Pointer > dvfs, char** filenames ) + CalculateTREGenericFilter::ProcessVectorFields<4,3>(std::vector, 4>::Pointer > dvfs, char** filenames ) { // Typedefs - typedef itk::Vector PixelType; + typedef itk::Vector PixelType; typedef itk::Image InputImageType; typedef itk::Image OutputImageType; // IO InputImageType::Pointer input=dvfs[0]; - std::vector, 3>::Pointer > new_dvfs; + std::vector, 3>::Pointer > new_dvfs; // Split vector field typedef itk::ExtractImageFilter FilterType; @@ -124,11 +152,69 @@ namespace clitk } // Update - this->UpdateWithDim<3>(new_dvfs, new_filenames); + this->UpdateDVFWithDim<3>(new_dvfs, new_filenames); } + //----------------------------- + // Process Coefficient images + //----------------------------- + template< > + void + CalculateTREGenericFilter::ProcessCoefficientImages<4,3>(std::vector, 4>::Pointer > coeffs, char** filenames ) + { + // Typedefs + typedef itk::Vector PixelType; + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + // IO + InputImageType::Pointer input=coeffs[0]; + std::vector, 3>::Pointer > new_coeffs; + + // Split vector field + typedef itk::ExtractImageFilter FilterType; + unsigned int splitDimension=3; + + // Make new file names + std::vector new_filenames; + std::string base = filenames[0]; + + // Set the extract region + InputImageType::SizeType size=input->GetLargestPossibleRegion().GetSize(); + size[splitDimension]=0; + InputImageType::RegionType extracted_region; + extracted_region.SetSize(size); + InputImageType::IndexType index=input->GetLargestPossibleRegion().GetIndex(); + + + // Loop + for (unsigned int i=0;iGetLargestPossibleRegion().GetSize()[splitDimension];i++) + { + + // Skip? + if (m_ArgsInfo.skip_given && i==(unsigned int) m_ArgsInfo.skip_arg) continue; + + // extract dvf + FilterType::Pointer filter= FilterType::New(); + filter->SetInput(input); + index[splitDimension]=i; + extracted_region.SetIndex(index); + filter->SetExtractionRegion(extracted_region); + filter->Update(); + new_coeffs.push_back(filter->GetOutput()); + + // make name + std::ostringstream number_dvf; + number_dvf << i; + std::string number = number_dvf.str(); + new_filenames.push_back(base+"_"+number); + } + + // Update + this->UpdateCoeffsWithDim<3>(new_coeffs, new_filenames); + + } diff --git a/registration/clitkCalculateTREGenericFilter.h b/registration/clitkCalculateTREGenericFilter.h index d9caea1..e504817 100755 --- a/registration/clitkCalculateTREGenericFilter.h +++ b/registration/clitkCalculateTREGenericFilter.h @@ -67,9 +67,11 @@ namespace clitk itkTypeMacro( CalculateTREGenericFilter, LightObject ); - //---------------------------------------- + //----------------------------- // Typedefs - //---------------------------------------- + //----------------------------- + typedef double ValueType; + typedef std::vector MeasureListType; //---------------------------------------- @@ -79,7 +81,6 @@ namespace clitk { m_ArgsInfo=a; m_Verbose=m_ArgsInfo.verbose_flag; - m_InputFileName=m_ArgsInfo.vf_arg[0]; } @@ -101,9 +102,12 @@ namespace clitk // Templated members //---------------------------------------- template void ReadVectorFields(void); - template void ProcessVectorFields(std::vector< typename itk::Image, Dimension>::Pointer > dvfs, char** filenames); - template void UpdateWithDim( std::vector, Dimension>::Pointer > dvfs, std::vector filenames); - + template void ProcessVectorFields(std::vector< typename itk::Image, Dimension>::Pointer > dvfs, char** filenames); + template void UpdateDVFWithDim( std::vector, Dimension>::Pointer > dvfs, std::vector filenames); + template void ReadCoefficientImages(void); + template void ProcessCoefficientImages(std::vector< typename itk::Image, Dimension>::Pointer > dvfs, char** filenames); + template void UpdateCoeffsWithDim( std::vector, Dimension>::Pointer > dvfs, std::vector filenames); + template void BuildPointLists(std::vector& filenames); //---------------------------------------- // Data members @@ -111,11 +115,14 @@ namespace clitk args_info_clitkCalculateTRE m_ArgsInfo; bool m_Verbose; std::string m_InputFileName; + unsigned int m_NumberOfFields; + unsigned int m_NumberOfLists; + unsigned int m_NumberOfPoints; }; -} // end namespace clitk +} // end namespace clitk #ifndef ITK_MANUAL_INSTANTIATION #include "clitkCalculateTREGenericFilter.txx" diff --git a/registration/clitkCalculateTREGenericFilter.txx b/registration/clitkCalculateTREGenericFilter.txx index 1198ac8..f75a3f2 100755 --- a/registration/clitkCalculateTREGenericFilter.txx +++ b/registration/clitkCalculateTREGenericFilter.txx @@ -18,6 +18,10 @@ #ifndef clitkCalculateTREGenericFilter_txx #define clitkCalculateTREGenericFilter_txx + +#include "clitkBSplineDeformableTransform.h" + + /* ================================================= * @file clitkCalculateTREGenericFilter.txx * @author @@ -28,6 +32,495 @@ ===================================================*/ +//===================================================================================== +// Macros +// Rômulo Pinho - 25/02/2011 +// The macros below avoid the duplication of code after introducing the function +// UpdateCoeffsWithDim(). Although the code generated by these functions will be +// duplicated anyway (since they're template functions) the macros make their sources +// more intelligible. +// Ideally, these macros should be made member functions, with the typedefs inside the +// the filter class, but that would change the class' interface, since it would need +// to become a template class (with parameter Dimension). To avoid breaking legacy code, +// I opted for the macros, although I don't quite like them (especially long ones like +// these). In any case, it's advisable to think of a better solution, even if it breaks +// the class' interface. +//===================================================================================== + +//----------------------------- +// Typedefs +//----------------------------- +#define TypedefsMacro \ +\ + typedef itk::Point PointType; \ + typedef clitk::List PointListType; \ + typedef clitk::Lists PointListsType; \ +\ + typedef itk::Vector VectorType; \ + typedef clitk::List VectorListType; \ + typedef clitk::Lists VectorListsType; \ +\ + typedef itk::Vector DeformationVectorType; \ + typedef itk::Image DeformationFieldType; + +//------------------------------------------------------------------- +// Build the point lists necessary for the computation of distances. +//------------------------------------------------------------------- +#define BuildPointListsMacro(filenames) \ +\ + m_NumberOfFields=filenames.size(); \ + m_NumberOfLists=m_ArgsInfo.input_given; \ + if ( (m_NumberOfLists!=m_NumberOfFields) && (m_NumberOfLists!=1) ) \ + { \ + std::cerr<<"Error: Number of lists (="< StatisticsFilterType; \ + typename StatisticsFilterType::Pointer statisticsFilter=StatisticsFilterType::New(); \ +\ + /* // Statistics (magnitude) */ \ + MeasureListType oMeanList, oStdList, oMaxList; \ + ValueType oMean, oStd, oMax; \ + statisticsFilter->GetStatistics(originalDistanceLists, oMean, oStd, oMax, oMeanList, oStdList, oMaxList); \ +\ + /* // Statistics (per component) */\ + VectorListType oMeanXYZList, oStdXYZList,oMaxXYZList; \ + VectorType oMeanXYZ, oStdXYZ, oMaxXYZ; \ + statisticsFilter->GetStatistics(originalDistanceLists, oMeanXYZ, oStdXYZ, oMaxXYZ, oMeanXYZList, oStdXYZList, oMaxXYZList); \ +\ +\ + /* //----------------------------- */\ + /* // Output */\ + /* //----------------------------- */\ + std::vector labels; \ + labels.push_back("MeanX\tSDX"); \ + labels.push_back("MeanY\tSDY"); \ + labels.push_back("MeanZ\tSDZ"); \ + labels.push_back("MeanT\tSDT"); \ + labels.push_back("MaxX"); \ + labels.push_back("MaxY"); \ + labels.push_back("MaxZ"); \ + labels.push_back("MaxT"); \ +\ +\ + /* // Output to screen */\ + if(m_Verbose) \ + { \ +\ + /* // Numbers of DVF */\ + std::cout<<"# Number\tDVF"<GetStatistics(displacementLists, dmean, dstd, dmax, dmeanList, dstdList, dmaxList); \ +\ + /* // Statistics (per component) */\ + VectorListType dmeanXYZList, dstdXYZList,dmaxXYZList; \ + VectorType dmeanXYZ, dstdXYZ, dmaxXYZ; \ + statisticsFilter->GetStatistics(displacementLists, dmeanXYZ, dstdXYZ, dmaxXYZ,dmeanXYZList, dstdXYZList, dmaxXYZList); \ +\ +\ + /* //----------------------------- */\ + /* // Statistics TRE */\ + /* //----------------------------- */\ +\ + /* // Statistics (magnitude) */\ + MeasureListType meanList, stdList, maxList; \ + ValueType mean, std, max; \ + statisticsFilter->GetStatistics(treLists, mean, std, max, meanList, stdList, maxList); \ +\ + /* // Statistics (per component) */\ + VectorListType meanXYZList, stdXYZList,maxXYZList; \ + VectorType meanXYZ, stdXYZ, maxXYZ; \ + statisticsFilter->GetStatistics(treLists, meanXYZ, stdXYZ, maxXYZ, meanXYZList, stdXYZList, maxXYZList); \ +\ +\ + /* // Output to screen */\ + if(m_Verbose) \ + { \ +\ + std::cout< filenames; \ + for (unsigned int i=0;i > originalDistanceListsMag=originalDistanceLists.Norm(); \ + std::vector filenames; \ + for (unsigned int i=0;i filenames; \ + for (unsigned int i=0;i > displacementListsMag=displacementLists.Norm(); \ + std::vector filenames; \ + for (unsigned int i=0;i filenames; \ + for (unsigned int i=0;i filenames; \ + for (unsigned int i=0;i > treMagLists=treLists.Norm(); \ +\ + std::vector filenames; \ + for (unsigned int i=0;i VectorType; + // if using dvfs + typedef itk::Vector VectorType; typedef itk::Image DeformationFieldType; - typedef itk::ImageFileReader InputReaderType; + typedef itk::ImageFileReader DvfReaderType; std::vector dvfs; + for (unsigned int i=0; i< m_ArgsInfo.vf_given; i++) { - typename InputReaderType::Pointer reader = InputReaderType::New(); - reader->SetFileName( m_ArgsInfo.vf_arg[i]); - if (m_Verbose) std::cout<<"Reading vector field "<< i <<"..."<Update(); - dvfs.push_back( reader->GetOutput() ); + typename DvfReaderType::Pointer reader = DvfReaderType::New(); + reader->SetFileName( m_ArgsInfo.vf_arg[i]); + if (m_Verbose) std::cout<<"Reading vector field "<< i <<"..."<Update(); + dvfs.push_back( reader->GetOutput() ); } - + ProcessVectorFields(dvfs, m_ArgsInfo.vf_arg); + } //----------------------------- @@ -61,279 +556,84 @@ namespace clitk //----------------------------- template void - CalculateTREGenericFilter::ProcessVectorFields(std::vector, Dimension>::Pointer > dvfs, char** filenames ) + CalculateTREGenericFilter::ProcessVectorFields(std::vector, Dimension>::Pointer > dvfs, char** filenames ) { - std::vector new_filenames; for (unsigned int i=0;i(dvfs, new_filenames); + UpdateDVFWithDim(dvfs, new_filenames); } - //------------------------------------------------------------------- - // Update with the number of dimensions - //------------------------------------------------------------------- - template + //----------------------------- + // Read Coefficient Images + //----------------------------- + template void - CalculateTREGenericFilter::UpdateWithDim(std::vector, Dimension>::Pointer > dvfs, std::vector filenames) + CalculateTREGenericFilter::ReadCoefficientImages(void) { - if (m_Verbose) std::cout << "Image was detected to be "< MeasureListType; - - typedef itk::Point PointType; - typedef clitk::List PointListType; - typedef clitk::Lists PointListsType; - - typedef itk::Vector VectorType; - typedef clitk::List VectorListType; - typedef clitk::Lists VectorListsType; + // if using coefficient images + typedef itk::Vector VectorType; + typedef itk::Image CoefficientImageType; - typedef itk::Vector DeformationVectorType; - typedef itk::Image DeformationFieldType; + typedef itk::ImageFileReader CoeffReaderType; + std::vector coeffs; - //----------------------------- - // Number of inputs - //----------------------------- - unsigned int numberOfFields=filenames.size(); - unsigned int numberOfLists=m_ArgsInfo.input_given; - if ( (numberOfLists!=numberOfFields) && (numberOfLists!=1) ) - { - std::cerr<<"Error: Number of lists (="<SetFileName( m_ArgsInfo.coeff_arg[i]); + if (m_Verbose) std::cout<<"Reading coefficient image "<< i <<"..."<Update(); + coeffs.push_back( reader->GetOutput() ); } + + ProcessCoefficientImages(coeffs, m_ArgsInfo.coeff_arg); + } - - //----------------------------- - // Input point lists - //----------------------------- - PointListsType pointLists; - unsigned int numberOfPoints=0; - for (unsigned int i=0; i + void + CalculateTREGenericFilter::ProcessCoefficientImages(std::vector, Dimension>::Pointer > coeffs, char** filenames ) + { + std::vector new_filenames; + for (unsigned int i=0;i(coeffs, new_filenames); + } + - // Verify the number of points - if (i==0) numberOfPoints=pointLists[i].size(); - else - { - if (numberOfPoints!=pointLists[i].size()) - { - std::cerr<<"Size of first list ("< + void + CalculateTREGenericFilter::UpdateDVFWithDim(std::vector, Dimension>::Pointer > dvfs, std::vector filenames) + { + if (m_Verbose) std::cout << "Image was detected to be "< GenericVectorInterpolatorType; + typedef clitk::GenericVectorInterpolator GenericVectorInterpolatorType; typename GenericVectorInterpolatorType::Pointer genericInterpolator=GenericVectorInterpolatorType::New(); genericInterpolator->SetArgsInfo(m_ArgsInfo); - typedef itk::VectorInterpolateImageFunction InterpolatorType; + typedef itk::VectorInterpolateImageFunction InterpolatorType; typename InterpolatorType::Pointer interpolator=genericInterpolator->GetInterpolatorPointer(); - //===================================================================================== - // Original distance between points - //===================================================================================== - VectorListsType originalDistanceLists(numberOfFields); - - //----------------------------- - // Calculate original distances - //----------------------------- - PointType referencePoint; - VectorType distance; - for (unsigned int phaseIndex=0; phaseIndex StatisticsFilterType; - typename StatisticsFilterType::Pointer statisticsFilter=StatisticsFilterType::New(); - - // Statistics (magnitude) - MeasureListType oMeanList, oStdList, oMaxList; - ValueType oMean, oStd, oMax; - statisticsFilter->GetStatistics(originalDistanceLists, oMean, oStd, oMax, oMeanList, oStdList, oMaxList); - - // Statistics (per component) - VectorListType oMeanXYZList, oStdXYZList,oMaxXYZList; - VectorType oMeanXYZ, oStdXYZ, oMaxXYZ; - statisticsFilter->GetStatistics(originalDistanceLists, oMeanXYZ, oStdXYZ, oMaxXYZ, oMeanXYZList, oStdXYZList, oMaxXYZList); - - - //----------------------------- - // Output - //----------------------------- - std::vector labels; - labels.push_back("MeanX\tSDX"); - labels.push_back("MeanY\tSDY"); - labels.push_back("MeanZ\tSDZ"); - labels.push_back("MeanT\tSDT"); - labels.push_back("MaxX"); - labels.push_back("MaxY"); - labels.push_back("MaxZ"); - labels.push_back("MaxT"); - - - // Output to screen - if(m_Verbose) - { - - // Numbers of DVF - std::cout<<"# Number\tDVF"<SetInputImage( dvfs[phaseIndex]); - for (unsigned int pointIndex=0; pointIndexSetInputImage( dvfs[phaseIndex] ); + for (unsigned int pointIndex=0; pointIndex + void + CalculateTREGenericFilter::UpdateCoeffsWithDim(std::vector, Dimension>::Pointer > coeffs, std::vector filenames) + { + // call macros + TypedefsMacro; + BuildPointListsMacro(filenames); + OriginalDistancesMacro; + + //===================================================================================== + // Distance between points after warp + //===================================================================================== + //----------------------------- - // Statistics displacements + // Transform to get the transformed points from the coeff images //----------------------------- + typedef clitk::BSplineDeformableTransform TransformType; + typename TransformType::Pointer transform = TransformType::New(); + + PointListsType warpedPointLists(m_NumberOfFields); + VectorListsType treLists(m_NumberOfFields), displacementLists(m_NumberOfFields); - // Statistics (magnitude) - MeasureListType dmeanList, dstdList, dmaxList; - ValueType dmean, dstd, dmax; - statisticsFilter->GetStatistics(displacementLists, dmean, dstd, dmax, dmeanList, dstdList, dmaxList); - - // Statistics (per component) - VectorListType dmeanXYZList, dstdXYZList,dmaxXYZList; - VectorType dmeanXYZ, dstdXYZ, dmaxXYZ; - statisticsFilter->GetStatistics(displacementLists, dmeanXYZ, dstdXYZ, dmaxXYZ,dmeanXYZList, dstdXYZList, dmaxXYZList); - - //----------------------------- - // Statistics TRE + // Calculate residual distances //----------------------------- - - // Statistics (magnitude) - MeasureListType meanList, stdList, maxList; - ValueType mean, std, max; - statisticsFilter->GetStatistics(treLists, mean, std, max, meanList, stdList, maxList); - - // Statistics (per component) - VectorListType meanXYZList, stdXYZList,maxXYZList; - VectorType meanXYZ, stdXYZ, maxXYZ; - statisticsFilter->GetStatistics(treLists, meanXYZ, stdXYZ, maxXYZ, meanXYZList, stdXYZList, maxXYZList); - - - // Output to screen - if(m_Verbose) - { - - std::cout< filenames; - for (unsigned int i=0;i > originalDistanceListsMag=originalDistanceLists.Norm(); - std::vector filenames; - for (unsigned int i=0;i filenames; - for (unsigned int i=0;i > displacementListsMag=displacementLists.Norm(); - std::vector filenames; - for (unsigned int i=0;i filenames; - for (unsigned int i=0;i filenames; - for (unsigned int i=0;iSetCoefficientImage(coeffs[phaseIndex]); + + // transform the input points + for (unsigned int pointIndex=0; pointIndexTransformPoint(referencePoint); + + // Warp + displacement=warpedPoint-referencePoint; + displacementLists[phaseIndex].push_back(displacement); + warpedPointLists[phaseIndex].push_back(warpedPoint); + tre=pointLists[phaseIndex][pointIndex]-warpedPoint; + treLists[phaseIndex].push_back(tre); + } } - // Output tre mag - if( m_ArgsInfo.treMag_given) - { - clitk::Lists > treMagLists=treLists.Norm(); - - std::vector filenames; - for (unsigned int i=0;i