diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/MultishellProcessing/itkRadialMultishellToSingleshellImageFilter.cpp b/Modules/DiffusionCore/Algorithms/Reconstruction/MultishellProcessing/itkRadialMultishellToSingleshellImageFilter.cpp index f86dd43..7ff571d 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/MultishellProcessing/itkRadialMultishellToSingleshellImageFilter.cpp +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/MultishellProcessing/itkRadialMultishellToSingleshellImageFilter.cpp @@ -1,237 +1,237 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*========================================================================= Program: Tensor ToolKit - TTK Module: $URL: svn://scm.gforge.inria.fr/svn/ttk/trunk/Algorithms/itkElectrostaticRepulsionDiffusionGradientReductionFilter.txx $ Language: C++ Date: $Date: 2010-06-07 13:39:13 +0200 (Mo, 07 Jun 2010) $ Version: $Revision: 68 $ Copyright (c) INRIA 2010. All rights reserved. See LICENSE.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _itk_RadialMultishellToSingleshellImageFilter_cpp_ #define _itk_RadialMultishellToSingleshellImageFilter_cpp_ #endif #define _USE_MATH_DEFINES #include "itkRadialMultishellToSingleshellImageFilter.h" #include "mitkDiffusionFunctionCollection.h" namespace itk { template RadialMultishellToSingleshellImageFilter ::RadialMultishellToSingleshellImageFilter() { this->SetNumberOfRequiredInputs( 1 ); - this->DynamicMultiThreadingOff(); + } template void RadialMultishellToSingleshellImageFilter ::BeforeThreadedGenerateData() { // test whether BvalueMap contains all necessary information if(m_BValueMap.size() == 0) { itkWarningMacro(<< "No BValueMap given: create one using GradientDirectionContainer"); GradientDirectionContainerType::ConstIterator gdcit; for( gdcit = m_OriginalGradientDirections->Begin(); gdcit != m_OriginalGradientDirections->End(); ++gdcit) { double bValueKey = int(((m_OriginalBValue * gdcit.Value().two_norm() * gdcit.Value().two_norm())+7.5)/10)*10; m_BValueMap[bValueKey].push_back(gdcit.Index()); } } //# BValueMap contains no bZero --> itkException if(m_BValueMap.find(0.0) == m_BValueMap.end()) { MITK_INFO << "No ReferenceSignal (BZeroImages) found!"; itkExceptionMacro(<< "No ReferenceSignal (BZeroImages) found!"); } // [allDirectionsContainer] Gradient DirectionContainer containing all unique directions m_TargetDirectionsIndicies = mitk::gradients::GetAllUniqueDirections(m_BValueMap, m_OriginalGradientDirections); // [sizeAllDirections] size of GradientContainer cointaining all unique directions m_NumberTargetDirections = m_TargetDirectionsIndicies.size(); m_TargetGradientDirections = mitk::gradients::CreateNormalizedUniqueGradientDirectionContainer(m_BValueMap,m_OriginalGradientDirections); m_ShellInterpolationMatrixVector.reserve(m_BValueMap.size()-1); // for each shell BValueMap::const_iterator it = m_BValueMap.begin(); it++; //skip bZeroIndices unsigned int shellIndex = 0; for(;it != m_BValueMap.end();++it) { //- calculate maxShOrder const IndicesVector currentShell = it->second; unsigned int SHMaxOrder = 12; while( ((SHMaxOrder+1)*(SHMaxOrder+2)/2) > currentShell.size() && ((SHMaxOrder+1)*(SHMaxOrder+2)/2) >= 4 ) SHMaxOrder -= 2 ; //- get TragetSHBasis using allDirectionsContainer vnl_matrix sphericalCoordinates; sphericalCoordinates = mitk::gradients::ComputeSphericalFromCartesian(m_TargetDirectionsIndicies, m_OriginalGradientDirections); vnl_matrix TargetSHBasis = mitk::gradients::ComputeSphericalHarmonicsBasis(sphericalCoordinates, SHMaxOrder); //- get ShellSHBasis using currentShellDirections sphericalCoordinates = mitk::gradients::ComputeSphericalFromCartesian(currentShell, m_OriginalGradientDirections); vnl_matrix ShellSHBasis = mitk::gradients::ComputeSphericalHarmonicsBasis(sphericalCoordinates, SHMaxOrder); //- calculate interpolationSHBasis [TargetSHBasis * ShellSHBasis^-1] vnl_matrix_inverse invShellSHBasis(ShellSHBasis); vnl_matrix shellInterpolationMatrix = TargetSHBasis * invShellSHBasis.pinverse(); //- save interpolationSHBasis m_ShellInterpolationMatrixVector.push_back(shellInterpolationMatrix); ++shellIndex; } // initialize output image typename OutputImageType::Pointer outImage = static_cast(ProcessObject::GetOutput(0)); outImage->SetSpacing( this->GetInput()->GetSpacing() ); outImage->SetOrigin( this->GetInput()->GetOrigin() ); outImage->SetDirection( this->GetInput()->GetDirection() ); // Set the image direction using bZeroDirection+AllDirectionsContainer outImage->SetLargestPossibleRegion( this->GetInput()->GetLargestPossibleRegion()); outImage->SetBufferedRegion( this->GetInput()->GetLargestPossibleRegion() ); outImage->SetRequestedRegion( this->GetInput()->GetLargestPossibleRegion() ); outImage->SetVectorLength( 1+m_NumberTargetDirections ); // size of 1(bzeroValue) + AllDirectionsContainer outImage->Allocate(); m_ErrorImage = ErrorImageType::New(); m_ErrorImage->SetSpacing( this->GetInput()->GetSpacing() ); m_ErrorImage->SetOrigin( this->GetInput()->GetOrigin() ); m_ErrorImage->SetDirection( this->GetInput()->GetDirection() ); // Set the image direction using bZeroDirection+AllDirectionsContainer m_ErrorImage->SetLargestPossibleRegion( this->GetInput()->GetLargestPossibleRegion()); m_ErrorImage->SetBufferedRegion( this->GetInput()->GetLargestPossibleRegion() ); m_ErrorImage->SetRequestedRegion( this->GetInput()->GetLargestPossibleRegion() ); m_ErrorImage->Allocate(); MITK_INFO << "Input:" << std::endl << std::endl << " GradientDirections: " << m_OriginalGradientDirections->Size() << std::endl << " Shells: " << (m_BValueMap.size() - 1) << std::endl << " ReferenceImages: " << m_BValueMap[0.0].size() << std::endl; MITK_INFO << "Output:" << std::endl << std::endl << " OutImageVectorLength: " << outImage->GetVectorLength() << std::endl << " TargetDirections: " << m_NumberTargetDirections << std::endl << std::endl; } template void RadialMultishellToSingleshellImageFilter -::ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType /*threadId*/) +::DynamicThreadedGenerateData(const OutputImageRegionType &outputRegionForThread /*threadId*/) { // Get input gradient image pointer typename InputImageType::Pointer inputImage = static_cast< InputImageType * >(ProcessObject::GetInput(0)); // ImageRegionIterator for the input image ImageRegionIterator< InputImageType > iit(inputImage, outputRegionForThread); iit.GoToBegin(); // Get output gradient image pointer typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(ProcessObject::GetOutput(0)); // ImageRegionIterator for the output image ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); // ImageRegionIterator for the output image ImageRegionIterator< ErrorImageType > eit(m_ErrorImage, outputRegionForThread); eit.GoToBegin(); // calculate target bZero-Value [b0_t] const IndicesVector IndicesS0 = m_BValueMap[0.0]; double AverageS0 = 0.0; unsigned int numberOfShells = m_BValueMap.size()-1; // create empty nxm SignalMatrix containing n->signals/directions (in case of interpolation ~ sizeAllDirections otherwise the size of any shell) for m->shells vnl_matrix SignalMatrix(m_NumberTargetDirections, numberOfShells); // create nx1 targetSignalVector vnl_vector SignalVector(m_NumberTargetDirections); OutputPixelType out; InputPixelType b; BValueMap::const_iterator shellIterator; vnl_matrix NewSignalMatrix (m_NumberTargetDirections, 2); vnl_vector InterpVector; unsigned int shellIndex = 0; // ** walking over each Voxel while(!iit.IsAtEnd()) { b = iit.Get(); AverageS0=0.0; for(unsigned int i = 0 ; i < IndicesS0.size(); i++){ AverageS0 += b[IndicesS0[i]]; } AverageS0 /= (double)IndicesS0.size(); out = oit.Get(); out.SetElement(0,AverageS0); shellIterator = m_BValueMap.begin(); shellIterator++; //skip bZeroImages shellIndex = 0; // for each shell while(shellIterator != m_BValueMap.end()) { const IndicesVector & currentShell = shellIterator->second; InterpVector.set_size(currentShell.size()); // get the raw signal for currente shell (signal for eacht direction) for(unsigned int i = 0 ; i < currentShell.size(); i++) InterpVector.put(i,b[currentShell[i]]); // interpolate the signal using corresponding interpolationSHBasis SignalVector = m_ShellInterpolationMatrixVector.at(shellIndex) * InterpVector; // save interpolated signal column SignalMatrix.set_column(shellIndex, SignalVector); shellIterator++; shellIndex++; } // apply voxel wise signal manipulation functor (*m_Functor)(NewSignalMatrix, /*const &*/SignalMatrix,/*const &*/ AverageS0); SignalVector = NewSignalMatrix.get_column(0); for(unsigned int i = 1 ; i < out.Size(); i ++) out.SetElement(i,SignalVector.get(i-1)); eit.Set(NewSignalMatrix.get_column(1).mean()); oit.Set(out); ++eit; ++oit; ++iit; } } } // end of namespace diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/MultishellProcessing/itkRadialMultishellToSingleshellImageFilter.h b/Modules/DiffusionCore/Algorithms/Reconstruction/MultishellProcessing/itkRadialMultishellToSingleshellImageFilter.h index 8d78833..25e5667 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/MultishellProcessing/itkRadialMultishellToSingleshellImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/MultishellProcessing/itkRadialMultishellToSingleshellImageFilter.h @@ -1,111 +1,111 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _itk_RadialMultishellToSingleshellImageFilterr_h_ #define _itk_RadialMultishellToSingleshellImageFilterr_h_ #include #include #include "itkDWIVoxelFunctor.h" namespace itk { template class RadialMultishellToSingleshellImageFilter : public ImageToImageFilter, itk::VectorImage > { public: typedef RadialMultishellToSingleshellImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< itk::VectorImage, itk::VectorImage > Superclass; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(RadialMultishellToSingleshellImageFilter, ImageToImageFilter) typedef TInputScalarType InputScalarType; typedef itk::VectorImage InputImageType; typedef typename InputImageType::PixelType InputPixelType; typedef TOutputScalarType OutputScalarType; typedef itk::VectorImage OutputImageType; typedef typename OutputImageType::PixelType OutputPixelType; typedef OutputScalarType BaselineScalarType; typedef BaselineScalarType BaselinePixelType; typedef typename itk::Image BaselineImageType; typedef float ErrorScalarType; typedef ErrorScalarType ErrorPixelType; typedef typename itk::Image ErrorImageType; typedef vnl_vector_fixed< double, 3 > GradientDirectionType; typedef itk::VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; typedef std::vector IndicesVector; typedef std::map BValueMap; void SetOriginalGradientDirections(GradientDirectionContainerType::ConstPointer ptr){m_OriginalGradientDirections = ptr;} void SetOriginalBValue(const double & val){m_OriginalBValue = val;} void SetOriginalBValueMap(const BValueMap & inp){m_BValueMap = inp;} void SetFunctor(DWIVoxelFunctor * functor){m_Functor = functor;} GradientDirectionContainerType::Pointer GetTargetGradientDirections(){return m_TargetGradientDirections;} ErrorImageType::Pointer GetErrorImage(){return m_ErrorImage;} protected: RadialMultishellToSingleshellImageFilter(); ~RadialMultishellToSingleshellImageFilter() {} void BeforeThreadedGenerateData(); - void ThreadedGenerateData( const OutputImageRegionType &, ThreadIdType); + void DynamicThreadedGenerateData( const OutputImageRegionType &); GradientDirectionContainerType::Pointer m_TargetGradientDirections; ///< container for the subsampled output gradient directions GradientDirectionContainerType::ConstPointer m_OriginalGradientDirections; ///< input gradient directions BValueMap m_BValueMap; double m_OriginalBValue; std::vector > m_ShellInterpolationMatrixVector; IndicesVector m_TargetDirectionsIndicies; unsigned int m_NumberTargetDirections; DWIVoxelFunctor * m_Functor; ErrorImageType::Pointer m_ErrorImage; }; } // end of namespace #ifndef ITK_MANUAL_INSTANTIATION #include "itkRadialMultishellToSingleshellImageFilter.cpp" #endif #endif diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkAnalyticalDiffusionQballReconstructionImageFilter.cpp b/Modules/DiffusionCore/Algorithms/Reconstruction/itkAnalyticalDiffusionQballReconstructionImageFilter.cpp index d7f4705..4753bb9 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkAnalyticalDiffusionQballReconstructionImageFilter.cpp +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkAnalyticalDiffusionQballReconstructionImageFilter.cpp @@ -1,656 +1,656 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkAnalyticalDiffusionQballReconstructionImageFilter_cpp #define __itkAnalyticalDiffusionQballReconstructionImageFilter_cpp #include #include #include #include #include #include #include #include #include #include #include "itkPointShell.h" namespace itk { template< class T, class TG, class TO, int ShOrder, int NrOdfDirections> AnalyticalDiffusionQballReconstructionImageFilter::AnalyticalDiffusionQballReconstructionImageFilter() : m_GradientDirectionContainer(nullptr), m_NumberOfGradientDirections(0), m_NumberOfBaselineImages(1), m_Threshold(NumericTraits< ReferencePixelType >::NonpositiveMin()), m_BValue(-1), m_Lambda(0.0), m_DirectionsDuplicated(false), m_Delta1(0.001), m_Delta2(0.001), m_UseMrtrixBasis(false) { // At least 1 inputs is necessary for a vector image. // For images added one at a time we need at least six this->SetNumberOfRequiredInputs( 1 ); - this->DynamicMultiThreadingOff(); + } template< class TReferenceImagePixelType, class TGradientImagePixelType, class TOdfPixelType, int ShOrder, int NrOdfDirections> typename itk::AnalyticalDiffusionQballReconstructionImageFilter< TReferenceImagePixelType,TGradientImagePixelType,TOdfPixelType, ShOrder,NrOdfDirections>::OdfPixelType itk::AnalyticalDiffusionQballReconstructionImageFilter::Normalize( OdfPixelType odf, typename NumericTraits::AccumulateType b0 ) { switch( m_NormalizationMethod ) { case QBAR_STANDARD: { TOdfPixelType sum = 0; for(int i=0; i0) odf /= sum; return odf; break; } case QBAR_B_ZERO_B_VALUE: { for(int i=0; i vnl_vector itk::AnalyticalDiffusionQballReconstructionImageFilter::PreNormalize( vnl_vector vec, typename NumericTraits::AccumulateType b0 ) { switch( m_NormalizationMethod ) { case QBAR_STANDARD: { int n = vec.size(); double b0f = (double)b0; for(int i=0; i=1) vec[i] = 1-m_Delta2/2; else if (vec[i]>=1-m_Delta2) vec[i] = 1-m_Delta2/2-(1-vec[i])*(1-vec[i])/(2*m_Delta2); vec[i] = log(-log(vec[i])); } return vec; break; } } return vec; } template< class T, class TG, class TO, int ShOrder, int NrOdfDirections> void AnalyticalDiffusionQballReconstructionImageFilter::BeforeThreadedGenerateData() { // If we have more than 2 inputs, then each input, except the first is a // gradient image. The number of gradient images must match the number of // gradient directions. //const unsigned int numberOfInputs = this->GetNumberOfInputs(); // There need to be at least 6 gradient directions to be able to compute the // tensor basis if( m_NumberOfGradientDirections < (ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder ) { itkExceptionMacro( << "Not enough gradient directions supplied (" << m_NumberOfGradientDirections << "). At least " << (ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder << " needed for SH-order " << ShOrder); } // Input must be an itk::VectorImage. std::string gradientImageClassName( this->ProcessObject::GetInput(0)->GetNameOfClass()); if ( strcmp(gradientImageClassName.c_str(),"VectorImage") != 0 ) { itkExceptionMacro( << "There is only one Gradient image. I expect that to be a VectorImage. " << "But its of type: " << gradientImageClassName ); } this->ComputeReconstructionMatrix(); typename GradientImagesType::Pointer img = static_cast< GradientImagesType * >( this->ProcessObject::GetInput(0) ); m_BZeroImage = BZeroImageType::New(); m_BZeroImage->SetSpacing( img->GetSpacing() ); // Set the image spacing m_BZeroImage->SetOrigin( img->GetOrigin() ); // Set the image origin m_BZeroImage->SetDirection( img->GetDirection() ); // Set the image direction m_BZeroImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion()); m_BZeroImage->SetBufferedRegion( img->GetLargestPossibleRegion() ); m_BZeroImage->Allocate(); m_ODFSumImage = BZeroImageType::New(); m_ODFSumImage->SetSpacing( img->GetSpacing() ); // Set the image spacing m_ODFSumImage->SetOrigin( img->GetOrigin() ); // Set the image origin m_ODFSumImage->SetDirection( img->GetDirection() ); // Set the image direction m_ODFSumImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion()); m_ODFSumImage->SetBufferedRegion( img->GetLargestPossibleRegion() ); m_ODFSumImage->Allocate(); m_CoefficientImage = CoefficientImageType::New(); m_CoefficientImage->SetSpacing( img->GetSpacing() ); // Set the image spacing m_CoefficientImage->SetOrigin( img->GetOrigin() ); // Set the image origin m_CoefficientImage->SetDirection( img->GetDirection() ); // Set the image direction m_CoefficientImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion()); m_CoefficientImage->SetBufferedRegion( img->GetLargestPossibleRegion() ); m_CoefficientImage->Allocate(); if(m_NormalizationMethod == QBAR_SOLID_ANGLE || m_NormalizationMethod == QBAR_NONNEG_SOLID_ANGLE) m_Lambda = 0.0; } template< class T, class TG, class TO, int ShOrder, int NrOdfDirections> void AnalyticalDiffusionQballReconstructionImageFilter -::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) +::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread ) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); ImageRegionIterator< BZeroImageType > oit2(m_BZeroImage, outputRegionForThread); oit2.GoToBegin(); ImageRegionIterator< FloatImageType > oit3(m_ODFSumImage, outputRegionForThread); oit3.GoToBegin(); ImageRegionIterator< CoefficientImageType > oit4(m_CoefficientImage, outputRegionForThread); oit4.GoToBegin(); typedef ImageRegionConstIterator< GradientImagesType > GradientIteratorType; typedef typename GradientImagesType::PixelType GradientVectorType; typename GradientImagesType::Pointer gradientImagePointer = nullptr; // Would have liked a dynamic_cast here, but seems SGI doesn't like it // The enum will ensure that an inappropriate cast is not done gradientImagePointer = static_cast< GradientImagesType * >( this->ProcessObject::GetInput(0) ); GradientIteratorType git(gradientImagePointer, outputRegionForThread ); git.GoToBegin(); // Compute the indicies of the baseline images and gradient images std::vector baselineind; // contains the indicies of // the baseline images std::vector gradientind; // contains the indicies of // the gradient images for(GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin(); gdcit != this->m_GradientDirectionContainer->End(); ++gdcit) { float bval = gdcit.Value().two_norm(); bval = bval*bval*m_BValue; if(bval < 100) baselineind.push_back(gdcit.Index()); else gradientind.push_back(gdcit.Index()); } if( m_DirectionsDuplicated ) { int gradIndSize = gradientind.size(); for(int i=0; i::AccumulateType b0 = NumericTraits::Zero; // Average the baseline image pixels for(unsigned int i = 0; i < baselineind.size(); ++i) { b0 += b[baselineind[i]]; } b0 /= this->m_NumberOfBaselineImages; OdfPixelType odf(0.0); typename CoefficientImageType::PixelType coeffPixel(0.0); vnl_vector B(m_NumberOfGradientDirections); if( (b0 != 0) && (b0 >= m_Threshold) ) { for( unsigned int i = 0; i< m_NumberOfGradientDirections; i++ ) { B[i] = static_cast(b[gradientind[i]]); } B = PreNormalize(B, b0); if(m_NormalizationMethod == QBAR_SOLID_ANGLE) { vnl_vector coeffs(m_NumberCoefficients); coeffs = ( m_CoeffReconstructionMatrix * B ); coeffs[0] += 1.0/(2.0*sqrt(itk::Math::pi)); odf = ( m_SphericalHarmonicBasisMatrix * coeffs ).data_block(); coeffPixel = coeffs.data_block(); } else if(m_NormalizationMethod == QBAR_NONNEG_SOLID_ANGLE) { /** this would be the place to implement a non-negative * solver for quadratic programming problem: * min .5*|| Bc-s ||^2 subject to -CLPc <= 4*pi*ones * (refer to MICCAI 2009 Goh et al. "Estimating ODFs with PDF constraints") * .5*|| Bc-s ||^2 == .5*c'B'Bc - x'B's + .5*s's */ itkExceptionMacro( << "Nonnegative Solid Angle not yet implemented"); } else { vnl_vector coeffs(m_NumberCoefficients); coeffs = ( m_CoeffReconstructionMatrix * B ); coeffs[0] += 1.0/(2.0*sqrt(itk::Math::pi)); coeffPixel = coeffs.data_block(); odf = ( m_ReconstructionMatrix * B ).data_block(); } odf = Normalize(odf, b0); } oit.Set( odf ); oit2.Set( b0 ); float sum = 0; for (unsigned int k=0; k void AnalyticalDiffusionQballReconstructionImageFilter ::tofile2(vnl_matrix *pA, std::string fname) { vnl_matrix A = (*pA); std::ofstream myfile; std::locale C("C"); std::locale originalLocale = myfile.getloc(); myfile.imbue(C); myfile.open (fname.c_str()); myfile << "A1=["; for(unsigned int i=0; i void AnalyticalDiffusionQballReconstructionImageFilter::ComputeReconstructionMatrix() { m_NumberCoefficients = (ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder; if( m_NumberOfGradientDirections < m_NumberCoefficients ) { itkExceptionMacro( << "Not enough gradient directions supplied (" << m_NumberOfGradientDirections << "). At least " << (ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder << " needed for SH-order " << ShOrder); } // Gradient preprocessing { // check for duplicate diffusion gradients bool warning = false; for(GradientDirectionContainerType::ConstIterator gdcit1 = this->m_GradientDirectionContainer->Begin(); gdcit1 != this->m_GradientDirectionContainer->End(); ++gdcit1) { for(GradientDirectionContainerType::ConstIterator gdcit2 = this->m_GradientDirectionContainer->Begin(); gdcit2 != this->m_GradientDirectionContainer->End(); ++gdcit2) { if(gdcit1.Value() == gdcit2.Value() && gdcit1.Index() != gdcit2.Index()) { itkWarningMacro( << "Some of the Diffusion Gradients equal each other. Corresponding image data should be averaged before calling this filter." ); warning = true; break; } } if (warning) break; } // handle acquisition schemes where only half of the spherical // shell is sampled by the gradient directions. In this case, // each gradient direction is duplicated in negative direction. vnl_vector centerMass(3); centerMass.fill(0.0); int count = 0; for(GradientDirectionContainerType::ConstIterator gdcit1 = this->m_GradientDirectionContainer->Begin(); gdcit1 != this->m_GradientDirectionContainer->End(); ++gdcit1) { float bval = gdcit1.Value().two_norm(); bval = bval*bval*m_BValue; if(bval > 100) { centerMass += gdcit1.Value(); count ++; } } centerMass /= count; if(centerMass.two_norm() > 0.1) { m_DirectionsDuplicated = true; m_NumberOfGradientDirections *= 2; } } // Create 3xM matrix Q that contains the gradient vectors in polar coordinates vnl_matrix Q(3, m_NumberOfGradientDirections); { int i = 0; for(GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin(); gdcit != this->m_GradientDirectionContainer->End(); ++gdcit) { float bval = gdcit.Value().two_norm(); bval = bval*bval*m_BValue; if(bval > 100) { double x = gdcit.Value().get(0); double y = gdcit.Value().get(1); double z = gdcit.Value().get(2); double cart[3]; mitk::sh::Cart2Sph(x,y,z,cart); Q(0,i) = cart[0]; Q(1,i) = cart[1]; Q(2,i++) = cart[2]; } } if(m_DirectionsDuplicated) { for(GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin(); gdcit != this->m_GradientDirectionContainer->End(); ++gdcit) { float bval = gdcit.Value().two_norm(); bval = bval*bval*m_BValue; if(bval > 100) { double x = gdcit.Value().get(0); double y = gdcit.Value().get(1); double z = gdcit.Value().get(2); double cart[3]; mitk::sh::Cart2Sph(x,y,z,cart); Q(0,i) = cart[0]; Q(1,i) = cart[1]; Q(2,i++) = cart[2]; } } } } // Calcualte SH basis B vnl_matrix L(m_NumberCoefficients,m_NumberCoefficients, 0); vnl_vector lj(m_NumberCoefficients); vnl_matrix B(m_NumberOfGradientDirections,m_NumberCoefficients); for(unsigned int i=0; i P(m_NumberCoefficients,m_NumberCoefficients, 0); for(unsigned int i=0; i B_transpose(B.transpose()); vnl_matrix_inverse* pseudoInverse = new vnl_matrix_inverse( B_transpose * B + L*L*m_Lambda ); m_CoeffReconstructionMatrix = pseudoInverse->pinverse() * B_transpose; switch(m_NormalizationMethod) { case QBAR_ADC_ONLY: case QBAR_RAW_SIGNAL: break; case QBAR_STANDARD: case QBAR_B_ZERO_B_VALUE: case QBAR_B_ZERO: case QBAR_NONE: { m_CoeffReconstructionMatrix = P * m_CoeffReconstructionMatrix; break; } case QBAR_SOLID_ANGLE: { m_CoeffReconstructionMatrix = (float)(1.0/(8.0*itk::Math::pi)) * P * L * m_CoeffReconstructionMatrix; break; } case QBAR_NONNEG_SOLID_ANGLE: break; } // needed to calculate the ODF values from the SH coefficients vnl_matrix_fixed* U = itk::PointShell >::DistributePointShell(); m_SphericalHarmonicBasisMatrix = mitk::sh::CalcShBasisForDirections(ShOrder, U->as_matrix()); m_ReconstructionMatrix = m_SphericalHarmonicBasisMatrix * m_CoeffReconstructionMatrix; } template< class T, class TG, class TO, int ShOrder, int NrOdfDirections> void AnalyticalDiffusionQballReconstructionImageFilter ::SetGradientImage(const GradientDirectionContainerType *gradientDirection, const GradientImagesType *gradientImage ) { // Copy Gradient Direction Container this->m_GradientDirectionContainer = GradientDirectionContainerType::New(); for(GradientDirectionContainerType::ConstIterator it = gradientDirection->Begin(); it != gradientDirection->End(); it++) { this->m_GradientDirectionContainer->push_back(it.Value()); } if (m_BValue<0) mitkThrow() << "B-value needs to be set before gradient image! " << m_BValue; unsigned int numImages = gradientDirection->Size(); this->m_NumberOfBaselineImages = 0; for(GradientDirectionContainerType::Iterator it = this->m_GradientDirectionContainer->Begin(); it != this->m_GradientDirectionContainer->End(); it++) { float bval = it.Value().two_norm(); bval = bval*bval*m_BValue; if(bval < 100) { this->m_NumberOfBaselineImages++; } else // Normalize non-zero gradient directions { it.Value() = it.Value() / it.Value().two_norm(); } } if (this->m_NumberOfBaselineImages==0) itkExceptionMacro("No baseline image detected (no b-zero image)"); this->m_NumberOfGradientDirections = numImages - this->m_NumberOfBaselineImages; // ensure that the gradient image we received has as many components as // the number of gradient directions if( gradientImage->GetVectorLength() != this->m_NumberOfBaselineImages + m_NumberOfGradientDirections ) { itkExceptionMacro( << m_NumberOfGradientDirections << " gradients + " << this->m_NumberOfBaselineImages << "baselines = " << m_NumberOfGradientDirections + this->m_NumberOfBaselineImages << " directions specified but image has " << gradientImage->GetVectorLength() << " components."); } this->ProcessObject::SetNthInput( 0, const_cast< GradientImagesType* >(gradientImage) ); } template< class T, class TG, class TO, int ShOrder, int NrOdfDirections> void AnalyticalDiffusionQballReconstructionImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { std::locale C("C"); std::locale originalLocale = os.getloc(); os.imbue(C); Superclass::PrintSelf(os,indent); os << indent << "OdfReconstructionMatrix: " << m_ReconstructionMatrix << std::endl; if ( m_GradientDirectionContainer ) os << indent << "GradientDirectionContainer: " << m_GradientDirectionContainer << std::endl; else os << indent << "GradientDirectionContainer: (Gradient directions not set)" << std::endl; os << indent << "NumberOfGradientDirections: " << m_NumberOfGradientDirections << std::endl; os << indent << "NumberOfBaselineImages: " << m_NumberOfBaselineImages << std::endl; os << indent << "Threshold for reference B0 image: " << m_Threshold << std::endl; os << indent << "BValue: " << m_BValue << std::endl; os.imbue( originalLocale ); } } #endif // __itkAnalyticalDiffusionQballReconstructionImageFilter_cpp diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkAnalyticalDiffusionQballReconstructionImageFilter.h b/Modules/DiffusionCore/Algorithms/Reconstruction/itkAnalyticalDiffusionQballReconstructionImageFilter.h index f3ed194..e9c4ee1 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkAnalyticalDiffusionQballReconstructionImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkAnalyticalDiffusionQballReconstructionImageFilter.h @@ -1,265 +1,265 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkAnalyticalDiffusionQballReconstructionImageFilter_h_ #define __itkAnalyticalDiffusionQballReconstructionImageFilter_h_ #include "itkImageToImageFilter.h" #include "vnl/vnl_vector_fixed.h" #include "vnl/vnl_matrix.h" #include "vnl/algo/vnl_svd.h" #include "itkVectorContainer.h" #include "itkVectorImage.h" namespace itk{ /** \class AnalyticalDiffusionQballReconstructionImageFilter * \brief This class takes as input one or more reference image (acquired in the * absence of diffusion sensitizing gradients) and 'n' diffusion * weighted images and their gradient directions and computes an image of * orientation distribution function coefficients in a spherical harmonic basis. * * \par Inputs and Usage * \par * When you have the 'n' gradient and one or more reference images in a single * multi-component image (VectorImage), you can specify the images as * \code * filter->SetGradientImage( directionsContainer, vectorImage ); * \endcode * Note that this method is used to specify both the reference and gradient images. * This is convenient when the DWI images are read in using the * NRRD * format. Like the Nrrd format, the reference images are those components of the * vectorImage whose gradient direction is (0,0,0). If more than one reference image * is present, they are averaged prior to the reconstruction. * * \par Outputs * The output image is an image of vectors that must be understood as ODFs: * \code * Image< Vector< TPixelType, OdfNrDirections >, 3 > * \endcode * * \par Parameters * \li Threshold - Threshold on the reference image data. The output ODF will * be a null pdf for pixels in the reference image that have a value less * than this. * \li BValue - See the documentation of SetBValue(). * \li At least 6 gradient images must be specified for the filter to be able * to run. If the input gradient directions g_i are majorly sampled on one half * of the sqhere, then each input image I_i will be duplicated and assign -g_i * in order to guarantee stability of the algorithm. * \li OdfDirections - directions of resulting orientation distribution function * \li EquatorNrSamplingPoints - number of sampling points on equator when * performing Funk Radeon Transform (FRT) * \li BasisFunctionCenters - the centers of the basis functions are used for * the sRBF (spherical radial basis functions interpolation). If not set, they * will be defaulted to equal m_EquatorNrSamplingPoints * * \par Template parameters * The class is templated over * \li the pixel type of the reference and gradient images * (expected to be scalar data types) * \li the internal representation of the ODF pixels (double, float etc). * \li the number of OdfDirections * \li the number of basis function centers for the sRBF * * \par References: * \li[1] * Tuch DS, * "Q-ball imaging", Magn Reson Med. 2004 Dec;52(6):1358-72. * */ template< class TReferenceImagePixelType, class TGradientImagePixelType, class TOdfPixelType, int ShOrder, int NrOdfDirections> class AnalyticalDiffusionQballReconstructionImageFilter : public ImageToImageFilter< Image< TReferenceImagePixelType, 3 >, Image< Vector< TOdfPixelType, NrOdfDirections >, 3 > > { public: enum Normalization { QBAR_STANDARD, QBAR_B_ZERO_B_VALUE, QBAR_B_ZERO, QBAR_NONE, QBAR_ADC_ONLY, QBAR_RAW_SIGNAL, QBAR_SOLID_ANGLE, QBAR_NONNEG_SOLID_ANGLE }; typedef AnalyticalDiffusionQballReconstructionImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< TReferenceImagePixelType, 3>, Image< Vector< TOdfPixelType, NrOdfDirections >, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(AnalyticalDiffusionQballReconstructionImageFilter, ImageToImageFilter) typedef TReferenceImagePixelType ReferencePixelType; typedef TGradientImagePixelType GradientPixelType; typedef Vector< TOdfPixelType, NrOdfDirections > OdfPixelType; typedef TOdfPixelType BZeroPixelType; /** Reference image data, This image is aquired in the absence * of a diffusion sensitizing field gradient */ typedef typename Superclass::InputImageType ReferenceImageType; typedef Image< OdfPixelType, 3 > OdfImageType; typedef OdfImageType OutputImageType; typedef Image< Vector< TOdfPixelType, (ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder >, 3 > CoefficientImageType; typedef Image< BZeroPixelType, 3 > BZeroImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; /** Typedef defining one (of the many) gradient images. */ typedef Image< GradientPixelType, 3 > GradientImageType; /** An alternative typedef defining one (of the many) gradient images. * It will be assumed that the vectorImage has the same dimension as the * Reference image and a vector length parameter of \c n (number of * gradient directions)*/ typedef VectorImage< GradientPixelType, 3 > GradientImagesType; /** Holds each magnetic field gradient used to acquire one DWImage */ typedef vnl_vector_fixed< double, 3 > GradientDirectionType; /** Container to hold gradient directions of the 'n' DW measurements */ typedef VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; /** set method to add gradient directions and its corresponding * image. The image here is a VectorImage. The user is expected to pass the * gradient directions in a container. The ith element of the container * corresponds to the gradient direction of the ith component image the * VectorImage. For the baseline image, a vector of all zeros * should be set.*/ void SetGradientImage( const GradientDirectionContainerType *, const GradientImagesType *image); /** Get reference image */ virtual ReferenceImageType * GetReferenceImage() { return ( static_cast< ReferenceImageType *>(this->ProcessObject::GetInput(0)) ); } /** Return the gradient direction. idx is 0 based */ virtual GradientDirectionType GetGradientDirection( unsigned int idx) const { if( idx >= m_NumberOfGradientDirections ) itkExceptionMacro( << "Gradient direction " << idx << "does not exist" ); return m_GradientDirectionContainer->ElementAt( idx+1 ); } static void tofile2(vnl_matrix *A, std::string fname); OdfPixelType Normalize(OdfPixelType odf, typename NumericTraits::AccumulateType b0 ); vnl_vector PreNormalize( vnl_vector vec, typename NumericTraits::AccumulateType b0 ); /** Threshold on the reference image data. The output ODF will be a null * pdf for pixels in the reference image that have a value less than this * threshold. */ itkSetMacro( Threshold, ReferencePixelType ) itkGetMacro( Threshold, ReferencePixelType ) itkSetMacro( NormalizationMethod, Normalization) itkGetMacro( NormalizationMethod, Normalization ) typedef Image FloatImageType; itkGetMacro( BZeroImage, typename BZeroImageType::Pointer) itkGetMacro( ODFSumImage, typename FloatImageType::Pointer) itkGetMacro( CoefficientImage, typename CoefficientImageType::Pointer) itkSetMacro( BValue, float) itkSetMacro( Lambda, double ) itkGetMacro( Lambda, double ) itkSetMacro( UseMrtrixBasis, bool ) #ifdef ITK_USE_CONCEPT_CHECKING /** Begin concept checking */ itkConceptMacro(ReferenceEqualityComparableCheck, (Concept::EqualityComparable)); itkConceptMacro(TensorEqualityComparableCheck, (Concept::EqualityComparable)); itkConceptMacro(GradientConvertibleToDoubleCheck, (Concept::Convertible)); itkConceptMacro(DoubleConvertibleToTensorCheck, (Concept::Convertible)); itkConceptMacro(GradientReferenceAdditiveOperatorsCheck, (Concept::AdditiveOperators)); itkConceptMacro(ReferenceOStreamWritableCheck, (Concept::OStreamWritable)); itkConceptMacro(TensorOStreamWritableCheck, (Concept::OStreamWritable)); /** End concept checking */ #endif protected: AnalyticalDiffusionQballReconstructionImageFilter(); ~AnalyticalDiffusionQballReconstructionImageFilter() override {}; void PrintSelf(std::ostream& os, Indent indent) const override; void ComputeReconstructionMatrix(); void BeforeThreadedGenerateData() override; - void ThreadedGenerateData( const - OutputImageRegionType &outputRegionForThread, ThreadIdType) override; + void DynamicThreadedGenerateData( const + OutputImageRegionType &outputRegionForThread) override; private: vnl_matrix< float > m_ReconstructionMatrix; vnl_matrix< float > m_CoeffReconstructionMatrix; vnl_matrix< float > m_SphericalHarmonicBasisMatrix; /** container to hold gradient directions */ GradientDirectionContainerType::Pointer m_GradientDirectionContainer; /** Number of gradient measurements */ unsigned int m_NumberOfGradientDirections; /** Number of baseline images */ unsigned int m_NumberOfBaselineImages; /** Threshold on the reference image data */ ReferencePixelType m_Threshold; /** LeBihan's b-value for normalizing tensors */ float m_BValue; typename BZeroImageType::Pointer m_BZeroImage; double m_Lambda; bool m_DirectionsDuplicated; Normalization m_NormalizationMethod; unsigned int m_NumberCoefficients; FloatImageType::Pointer m_ODFSumImage; typename CoefficientImageType::Pointer m_CoefficientImage; TOdfPixelType m_Delta1; TOdfPixelType m_Delta2; bool m_UseMrtrixBasis; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkAnalyticalDiffusionQballReconstructionImageFilter.cpp" #endif #endif //__itkAnalyticalDiffusionQballReconstructionImageFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkBallAndSticksImageFilter.h b/Modules/DiffusionCore/Algorithms/Reconstruction/itkBallAndSticksImageFilter.h index 3c55c30..0ea0943 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkBallAndSticksImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkBallAndSticksImageFilter.h @@ -1,104 +1,104 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkBallAndSticksImageFilter_h_ #define __itkBallAndSticksImageFilter_h_ #include "itkImageToImageFilter.h" #include "itkVectorImage.h" #include #include #include #include #include #include #include #define NUM_TENSORS 2 namespace itk{ /** \class BallAndSticksImageFilter */ template< class TInPixelType, class TOutPixelType > class BallAndSticksImageFilter : public ImageToImageFilter< VectorImage< TInPixelType, 3 >, Image< TOutPixelType, 3 > > { public: typedef BallAndSticksImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< TInPixelType, 3 >, Image< TOutPixelType, 3 > > Superclass; typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType GradientContainerType; typedef itk::Image< unsigned char, 3> ItkUcharImageType; typedef itk::Image< float, 4 > PeakImageType; typedef itk::DiffusionTensor3DReconstructionImageFilter< TInPixelType, TInPixelType, float > TensorRecFilterType; typedef mitk::TensorImage::PixelType TensorType; typedef mitk::TensorImage::ItkTensorImageType TensorImageType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(BallAndSticksImageFilter, ImageToImageFilter) typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; itkSetMacro( MaskImage, ItkUcharImageType::Pointer ) itkSetMacro( B_value, double ) itkSetMacro( GradientDirections, GradientContainerType::Pointer ) itkGetMacro( PeakImage, PeakImageType::Pointer ) itkGetMacro( OutDwi, typename InputImageType::Pointer ) protected: BallAndSticksImageFilter(); ~BallAndSticksImageFilter() {} void PrintSelf(std::ostream& os, Indent indent) const override; void BeforeThreadedGenerateData() override; - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType) override; + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread) override; double m_B_value; std::vector m_B_values; std::vector m_WeightedIndices; std::vector m_UnWeightedIndices; GradientContainerType::Pointer m_GradientDirections; ItkUcharImageType::Pointer m_MaskImage; PeakImageType::Pointer m_PeakImage; TensorImageType::Pointer m_TensorImage; typename InputImageType::Pointer m_OutDwi; vnl_vector FitSingleVoxel( const typename InputImageType::PixelType &input, const typename InputImageType::IndexType &idx); }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkBallAndSticksImageFilter.txx" #endif #endif //__itkBallAndSticksImageFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkBallAndSticksImageFilter.txx b/Modules/DiffusionCore/Algorithms/Reconstruction/itkBallAndSticksImageFilter.txx index c571271..030a4c8 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkBallAndSticksImageFilter.txx +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkBallAndSticksImageFilter.txx @@ -1,253 +1,253 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkBallAndSticksImageFilter_txx #define __itkBallAndSticksImageFilter_txx #include #include #include #define _USE_MATH_DEFINES #include #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" #include namespace itk { template< class TInPixelType, class TOutPixelType > BallAndSticksImageFilter< TInPixelType, TOutPixelType> ::BallAndSticksImageFilter() : m_B_value(0) { this->SetNumberOfRequiredInputs( 1 ); - this->DynamicMultiThreadingOff(); + } template< class TInPixelType, class TOutPixelType > void BallAndSticksImageFilter< TInPixelType, TOutPixelType> ::BeforeThreadedGenerateData() { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); outputImage->FillBuffer(0.0); m_UnWeightedIndices.clear(); m_WeightedIndices.clear(); m_B_values.clear(); for (unsigned int i=0; iSize(); i++) { GradientDirectionType g = m_GradientDirections->GetElement(i); double twonorm = g.two_norm(); double b = m_B_value*twonorm*twonorm; m_B_values.push_back(b); if (b>100) m_WeightedIndices.push_back(i); else m_UnWeightedIndices.push_back(i); } if (m_UnWeightedIndices.empty()) mitkThrow() << "Unweighted (b=0 s/mm²) image volume missing!"; itk::Vector spacing3 = outputImage->GetSpacing(); itk::Point origin3 = outputImage->GetOrigin(); itk::Matrix direction3 = outputImage->GetDirection(); itk::ImageRegion<3> imageRegion3 = outputImage->GetLargestPossibleRegion(); itk::Vector spacing4; itk::Point origin4; itk::Matrix direction4; itk::ImageRegion<4> imageRegion4; spacing4[0] = spacing3[0]; spacing4[1] = spacing3[1]; spacing4[2] = spacing3[2]; spacing4[3] = 1; origin4[0] = origin3[0]; origin4[1] = origin3[1]; origin4[2] = origin3[2]; origin4[3] = 0; for (int r=0; r<3; r++) for (int c=0; c<3; c++) direction4[r][c] = direction3[r][c]; direction4[3][3] = 1; imageRegion4.SetSize(0, imageRegion3.GetSize()[0]); imageRegion4.SetSize(1, imageRegion3.GetSize()[1]); imageRegion4.SetSize(2, imageRegion3.GetSize()[2]); imageRegion4.SetSize(3, 3); m_PeakImage = PeakImageType::New(); m_PeakImage->SetSpacing( spacing4 ); m_PeakImage->SetOrigin( origin4 ); m_PeakImage->SetDirection( direction4 ); m_PeakImage->SetRegions( imageRegion4 ); m_PeakImage->Allocate(); m_PeakImage->FillBuffer(0.0); m_OutDwi = InputImageType::New(); m_OutDwi->SetSpacing( spacing3 ); m_OutDwi->SetOrigin( origin3 ); m_OutDwi->SetDirection( direction3 ); m_OutDwi->SetRegions( imageRegion3 ); m_OutDwi->SetVectorLength(m_GradientDirections->Size()); m_OutDwi->Allocate(); MITK_INFO << "Initial tensor fit"; typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); typename TensorRecFilterType::Pointer tensorReconstructionFilter = TensorRecFilterType::New(); tensorReconstructionFilter->SetBValue( m_B_value ); tensorReconstructionFilter->SetGradientImage( m_GradientDirections, inputImagePointer ); tensorReconstructionFilter->Update(); m_TensorImage = tensorReconstructionFilter->GetOutput(); } template< class TInPixelType, class TOutPixelType > vnl_vector BallAndSticksImageFilter< TInPixelType, TOutPixelType>::FitSingleVoxel( const typename InputImageType::PixelType &input, const typename InputImageType::IndexType &idx) { double S0 = 0; for (auto i : m_UnWeightedIndices) S0 += input[i]; S0 /= m_UnWeightedIndices.size(); // Linear tensor fit double md = 0.001; double f = 0.5; double theta = 0; double phi = 0; { TensorType tensor = m_TensorImage->GetPixel(idx); TensorType::EigenValuesArrayType eigenvalues; TensorType::EigenVectorsMatrixType eigenvectors; tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors); vnl_vector_fixed ev; ev[0] = eigenvectors(2, 0); ev[1] = eigenvectors(2, 1); ev[2] = eigenvectors(2, 2); if (ev.magnitude()>mitk::eps) ev.normalize(); else ev.fill(0.0); md = fabs(eigenvalues[0]+eigenvalues[1]+eigenvalues[2])/3; f = tensor.GetFractionalAnisotropy(); if (f<0.1) f = 0.1; else if (f>0.9) f = 0.9; mitk::AbstractFitter::Cart2Sph(ev, theta, phi); } int num_params = 4; // f, d, phi, theta vnl_vector x; x.set_size(num_params); x.fill(0.0); x[0] = f; // f (volume fraction) x[1] = md; // d x[2] = theta; x[3] = phi; mitk::BallStickFitter bs_fit(num_params, m_GradientDirections->size()); bs_fit.set_S0(S0); bs_fit.set_weightedIndices(m_WeightedIndices); bs_fit.set_bvalues(m_B_values); bs_fit.set_gradient_directions(m_GradientDirections); bs_fit.set_measurements(input); vnl_levenberg_marquardt lm(bs_fit); lm.minimize(x); return x; } template< class TInPixelType, class TOutPixelType > void BallAndSticksImageFilter< TInPixelType, TOutPixelType> -::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) +::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread ) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); InputIteratorType git( inputImagePointer, outputRegionForThread ); git.GoToBegin(); while( !git.IsAtEnd() ) { typename InputImageType::PixelType pix = git.Get(); vnl_vector x = FitSingleVoxel(pix, git.GetIndex()); /// PEAKS PeakImageType::IndexType idx4; idx4[0] = oit.GetIndex()[0]; idx4[1] = oit.GetIndex()[1]; idx4[2] = oit.GetIndex()[2]; oit.Set( x[0] ); vnl_vector_fixed dir; mitk::AbstractFitter::Sph2Cart(dir, x[2], x[3]); idx4[3] = 0; m_PeakImage->SetPixel(idx4, dir[0]); idx4[3] = 1; m_PeakImage->SetPixel(idx4, dir[1]); idx4[3] = 2; m_PeakImage->SetPixel(idx4, dir[2]); /// DWI from ball-stick typename InputImageType::PixelType dPix; dPix.SetSize(m_GradientDirections->Size()); dPix.Fill(0.0); for (unsigned int i=0; iSize(); i++) { GradientDirectionType g = m_GradientDirections->GetElement(i); double twonorm = g.two_norm(); double b = m_B_value*twonorm*twonorm; g.normalize(); double s_iso = 1000 * std::exp(-b * x[1]); double dot = dot_product(g, dir); double s_aniso = 1000 * std::exp(-b * x[1] * dot*dot ); double approx = (1-x[0])*s_iso + x[0]*s_aniso; dPix[i] = approx; } m_OutDwi->SetPixel(oit.GetIndex(), dPix); ++oit; ++git; } std::cout << "One Thread finished calculation" << std::endl; } template< class TInPixelType, class TOutPixelType > void BallAndSticksImageFilter< TInPixelType, TOutPixelType> ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); } } #endif // __itkBallAndSticksImageFilter_txx diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.cpp b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.cpp index a2d0133..0b12261 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.cpp +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.cpp @@ -1,720 +1,720 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_cpp #define __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_cpp #include "itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h" #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" #include "vnl/vnl_matrix.h" #include "vnl/algo/vnl_symmetric_eigensystem.h" #include #include "itkRegularizedIVIMReconstructionFilter.h" #include #define IVIM_FOO -100000 namespace itk { template< class TIn, class TOut> DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::DiffusionIntravoxelIncoherentMotionReconstructionImageFilter() : m_GradientDirectionContainer(nullptr), m_Method(IVIM_DSTAR_FIX), m_FitDStar(true), m_Verbose(false) { this->SetNumberOfRequiredInputs( 1 ); this->SetNumberOfRequiredOutputs( 3 ); typename OutputImageType::Pointer outputPtr1 = OutputImageType::New(); this->SetNthOutput(0, outputPtr1.GetPointer()); typename OutputImageType::Pointer outputPtr2 = OutputImageType::New(); this->SetNthOutput(1, outputPtr2.GetPointer()); typename OutputImageType::Pointer outputPtr3 = OutputImageType::New(); this->SetNthOutput(2, outputPtr3.GetPointer()); - this->DynamicMultiThreadingOff(); + } template< class TIn, class TOut> void DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::BeforeThreadedGenerateData() { // Input must be an itk::VectorImage. std::string gradientImageClassName(this->ProcessObject::GetInput(0)->GetNameOfClass()); if ( strcmp(gradientImageClassName.c_str(),"VectorImage") != 0 ) { itkExceptionMacro( << "There is only one Gradient image. I expect that to be a VectorImage. " << "But its of type: " << gradientImageClassName ); } // Compute the indicies of the baseline images and gradient images // If no b=0 mm/s² gradients ar found, the next lowest b-value is used. GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin(); double minNorm = itk::NumericTraits::max(); while( gdcit != this->m_GradientDirectionContainer->End() ) { double norm = gdcit.Value().one_norm(); if (normm_GradientDirectionContainer->Begin(); while( gdcit != this->m_GradientDirectionContainer->End() ) { if(gdcit.Value().one_norm() <= minNorm) m_Snap.baselineind.push_back(gdcit.Index()); else m_Snap.gradientind.push_back(gdcit.Index()); ++gdcit; } if (m_Snap.gradientind.size()==0) itkExceptionMacro("Only one b-value supplied. At least two needed for IVIM fit."); // check sind die grad und base gleichlang? alle grad gerade und base ungerade? dann iterierende aufnahme!! m_Snap.iterated_sequence = false; if(m_Snap.baselineind.size() == m_Snap.gradientind.size()) { int size = m_Snap.baselineind.size(); int sum_b = 0, sum_g = 0; for(int i=0; iGetElement(m_Snap.gradientind[i]).two_norm(); m_Snap.bvalues[i] = m_BValue*twonorm*twonorm; } if(m_Verbose) { std::cout << "ref bval: " << m_BValue << "; b-values: "; for(int i=0; im_BThres) m_Snap.high_indices.push_back(i); } m_Snap.num_high = m_Snap.high_indices.size(); m_Snap.high_bvalues.set_size(m_Snap.num_high); m_Snap.high_meas.set_size(m_Snap.num_high); for(int i=0; i MeasAndBvals DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::ApplyS0Threshold(vnl_vector &meas, vnl_vector &bvals) { std::vector newmeas; std::vector newbvals; int N = meas.size(); for(int i=0; i void DiffusionIntravoxelIncoherentMotionReconstructionImageFilter -::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) +::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread ) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); typename OutputImageType::Pointer dImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(1)); ImageRegionIterator< OutputImageType > oit1(dImage, outputRegionForThread); oit1.GoToBegin(); typename OutputImageType::Pointer dstarImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(2)); ImageRegionIterator< OutputImageType > oit2(dstarImage, outputRegionForThread); oit2.GoToBegin(); typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typedef typename InputImageType::PixelType InputVectorType; typename InputImageType::Pointer inputImagePointer = nullptr; // Would have liked a dynamic_cast here, but seems SGI doesn't like it // The enum will DiffusionIntravoxelIncoherentMotionReconstructionImageFilterensure that an inappropriate cast is not done inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); InputIteratorType iit(inputImagePointer, outputRegionForThread ); iit.GoToBegin(); // init internal vector image for regularized fit m_InternalVectorImage = VectorImageType::New(); m_InternalVectorImage->SetSpacing( inputImagePointer->GetSpacing() ); // Set the image spacing m_InternalVectorImage->SetOrigin( inputImagePointer->GetOrigin() ); // Set the image origin m_InternalVectorImage->SetDirection( inputImagePointer->GetDirection() ); // Set the image direction m_InternalVectorImage->SetRegions( inputImagePointer->GetLargestPossibleRegion() ); m_InitialFitImage = InitialFitImageType::New(); m_InitialFitImage->SetSpacing( inputImagePointer->GetSpacing() ); // Set the image spacing m_InitialFitImage->SetOrigin( inputImagePointer->GetOrigin() ); // Set the image origin m_InitialFitImage->SetDirection( inputImagePointer->GetDirection() ); // Set the image direction m_InitialFitImage->SetRegions( inputImagePointer->GetLargestPossibleRegion() ); if(m_Method == IVIM_REGULARIZED) { m_InternalVectorImage->SetVectorLength(m_Snap.num_high); m_InternalVectorImage->Allocate(); VectorImageType::PixelType varvec(m_Snap.num_high); for(int i=0; iFillBuffer(varvec); m_InitialFitImage->Allocate(); InitialFitImageType::PixelType vec; vec[0] = 0.5; vec[1] = 0.01; vec[2]=0.001; m_InitialFitImage->FillBuffer(vec); } typedef itk::ImageRegionIterator VectorIteratorType; VectorIteratorType vecit(m_InternalVectorImage, outputRegionForThread ); vecit.GoToBegin(); typedef itk::ImageRegionIterator InitIteratorType; InitIteratorType initit(m_InitialFitImage, outputRegionForThread ); initit.GoToBegin(); while( !iit.IsAtEnd() ) { InputVectorType measvec = iit.Get(); typename NumericTraits::AccumulateType b0 = NumericTraits::Zero; m_Snap.meas_for_threshold.set_size(m_Snap.num_weighted); m_Snap.allmeas.set_size(m_Snap.num_weighted); if(!m_Snap.iterated_sequence) { // Average the baseline image pixels for(unsigned int i = 0; i < m_Snap.baselineind.size(); ++i) b0 += measvec[m_Snap.baselineind[i]]; if(m_Snap.baselineind.size()) b0 /= m_Snap.baselineind.size(); // measurement vector for(int i = 0; i < m_Snap.num_weighted; ++i) { m_Snap.allmeas[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001); if(measvec[m_Snap.gradientind[i]] > m_S0Thres) m_Snap.meas_for_threshold[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001); else m_Snap.meas_for_threshold[i] = IVIM_FOO; } } else { // measurement vector for(int i = 0; i < m_Snap.num_weighted; ++i) { b0 = measvec[m_Snap.baselineind[i]]; m_Snap.allmeas[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001); if(measvec[m_Snap.gradientind[i]] > m_S0Thres) m_Snap.meas_for_threshold[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001); else m_Snap.meas_for_threshold[i] = IVIM_FOO; } } m_Snap.currentF = 0; m_Snap.currentD = 0; m_Snap.currentDStar = 0; switch(m_Method) { case IVIM_D_THEN_DSTAR: { for(int i=0; i x_donly(2); x_donly[0] = 0.001; x_donly[1] = 0.1; // f 0.1 Dstar 0.01 D 0.001 vnl_levenberg_marquardt lm_donly(f_donly); lm_donly.set_f_tolerance(0.0001); lm_donly.minimize(x_donly); m_Snap.currentD = x_donly[0]; m_Snap.currentF = x_donly[1]; if(m_FitDStar) { MeasAndBvals input2 = ApplyS0Threshold(m_Snap.meas_for_threshold, m_Snap.bvalues); m_Snap.bvals2 = input2.bvals; m_Snap.meas2 = input2.meas; if (input2.N < 2) break; IVIM_dstar_only f_dstar_only(input2.N,m_Snap.currentD,m_Snap.currentF); f_dstar_only.set_bvalues(input2.bvals); f_dstar_only.set_measurements(input2.meas); vnl_vector< double > x_dstar_only(1); vnl_vector< double > fx_dstar_only(input2.N); double opt = 1111111111111111.0; int opt_idx = -1; int num_its = 100; double min_val = .001; double max_val = .15; for(int i=0; i x(2); x[0] = 0.1; x[1] = 0.001; // f 0.1 Dstar 0.01 D 0.001 vnl_levenberg_marquardt lm(f_fixdstar); lm.set_f_tolerance(0.0001); lm.minimize(x); m_Snap.currentF = x[0]; m_Snap.currentD = x[1]; m_Snap.currentDStar = m_DStar; break; } case IVIM_FIT_ALL: { MeasAndBvals input = ApplyS0Threshold(m_Snap.meas_for_threshold, m_Snap.bvalues); m_Snap.bvals1 = input.bvals; m_Snap.meas1 = input.meas; if (input.N < 3) break; IVIM_3param f_3param(input.N); f_3param.set_bvalues(input.bvals); f_3param.set_measurements(input.meas); vnl_vector< double > x(3); x[0] = 0.1; x[1] = 0.001; x[2] = 0.01; // f 0.1 Dstar 0.01 D 0.001 vnl_levenberg_marquardt lm(f_3param); lm.set_f_tolerance(0.0001); lm.minimize(x); m_Snap.currentF = x[0]; m_Snap.currentD = x[1]; m_Snap.currentDStar = x[2]; break; } case IVIM_LINEAR_D_THEN_F: { for(int i=0; i X(input.N,2); bool nan_element = false; for(int i=0; i XX = X.transpose() * X; vnl_symmetric_eigensystem eigs(XX); vnl_vector eig; if(eigs.get_eigenvalue(0) > eigs.get_eigenvalue(1)) eig = eigs.get_eigenvector(0); else eig = eigs.get_eigenvector(1); m_Snap.currentF = 1 - exp( meas_m - bval_m*(eig(1)/eig(0)) ); m_Snap.currentD = -eig(1)/eig(0); if(m_FitDStar) { MeasAndBvals input2 = ApplyS0Threshold(m_Snap.meas_for_threshold, m_Snap.bvalues); m_Snap.bvals2 = input2.bvals; m_Snap.meas2 = input2.meas; if (input2.N < 2) break; IVIM_dstar_only f_dstar_only(input2.N,m_Snap.currentD,m_Snap.currentF); f_dstar_only.set_bvalues(input2.bvals); f_dstar_only.set_measurements(input2.meas); vnl_vector< double > x_dstar_only(1); vnl_vector< double > fx_dstar_only(input2.N); double opt = 1111111111111111.0; int opt_idx = -1; int num_its = 100; double min_val = .001; double max_val = .15; for(int i=0; i " << DStar; // x_dstar_only[0] = 0.01; // // f 0.1 Dstar 0.01 D 0.001 // vnl_levenberg_marquardt lm_dstar_only(f_dstar_only); // lm_dstar_only.set_f_tolerance(0.0001); // lm_dstar_only.minimize(x_dstar_only); // DStar = x_dstar_only[0]; break; } case IVIM_REGULARIZED: { //m_Snap.high_meas, m_Snap.high_bvalues; for(int i=0; i x_donly(2); x_donly[0] = 0.001; x_donly[1] = 0.1; if(input.N >= 2) { IVIM_d_and_f f_donly(input.N); f_donly.set_bvalues(input.bvals); f_donly.set_measurements(input.meas); //MITK_INFO << "initial fit N=" << input.N << ", min-b = " << input.bvals[0] << ", max-b = " << input.bvals[input.N-1]; vnl_levenberg_marquardt lm_donly(f_donly); lm_donly.set_f_tolerance(0.0001); lm_donly.minimize(x_donly); } typename InitialFitImageType::PixelType initvec; initvec[0] = x_donly[1]; initvec[1] = x_donly[0]; initit.Set(initvec); //MITK_INFO << "Init vox " << initit.GetIndex() << " with " << initvec[0] << "; " << initvec[1]; ++initit; int N = m_Snap.high_meas.size(); typename VectorImageType::PixelType vec(N); for(int i=0; i void DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::AfterThreadedGenerateData() { if(m_Method == IVIM_REGULARIZED) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); ImageRegionIterator< OutputImageType > oit0(outputImage, outputImage->GetLargestPossibleRegion()); oit0.GoToBegin(); typename OutputImageType::Pointer dImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(1)); ImageRegionIterator< OutputImageType > oit1(dImage, dImage->GetLargestPossibleRegion()); oit1.GoToBegin(); typename OutputImageType::Pointer dstarImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(2)); ImageRegionIterator< OutputImageType > oit2(dstarImage, dstarImage->GetLargestPossibleRegion()); oit2.GoToBegin(); typedef itk::RegularizedIVIMReconstructionFilter RegFitType; RegFitType::Pointer filter = RegFitType::New(); filter->SetInput(m_InitialFitImage); filter->SetReferenceImage(m_InternalVectorImage); filter->SetBValues(m_Snap.high_bvalues); filter->SetNumberIterations(m_NumberIterations); filter->SetNumberOfWorkUnits(1); filter->SetLambda(m_Lambda); filter->Update(); typename RegFitType::OutputImageType::Pointer outimg = filter->GetOutput(); ImageRegionConstIterator< RegFitType::OutputImageType > iit(outimg, outimg->GetLargestPossibleRegion()); iit.GoToBegin(); while( !iit.IsAtEnd() ) { double f = iit.Get()[0]; IVIM_CEIL( f, 0.0, 1.0 ); oit0.Set( myround(f) ); oit1.Set( myround(iit.Get()[1]) ); oit2.Set( myround(iit.Get()[2]) ); if(!m_Verbose) { // report the middle voxel if( iit.GetIndex()[0] == static_cast(outimg->GetLargestPossibleRegion().GetSize(0)-1)/2 && iit.GetIndex()[1] == static_cast(outimg->GetLargestPossibleRegion().GetSize(2)-1)/2 && iit.GetIndex()[2] == static_cast(outimg->GetLargestPossibleRegion().GetSize(1)-1)/2 ) { m_Snap.currentF = f; m_Snap.currentD = iit.Get()[1]; m_Snap.currentDStar = iit.Get()[2]; m_Snap.allmeas = m_tmp_allmeas; MITK_INFO << "setting " << f << ";" << iit.Get()[1] << ";" << iit.Get()[2]; } } ++oit0; ++oit1; ++oit2; ++iit; } } } template< class TIn, class TOut> double DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::myround(double number) { return number < 0.0 ? ceil(number - 0.5) : floor(number + 0.5); } template< class TIn, class TOut> void DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::SetGradientDirections( GradientDirectionContainerType::ConstPointer gradientDirection ) { this->m_GradientDirectionContainer = gradientDirection; this->m_NumberOfGradientDirections = gradientDirection->Size(); } template< class TIn, class TOut> void DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); if ( m_GradientDirectionContainer ) { os << indent << "GradientDirectionContainer: " << m_GradientDirectionContainer << std::endl; } else { os << indent << "GradientDirectionContainer: (Gradient directions not set)" << std::endl; } } } #endif // __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_cpp diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h index d42212e..34098e0 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h @@ -1,417 +1,416 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_h #define __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_h #include "itkImageToImageFilter.h" //#include "vnl/vnl_matrix.h" #include "vnl/vnl_vector_fixed.h" #include "vnl/vnl_matrix.h" #include "vnl/algo/vnl_svd.h" #include "itkVectorContainer.h" #include "itkVectorImage.h" //#include "QuadProg.h" #include "itkVectorImage.h" #include "vnl/vnl_least_squares_function.h" #include "vnl/vnl_cost_function.h" #include "vnl/algo/vnl_levenberg_marquardt.h" #include "vnl/vnl_math.h" #define IVIM_CEIL(val,u,o) (val) = \ ( (val) < (u) ) ? ( (u) ) : ( ( (val)>(o) ) ? ( (o) ) : ( (val) ) ); namespace itk{ /** baseclass for IVIM fitting algorithms */ struct IVIM_base { void set_measurements(const vnl_vector& x) { measurements.set_size(x.size()); measurements.copy_in(x.data_block()); } void set_bvalues(const vnl_vector& x) { bvalues.set_size(x.size()); bvalues.copy_in(x.data_block()); } vnl_vector measurements; vnl_vector bvalues; int N; }; /** Fitt all three parameters */ struct IVIM_3param : public IVIM_base, vnl_least_squares_function { IVIM_3param(unsigned int number_of_measurements) : vnl_least_squares_function(3, number_of_measurements, no_gradient) { N = get_number_of_residuals(); } void f(const vnl_vector& x, vnl_vector& fx) override { double ef = x[0]; double D = x[1]; double Dstar = x[2]; for(int s=0; s0.003) fx[s] += D*100000; if (Dstar>0.3) fx[s] += Dstar*100000; } } }; /** fit by setting DStar to a fix value */ struct IVIM_fixdstar : public IVIM_base, vnl_least_squares_function { IVIM_fixdstar(unsigned int number_of_measurements, double DStar) : vnl_least_squares_function(2, number_of_measurements, no_gradient) { N = get_number_of_residuals(); fixDStar = DStar; } void f(const vnl_vector& x, vnl_vector& fx) override { double ef = x[0]; double D = x[1]; for(int s=0; s0.003) fx[s] += D*100000; } } double fixDStar; }; /** fit a monoexponential curve only estimating D and f */ struct IVIM_d_and_f : public IVIM_base, vnl_least_squares_function { IVIM_d_and_f(unsigned int number_of_measurements) : vnl_least_squares_function(2, number_of_measurements, no_gradient) { N = get_number_of_residuals(); } void f(const vnl_vector& x, vnl_vector& fx) override { double D = x[0]; double f = x[1]; for(int s=0; s0.003) fx[s] += D*100000; } } }; /** fiting DStar and f with fix value of D */ struct IVIM_fixd : public IVIM_base, vnl_least_squares_function { IVIM_fixd(unsigned int number_of_measurements, double D) : vnl_least_squares_function(2, number_of_measurements, no_gradient) { N = get_number_of_residuals(); fixD = D; } void f(const vnl_vector& x, vnl_vector& fx) override { double ef = x[0]; double Dstar = x[1]; for(int s=0; s0.3) fx[s] += Dstar*100000; } } double fixD; }; /** fiting DStar with given f and D */ struct IVIM_dstar_only : public IVIM_base, vnl_least_squares_function { IVIM_dstar_only(unsigned int number_of_measurements, double D, double f) : vnl_least_squares_function(1, number_of_measurements, no_gradient) { N = get_number_of_residuals(); fixD = D; fixF = f; } void f(const vnl_vector& x, vnl_vector& fx) override { double Dstar = x[0]; for(int s=0; s0.3) fx[s] += Dstar*100000; } } double fixD; double fixF; }; struct MeasAndBvals { vnl_vector meas; vnl_vector bvals; int N; }; /** \class DiffusionIntravoxelIncoherentMotionReconstructionImageFilter */ template< class TInputPixelType, class TOutputPixelType> class DiffusionIntravoxelIncoherentMotionReconstructionImageFilter : public ImageToImageFilter< VectorImage< TInputPixelType, 3 >, Image< TOutputPixelType, 3 > > { public: struct IVIMSnapshot { double currentF; double currentFunceiled; double currentD; double currentDStar; bool iterated_sequence; // wether each measurement has its own b0-acqu. std::vector baselineind; // baseline image indicies std::vector gradientind; // gradient image indicies vnl_vector bvalues; // bvalues != 0 int num_weighted; // total number of measurements vnl_vector meas_for_threshold; // all measurements, thresholded blanked out vnl_vector allmeas; // all measurements int num_high; // number of used measurements std::vector high_indices; // indices of used measurements vnl_vector high_bvalues; // bvals of used measurements vnl_vector high_meas; // used measurements // fit 1 vnl_vector meas1; vnl_vector bvals1; // fit 2 vnl_vector meas2; vnl_vector bvals2; }; enum IVIM_Method { IVIM_FIT_ALL, IVIM_DSTAR_FIX, IVIM_D_THEN_DSTAR, IVIM_LINEAR_D_THEN_F, IVIM_REGULARIZED }; typedef DiffusionIntravoxelIncoherentMotionReconstructionImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< TInputPixelType, 3>, Image< TOutputPixelType,3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DiffusionIntravoxelIncoherentMotionReconstructionImageFilter, ImageToImageFilter); typedef TOutputPixelType OutputPixelType; typedef TInputPixelType InputPixelType; /** Reference image data, This image is aquired in the absence * of a diffusion sensitizing field gradient */ typedef typename Superclass::InputImageType InputImageType; typedef Image< OutputPixelType, 3 > OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; /** Holds each magnetic field gradient used to acquire one DWImage */ typedef vnl_vector_fixed< double, 3 > GradientDirectionType; /** Container to hold gradient directions of the 'n' DW measurements */ typedef VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; // vector image typedefs for regularized fit typedef itk::VectorImage VectorImageType; typedef itk::Image, 3> InitialFitImageType; /** set method to add gradient directions and its corresponding * image. The image here is a VectorImage. The user is expected to pass the * gradient directions in a container. The ith element of the container * corresponds to the gradient direction of the ith component image the * VectorImage. For the baseline image, a vector of all zeros * should be set.*/ void SetGradientDirections( GradientDirectionContainerType::ConstPointer ); void SetBValue(double bval){m_BValue = bval;} void SetBThres(double bval){m_BThres = bval;} void SetS0Thres(double val){m_S0Thres = val;} void SetDStar(double dstar){m_DStar = dstar;} void SetFitDStar(bool fit){m_FitDStar = fit;} void SetVerbose(bool verbose){m_Verbose = verbose;} void SetNumberIterations(int num){m_NumberIterations = num;} void SetLambda(double lambda){m_Lambda = lambda;} void SetCrossPosition(typename InputImageType::IndexType crosspos){this->m_CrossPosition = crosspos;} void SetMethod(IVIM_Method method){m_Method = method;} IVIMSnapshot GetSnapshot(){return m_Snap;} /** Return the gradient direction. idx is 0 based */ virtual GradientDirectionType GetGradientDirection( unsigned int idx) const { if( idx >= m_NumberOfGradientDirections ) { itkExceptionMacro( << "Gradient direction " << idx << "does not exist" ); } return m_GradientDirectionContainer->ElementAt( idx+1 ); } protected: DiffusionIntravoxelIncoherentMotionReconstructionImageFilter(); ~DiffusionIntravoxelIncoherentMotionReconstructionImageFilter() {}; void PrintSelf(std::ostream& os, Indent indent) const; void BeforeThreadedGenerateData(); - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, - ThreadIdType); + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread); void AfterThreadedGenerateData(); MeasAndBvals ApplyS0Threshold(vnl_vector &meas, vnl_vector &bvals); private: double myround(double number); /** container to hold gradient directions */ GradientDirectionContainerType::ConstPointer m_GradientDirectionContainer; /** Number of gradient measurements */ unsigned int m_NumberOfGradientDirections; double m_BValue; double m_BThres; double m_S0Thres; double m_DStar; IVIM_Method m_Method; typename OutputImageType::Pointer m_DMap; typename OutputImageType::Pointer m_DStarMap; bool m_FitDStar; IVIMSnapshot m_Snap; bool m_Verbose; typename VectorImageType::Pointer m_InternalVectorImage; typename InitialFitImageType::Pointer m_InitialFitImage; int m_NumberIterations; // for total variation vnl_vector m_tmp_allmeas; double m_Lambda; typename InputImageType::IndexType m_CrossPosition; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.cpp" #endif #endif //__itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_h diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.cxx b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.cxx index c8e88b7..11ea10d 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.cxx +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.cxx @@ -1,494 +1,494 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_CXX #define DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_CXX #include "itkDiffusionKurtosisReconstructionImageFilter.h" #include #include #include #include #include #include #include template< class TInputPixelType> static void FitSingleVoxel( const itk::VariableLengthVector< TInputPixelType > &input, const vnl_vector& bvalues, vnl_vector& result, itk::KurtosisFitConfiguration kf_config) { // check for length assert( input.Size() == bvalues.size() ); // assembly data vectors for fitting auto bvalueIter = bvalues.begin(); unsigned int unused_values = 0; while( bvalueIter != bvalues.end() ) { if( *bvalueIter < vnl_math::eps && kf_config.omit_bzero ) { ++unused_values; } ++bvalueIter; } // initialize data vectors with the estimated size (after filtering) vnl_vector fit_measurements( input.Size() - unused_values, 0 ); vnl_vector fit_bvalues( input.Size() - unused_values, 0 ); bvalueIter = bvalues.begin(); unsigned int running_index = 0; unsigned int skip_count = 0; while( bvalueIter != bvalues.end() ) { // skip b=0 if the corresponding flag is set if( ( kf_config.omit_bzero && *bvalueIter < vnl_math::eps ) // skip bvalues higher than the limit provided, if the flag is activated || ( kf_config.exclude_high_b && *bvalueIter > kf_config.b_upper_threshold ) ) { ++skip_count; } else { fit_measurements[ running_index - skip_count ] = input.GetElement(running_index); fit_bvalues[ running_index - skip_count] = *bvalueIter; } ++running_index; ++bvalueIter; } MITK_DEBUG("KurtosisFilter.FitSingleVoxel.Meas") << fit_measurements; MITK_DEBUG("KurtosisFilter.FitSingleVoxel.Bval") << fit_bvalues; // perform fit on data vectors if( kf_config.omit_bzero ) { itk::kurtosis_fit_omit_unweighted kurtosis_cost_fn( fit_measurements.size() ); // configuration kurtosis_cost_fn.set_fit_logscale( static_cast(kf_config.fit_scale) ); kurtosis_cost_fn.initialize( fit_measurements, fit_bvalues ); if( kf_config.use_K_limits) { kurtosis_cost_fn.set_K_bounds( kf_config.K_limits ); } vnl_levenberg_marquardt nonlinear_fit( kurtosis_cost_fn ); nonlinear_fit.minimize( result ); } else { itk::kurtosis_fit_lsq_function kurtosis_cost_fn( fit_measurements.size() ); // configuration kurtosis_cost_fn.set_fit_logscale( static_cast(kf_config.fit_scale) ); kurtosis_cost_fn.initialize( fit_measurements, fit_bvalues ); if( kf_config.use_K_limits) { kurtosis_cost_fn.set_K_bounds( kf_config.K_limits ); } vnl_levenberg_marquardt nonlinear_fit( kurtosis_cost_fn ); nonlinear_fit.minimize(result); } MITK_DEBUG("KurtosisFilter.FitSingleVoxel.Rslt") << result; } template< class TInputPixelType, class TOutputPixelType> itk::DiffusionKurtosisReconstructionImageFilter ::DiffusionKurtosisReconstructionImageFilter() : m_ReferenceBValue(-1), m_OmitBZero(false), m_ApplyPriorSmoothing(false), m_SmoothingSigma(1.5), m_UseKBounds( false ), m_MaxFitBValue( 3000 ), m_ScaleForFitting( STRAIGHT ) { this->m_InitialPosition = vnl_vector(3, 0); this->m_InitialPosition[2] = 1000.0; // S_0 this->m_InitialPosition[0] = 0.001; // D this->m_InitialPosition[1] = 1; // K this->m_KurtosisBounds.fill(0); // single input image this->SetNumberOfRequiredInputs(1); // two output images (D, K) this->SetNumberOfRequiredOutputs(2); typename OutputImageType::Pointer outputPtr1 = OutputImageType::New(); typename OutputImageType::Pointer outputPtr2 = OutputImageType::New(); this->SetNthOutput(0, outputPtr1.GetPointer() ); this->SetNthOutput(1, outputPtr2.GetPointer() ); - this->DynamicMultiThreadingOff(); + } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::GenerateOutputInformation() { // first call superclass Superclass::GenerateOutputInformation(); } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::SetImageMask(MaskImageType::Pointer mask) { this->m_MaskImage = mask; } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::BeforeThreadedGenerateData() { // if we have a region set, convert it to a mask image, which is to be used as default for telling // we need to set the image anyway, so by default the mask is overall 1 if( m_MaskImage.IsNull() ) { m_MaskImage = MaskImageType::New(); m_MaskImage->SetRegions( this->GetInput()->GetLargestPossibleRegion() ); m_MaskImage->CopyInformation( this->GetInput() ); m_MaskImage->Allocate(); if( this->m_MapOutputRegion.GetNumberOfPixels() > 0 ) { m_MaskImage->FillBuffer(0); typedef itk::ImageRegionIteratorWithIndex< MaskImageType > MaskIteratorType; MaskIteratorType maskIter( this->m_MaskImage, this->m_MapOutputRegion ); maskIter.GoToBegin(); while( !maskIter.IsAtEnd() ) { maskIter.Set( 1 ); ++maskIter; } } else { m_MaskImage->FillBuffer(1); } } // apply smoothing to the input image if( this->m_ApplyPriorSmoothing ) { // filter typedefs typedef itk::DiscreteGaussianImageFilter< itk::Image, itk::Image > GaussianFilterType; typedef itk::VectorIndexSelectionCastImageFilter< InputImageType, itk::Image > IndexSelectionType; typedef itk::ComposeImageFilter< itk::Image, InputImageType > ComposeFilterType; auto vectorImage = this->GetInput(); typename IndexSelectionType::Pointer indexSelectionFilter = IndexSelectionType::New(); indexSelectionFilter->SetInput( vectorImage ); typename ComposeFilterType::Pointer vec_composer = ComposeFilterType::New(); for( unsigned int i=0; iGetVectorLength(); ++i) { typename GaussianFilterType::Pointer gaussian_filter = GaussianFilterType::New(); indexSelectionFilter->SetIndex( i ); gaussian_filter->SetInput( indexSelectionFilter->GetOutput() ); gaussian_filter->SetVariance( m_SmoothingSigma ); vec_composer->SetInput(i, gaussian_filter->GetOutput() ); gaussian_filter->Update(); } try { vec_composer->Update(); } catch(const itk::ExceptionObject &e) { mitkThrow() << "[VectorImage.GaussianSmoothing] !! Failed with ITK Exception: " << e.what(); } this->m_ProcessedInputImage = vec_composer->GetOutput(); } else { this->m_ProcessedInputImage = const_cast( this->GetInput() ); } } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::AfterThreadedGenerateData() { /* // initialize buffer to zero overall, but don't forget the requested region pointer for( unsigned int i=0; iGetNumberOfOutputs(); ++i) { typename OutputImageType::Pointer output = this->GetOutput(i); // after generating, set the buffered region to max, we have taken care about filling it with valid data in // UpdateOutputInformation, if not set, a writer (or any filter using the LargestPossibleRegion() during update may // complain about not getting the requested region output->SetBufferedRegion( output->GetLargestPossibleRegion() ); std::cout << "[DiffusionKurtosisReconstructionImageFilter.After]" << output->GetLargestPossibleRegion() << std::endl; }*/ } template< class TInputPixelType, class TOutputPixelType> typename itk::DiffusionKurtosisReconstructionImageFilter::KurtosisSnapshot itk::DiffusionKurtosisReconstructionImageFilter ::GetSnapshot(const itk::VariableLengthVector &input, GradientDirectionContainerType::ConstPointer gradients, float bvalue, KurtosisFitConfiguration kf_conf) { // initialize bvalues from reference value and the gradients provided on input this->SetReferenceBValue(bvalue); this->SetGradientDirections( gradients ); // call the other method return this->GetSnapshot( input, this->m_BValues, kf_conf ); } template< class TInputPixelType, class TOutputPixelType> typename itk::DiffusionKurtosisReconstructionImageFilter::KurtosisSnapshot itk::DiffusionKurtosisReconstructionImageFilter ::GetSnapshot(const itk::VariableLengthVector &input, vnl_vector bvalues, KurtosisFitConfiguration kf_conf) { // initialize vnl_vector initial_position; bool omit_bzero = kf_conf.omit_bzero; if( !omit_bzero ) { initial_position.set_size(2); initial_position[0] = this->m_InitialPosition[0]; initial_position[1] = this->m_InitialPosition[1]; } else { initial_position.set_size(3); initial_position = this->m_InitialPosition; } // fit FitSingleVoxel( input, bvalues, initial_position, kf_conf ); // assembly result snapshot KurtosisSnapshot result; result.m_D = initial_position[0]; result.m_K = initial_position[1]; if( omit_bzero ) { result.m_f = 1 - initial_position[2] / std::fmax(0.01, input.GetElement(0)); result.m_BzeroFit = initial_position[2]; } else result.m_f = 1; // assembly data vectors for fitting auto bvalueIter = bvalues.begin(); unsigned int unused_values = 0; while( bvalueIter != bvalues.end() ) { if( *bvalueIter < vnl_math::eps && omit_bzero ) { ++unused_values; } ++bvalueIter; } // initialize data vectors with the estimated size (after filtering) vnl_vector fit_measurements( input.Size() - unused_values, 0 ); vnl_vector fit_bvalues( input.Size() - unused_values, 0 ); // original data vnl_vector orig_measurements( input.Size(), 0 ); bvalueIter = bvalues.begin(); unsigned int running_index = 0; unsigned int skip_count = 0; unsigned int bzero_count = 0; result.m_Bzero = 0; while( bvalueIter != bvalues.end() ) { if( *bvalueIter < vnl_math::eps && omit_bzero ) { ++skip_count; } else { fit_measurements[ running_index - skip_count ] = input.GetElement(running_index); fit_bvalues[ running_index - skip_count ] = *bvalueIter; } if( *bvalueIter < vnl_math::eps ) { result.m_Bzero += input.GetElement(running_index); ++bzero_count; } orig_measurements[ running_index ] = input.GetElement(running_index); ++running_index; ++bvalueIter; } result.m_Bzero /= bzero_count; result.fit_bvalues = fit_bvalues; result.fit_measurements = fit_measurements; result.bvalues = bvalues; result.measurements = orig_measurements; result.m_fittedBZero = omit_bzero; return result; } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::SetGradientDirections(GradientDirectionContainerType::ConstPointer gradients) { if( this->m_ReferenceBValue < 0) { itkExceptionMacro( << "Specify reference b-value prior to setting the gradient directions." ); } if( gradients->Size() == 0 ) { itkExceptionMacro( << "Empty gradient directions container retrieved" ); } vnl_vector vnl_bvalues( gradients->Size(), 0 ); // initialize the b-values auto grIter = gradients->Begin(); unsigned int index = 0; while( grIter != gradients->End() ) { const double twonorm = grIter.Value().two_norm(); vnl_bvalues( index++ ) = this->m_ReferenceBValue * twonorm * twonorm; ++grIter; } this->m_BValues = vnl_bvalues; } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::SetInitialSolution(const vnl_vector& x0 ) { assert( x0.size() == (2 + static_cast( this->m_OmitBZero )) ); this->m_InitialPosition = x0; } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter -::ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType /*threadId*/) +::DynamicThreadedGenerateData(const OutputImageRegionType &outputRegionForThread /*threadId*/) { typename OutputImageType::Pointer dImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); itk::ImageRegionIteratorWithIndex< OutputImageType > dImageIt(dImage, outputRegionForThread); dImageIt.GoToBegin(); typename OutputImageType::Pointer kImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(1)); itk::ImageRegionIteratorWithIndex< OutputImageType > kImageIt(kImage, outputRegionForThread); kImageIt.GoToBegin(); typedef itk::ImageRegionConstIteratorWithIndex< InputImageType > InputIteratorType; InputIteratorType inputIter( m_ProcessedInputImage, outputRegionForThread ); inputIter.GoToBegin(); typedef itk::ImageRegionConstIteratorWithIndex< MaskImageType > MaskIteratorType; MaskIteratorType maskIter( this->m_MaskImage, outputRegionForThread ); maskIter.GoToBegin(); KurtosisFitConfiguration fit_config; fit_config.omit_bzero = this->m_OmitBZero; fit_config.fit_scale = this->m_ScaleForFitting; fit_config.use_K_limits = this->m_UseKBounds; fit_config.K_limits = this->m_KurtosisBounds; vnl_vector initial_position; if( !this->m_OmitBZero ) { initial_position.set_size(2); initial_position[0] = this->m_InitialPosition[0]; initial_position[1] = this->m_InitialPosition[1]; } else { initial_position.set_size(3); initial_position = this->m_InitialPosition; } while( !inputIter.IsAtEnd() ) { // set (reset) each iteration vnl_vector result = initial_position; // fit single voxel (if inside mask ) if( maskIter.Get() > 0 ) { FitSingleVoxel( inputIter.Get(), this->m_BValues, result, fit_config ); } else { result.fill(0); } // regardless the fit type, the parameters are always in the first two position // of the results vector dImageIt.Set( result[0] ); kImageIt.Set( result[1] ); //std::cout << "[Kurtosis.Fit]" << inputIter.GetIndex() << " --> " << dImageIt.GetIndex() << " result: " << result << std::endl; ++maskIter; ++inputIter; ++dImageIt; ++kImageIt; } } #endif // guards diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.h b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.h index 59a6b94..f0742ea 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.h @@ -1,443 +1,443 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_H #define DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_H #include "itkImageToImageFilter.h" #include "itkVectorImage.h" #include "mitkDiffusionPropertyHelper.h" // vnl includes #include #include namespace itk { // Fitting routines /** @struct Kurtosis_fit_lsq_function @brief A base least-squares function for the diffusion kurtosis fit (non-IVIM) The basic function fits the signal to S_0 = S * exp [ -b * D + -b^2 * D^2 * K^2 ] */ struct kurtosis_fit_lsq_function : public vnl_least_squares_function { public: /** full lsq_function constructor */ kurtosis_fit_lsq_function( unsigned int num_params, unsigned int num_measurements, UseGradient g=no_gradient) : vnl_least_squares_function( num_params, num_measurements, g), m_use_bounds(false), m_use_logscale(false), m_skip_fit(false) {} /** simplified constructor for the 2-parameters fit */ kurtosis_fit_lsq_function( unsigned int number_measurements) : kurtosis_fit_lsq_function( 2, number_measurements, no_gradient ) {} /** Initialize the function by setting measurements and the corresponding b-values */ void initialize( vnl_vector< double > const& _meas, vnl_vector< double> const& _bvals ) { meas = _meas; if( m_use_logscale ) { for( unsigned int i=0; i< meas.size(); ++i) { // would produce NaN values, skip the fit // using the virtual function from the superclass (sets a boolean flag) if( meas[i] < vnl_math::eps ) { m_skip_fit = true; throw_failure(); continue; } meas[i] = log( meas[i] ); } } bvalues = _bvals; } /** use penalty terms on fitting to force the parameters stay within the default bounds */ void use_bounds() { m_use_bounds = true; // initialize bounds double upper_bounds[2] = {4e-3, 4 }; kurtosis_upper_bounds = vnl_vector(2, 2, upper_bounds); kurtosis_lower_bounds = vnl_vector(2, 0); } void set_fit_logscale( bool flag ) { this->m_use_logscale = flag; } void set_K_bounds( const vnl_vector_fixed k_bounds ) { // init this->use_bounds(); // override K bounds kurtosis_lower_bounds[1] = k_bounds[0]; kurtosis_upper_bounds[1] = k_bounds[1]; } virtual void f(const vnl_vector &x, vnl_vector &fx) { for ( unsigned int s=0; s < fx.size(); s++ ) { const double factor = ( meas[s] - M(x, s) ); fx[s] = factor * factor + penalty_term(x); } MITK_DEBUG("Fit.x_and_f") << x << " | " << fx; } protected: /** Formula for diffusion term, use for internal computations */ double Diff( double x1, double x2, double b) { const double quotient = -1. * b * x1 + b*b * x1 * x1 * x2 / 6; if( m_use_logscale ) return quotient; else return exp(quotient); } /** The fitting measurement function, has to be reimplemented in the classes */ virtual double M( vnl_vector const& x, unsigned int idx ) { const double bvalue = bvalues[idx]; double result = Diff( x[0], x[1], bvalue); if( m_use_logscale ) return meas[0] + result; else return meas[0] * result ; } /** Penalty term on D and K during fitting, make sure the vector that is passed in contains (D, K) in this ordering */ virtual double penalty_term( vnl_vector const& x) { double penalty = 0; // skip when turned off if( !m_use_bounds ) return penalty; // we have bounds for D and K only (the first two params ) for( unsigned int i=0; i< 2; i++) { // 5% penalty boundary // use exponential function to scale the penalty (max when x[i] == bounds ) double penalty_boundary = 0.02 * (kurtosis_upper_bounds[i] - kurtosis_lower_bounds[i]); if( x[i] < kurtosis_lower_bounds[i] + penalty_boundary ) { penalty += 1e6 * exp( -1 * ( x[i] - kurtosis_lower_bounds[i]) / penalty_boundary ); } else if ( x[i] > kurtosis_upper_bounds[i] - penalty_boundary ) { penalty += 1e6 * exp( -1 * ( kurtosis_upper_bounds[i] - x[i]) / penalty_boundary ); } } MITK_DEBUG("Fit.Orig.Penalty") << x << " || penalty: " << penalty; return penalty; } bool m_use_bounds; bool m_use_logscale; bool m_skip_fit; vnl_vector kurtosis_upper_bounds; vnl_vector kurtosis_lower_bounds; vnl_vector meas; vnl_vector bvalues; }; /** @struct kurtosis_fit_omit_unweighted @brief A fitting function handling the unweighted signal b_0 as a fitted parameter */ struct kurtosis_fit_omit_unweighted : public kurtosis_fit_lsq_function { public: /** simplified constructor for the 3-parameters fit */ kurtosis_fit_omit_unweighted( unsigned int number_measurements) : kurtosis_fit_lsq_function( 3, number_measurements, no_gradient ) {} protected: virtual double M(const vnl_vector &x, unsigned int idx) override { const double bvalue = bvalues[idx]; double result = Diff( x[0], x[1], bvalue); if( m_use_logscale ) return log( x[2] ) + result; else return x[2] * result ; } }; enum FitScale { STRAIGHT = 0, LOGARITHMIC }; struct KurtosisFitConfiguration { KurtosisFitConfiguration() : omit_bzero(false) , use_K_limits(false) , exclude_high_b(false) , b_upper_threshold(10e9) {} bool omit_bzero; FitScale fit_scale; bool use_K_limits; vnl_vector_fixed K_limits; bool exclude_high_b; double b_upper_threshold; }; /** @class DiffusionKurtosisReconstructionImageFilter @brief This filter provides the fit of the kurtosis (non-IVIM) signal to the data It has two main modes of operation, either as an image filter to compute the D and K maps, i.e. fitting the values to each voxel or a computation on a single voxel or a voxel group (with mask) can be triggered by @sa GetSnapshot, GetCurrentSnapshot methods. */ template< class TInputPixelType, class TOutputPixelType > class DiffusionKurtosisReconstructionImageFilter : public ImageToImageFilter< VectorImage< TInputPixelType, 3>, Image > { public: /** @struct KurtosisSnapshot @brief Struct describing a result (and the data) of a Kurtosis model fit */ struct KurtosisSnapshot { KurtosisSnapshot() : m_f(1), m_BzeroFit(1), m_D(0.001), m_K(0) {} // input data structures //vnl_vector filtered_measurements; vnl_vector bvalues; vnl_vector measurements; vnl_vector fit_bvalues; vnl_vector fit_measurements; vnl_vector weighted_image_indices; bool m_fittedBZero; // variables holding the fitted values double m_f; double m_BzeroFit; double m_D; double m_K; double m_Bzero; // mean baseline signal }; //-- class typedefs typedef DiffusionKurtosisReconstructionImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< TInputPixelType, 3>, Image< TOutputPixelType,3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DiffusionKurtosisReconstructionImageFilter, ImageToImageFilter) typedef TOutputPixelType OutputPixelType; typedef TInputPixelType InputPixelType; typedef typename Superclass::InputImageType InputImageType; typedef Image< OutputPixelType, 3 > OutputImageType; typedef itk::Image< short , 3> MaskImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; /** Holds each magnetic field gradient used to acquire one DWImage */ typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType GradientDirectionContainerType; // vector image typedefs for regularized fit typedef itk::VectorImage VectorImageType; typedef itk::Image, 3> InitialFitImageType; //-- input (Set) methods /** Set the initial solution for fitting, make sure the length and the values correspond to the parameters * x0 = ( S_0, ADC_0, AKC_0 ) when also the S_0 is estimated * x0 = ( ADC_0, AKC_0 ) when the S_0 is used in fitting */ void SetInitialSolution(const vnl_vector& x0 ); /** Set whether the S_0 value is fitted or used in fitting */ void SetOmitUnweightedValue( bool flag) { this->m_OmitBZero = flag; } /** Trigger a single computation of the Kurtosis values from the given input vector and the bvalues and returns the result as a KurtosisSnapshot object */ KurtosisSnapshot GetSnapshot( const itk::VariableLengthVector< TInputPixelType > &input, vnl_vector bvalues, KurtosisFitConfiguration kf_conf); /** Trigger a single computation of the kurtosis values, first the bvalues vector is computed internally but then also stored into the returend snapshot */ KurtosisSnapshot GetSnapshot( const itk::VariableLengthVector< TInputPixelType > &input, GradientDirectionContainerType::ConstPointer, float bvalue, KurtosisFitConfiguration kf_conf); /** * Returns the value of the current data presented to the filter. If a mask is set, the voxels are first averaged before passed to the fitting procedure */ KurtosisSnapshot GetCurrentSnapshot(bool omit_bzero); /** Set the reference bvalue of the input DW image */ void SetReferenceBValue( double bvalue ) { this->m_ReferenceBValue = bvalue; } /** Set the gradient directions */ void SetGradientDirections( GradientDirectionContainerType::ConstPointer gradients ); /** Restrict map generation to an image region */ void SetMapOutputRegion( OutputImageRegionType region ) { m_MapOutputRegion = region; this->m_ApplyPriorSmoothing = true; } void SetImageMask( MaskImageType::Pointer mask ); /** Set smoothing sigma (default = 1.5 ), automatically enables smoothing prior to fitting */ void SetSmoothingSigma( double sigma ) { this->m_SmoothingSigma = sigma; this->m_ApplyPriorSmoothing = true; } /** Activate/Deactivate the gaussian smoothing applied to the input prior to fitting ( default = off ) */ void SetUseSmoothingPriorToFitting( bool flag) { this->m_ApplyPriorSmoothing = flag; } /** Set boundaries enforced by penalty terms in the fitting procedure */ void SetBoundariesForKurtosis( double lower, double upper ) { m_UseKBounds = true; m_KurtosisBounds[0] = lower; m_KurtosisBounds[1] = upper; } /** Exclude measurements associated with b-values higher than max_bvalue from fitting */ void SetMaximalBValueUsedForFitting( double max_bvalue ) { m_MaxFitBValue = max_bvalue; } /** Select the method used in fitting of the data STRAIHT - fit the exponential signal equation S / S_0 = exp [ ... ] LOGARITHMIC - fit the logarithmic signal equation ln( S / S_0 ) = [] */ void SetFittingScale( FitScale scale ) { m_ScaleForFitting = scale; } protected: DiffusionKurtosisReconstructionImageFilter(); virtual ~DiffusionKurtosisReconstructionImageFilter() {} void GenerateOutputInformation() override; void AfterThreadedGenerateData() override; void BeforeThreadedGenerateData() override; - void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId) override; + void DynamicThreadedGenerateData(const OutputImageRegionType &outputRegionForThread) override; double m_ReferenceBValue; vnl_vector m_BValues; vnl_vector m_InitialPosition; bool m_OmitBZero; OutputImageRegionType m_MapOutputRegion; MaskImageType::Pointer m_MaskImage; typename InputImageType::Pointer m_ProcessedInputImage; bool m_ApplyPriorSmoothing; double m_SmoothingSigma; bool m_UseKBounds; vnl_vector_fixed m_KurtosisBounds; double m_MaxFitBValue; FitScale m_ScaleForFitting; private: }; } //end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkDiffusionKurtosisReconstructionImageFilter.cxx" #endif #endif // DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_H diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.cpp b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.cpp index addea49..bc36963 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.cpp +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.cpp @@ -1,1263 +1,1263 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkDiffusionMultiShellQballReconstructionImageFilter_cpp #define __itkDiffusionMultiShellQballReconstructionImageFilter_cpp #include #include #include #include namespace itk { template< class T, class TG, class TO, int L, int NODF> DiffusionMultiShellQballReconstructionImageFilter ::DiffusionMultiShellQballReconstructionImageFilter() : m_ReconstructionType(Mode_Standard1Shell), m_Interpolation_Flag(false), m_Interpolation_SHT1_inv(nullptr), m_Interpolation_SHT2_inv(nullptr), m_Interpolation_SHT3_inv(nullptr), m_TARGET_SH_shell1(nullptr), m_TARGET_SH_shell2(nullptr), m_TARGET_SH_shell3(nullptr), m_MaxDirections(0), m_CoeffReconstructionMatrix(nullptr), m_ODFSphericalHarmonicBasisMatrix(nullptr), m_GradientDirectionContainer(nullptr), m_NumberOfGradientDirections(0), m_NumberOfBaselineImages(0), m_Threshold(0), m_BZeroImage(nullptr), m_CoefficientImage(nullptr), m_BValue(1.0), m_Lambda(0.0), m_IsHemisphericalArrangementOfGradientDirections(false), m_IsArithmeticProgession(false) { // At least 1 inputs is necessary for a vector image. // For images added one at a time we need at least six this->SetNumberOfRequiredInputs( 1 ); - this->DynamicMultiThreadingOff(); + } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::SetGradientImage(const GradientDirectionContainerType *gradientDirection , const GradientImagesType *gradientImage , float bvalue) { m_BValue = bvalue; m_NumberOfBaselineImages = 0; this->m_GradientDirectionContainer = GradientDirectionContainerType::New(); for(GradientDirectionContainerType::ConstIterator it = gradientDirection->Begin(); it != gradientDirection->End(); it++) { this->m_GradientDirectionContainer->push_back(it.Value()); } if(m_BValueMap.size() == 0){ itkWarningMacro(<< "DiffusionMultiShellQballReconstructionImageFilter.cpp : no GradientIndexMapAvalible"); GradientDirectionContainerType::ConstIterator gdcit; for( gdcit = m_GradientDirectionContainer->Begin(); gdcit != m_GradientDirectionContainer->End(); ++gdcit) { double bValueKey = int(((m_BValue * gdcit.Value().two_norm() * gdcit.Value().two_norm())+7.5)/10)*10; MITK_INFO << bValueKey; m_BValueMap[bValueKey].push_back(gdcit.Index()); } } if(m_BValueMap.find(0) == m_BValueMap.end()) { itkExceptionMacro(<< "DiffusionMultiShellQballReconstructionImageFilter.cpp : GradientIndxMap with no b-Zero indecies found: check input BValueMap"); } m_NumberOfBaselineImages = m_BValueMap[0].size(); m_NumberOfGradientDirections = gradientDirection->Size() - m_NumberOfBaselineImages; // ensure that the gradient image we received has as many components as // the number of gradient directions if( gradientImage->GetVectorLength() != m_NumberOfBaselineImages + m_NumberOfGradientDirections ) { itkExceptionMacro( << m_NumberOfGradientDirections << " gradients + " << m_NumberOfBaselineImages << "baselines = " << m_NumberOfGradientDirections + m_NumberOfBaselineImages << " directions specified but image has " << gradientImage->GetVectorLength() << " components."); } ProcessObject::SetNthInput( 0, const_cast< GradientImagesType* >(gradientImage) ); std::string gradientImageClassName(ProcessObject::GetInput(0)->GetNameOfClass()); if ( strcmp(gradientImageClassName.c_str(),"VectorImage") != 0 ) itkExceptionMacro( << "There is only one Gradient image. I expect that to be a VectorImage. But its of type: " << gradientImageClassName ); m_BZeroImage = BZeroImageType::New(); typename GradientImagesType::Pointer img = static_cast< GradientImagesType * >( ProcessObject::GetInput(0) ); m_BZeroImage->SetSpacing( img->GetSpacing() ); // Set the image spacing m_BZeroImage->SetOrigin( img->GetOrigin() ); // Set the image origin m_BZeroImage->SetDirection( img->GetDirection() ); // Set the image direction m_BZeroImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion()); m_BZeroImage->SetBufferedRegion( img->GetLargestPossibleRegion() ); m_BZeroImage->Allocate(); m_CoefficientImage = CoefficientImageType::New(); m_CoefficientImage->SetSpacing( img->GetSpacing() ); // Set the image spacing m_CoefficientImage->SetOrigin( img->GetOrigin() ); // Set the image origin m_CoefficientImage->SetDirection( img->GetDirection() ); // Set the image direction m_CoefficientImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion()); m_CoefficientImage->SetBufferedRegion( img->GetLargestPossibleRegion() ); m_CoefficientImage->Allocate(); } template void DiffusionMultiShellQballReconstructionImageFilter ::Normalize( OdfPixelType & out) { for(int i=0; i void DiffusionMultiShellQballReconstructionImageFilter ::Projection1(vnl_vector & vec, double delta) { if (delta==0){ //Clip attenuation values. If att<0 => att=0, if att>1 => att=1 for (unsigned int i=0; i=0 && vec[i]<=1)*vec[i]+(vec[i]>1); } else{ //Use function from Aganj et al, MRM, 2010 for (unsigned int i=0; i< vec.size(); i++) vec[i]=CalculateThreashold(vec[i], delta); } } template double DiffusionMultiShellQballReconstructionImageFilter ::CalculateThreashold(const double value, const double delta) { return (value<0)*(0.5*delta) + (value>=0 && value=delta && value<1-delta)*value+(value>=1-delta && value<1)*(1-0.5*delta-0.5*((1-value)*(1-value))/delta) + (value>=1)*(1-0.5*delta); } template void DiffusionMultiShellQballReconstructionImageFilter ::Projection2( vnl_vector & E1,vnl_vector & E2, vnl_vector & E3, double delta ) { const double sF = sqrt(5.0); vnl_vector vOnes(m_MaxDirections); vOnes.fill(1.0); vnl_matrix T0(m_MaxDirections, 3); vnl_matrix C(m_MaxDirections, 7); vnl_matrix A(m_MaxDirections, 7); vnl_matrix B(m_MaxDirections, 7); vnl_vector s0(m_MaxDirections); vnl_vector a0(m_MaxDirections); vnl_vector b0(m_MaxDirections); vnl_vector ta(m_MaxDirections); vnl_vector tb(m_MaxDirections); vnl_vector e(m_MaxDirections); vnl_vector m(m_MaxDirections); vnl_vector a(m_MaxDirections); vnl_vector b(m_MaxDirections); // logarithmierung aller werte in E for(unsigned int i = 0 ; i < m_MaxDirections; i++) { T0(i,0) = -log(E1(i)); T0(i,1) = -log(E2(i)); T0(i,2) = -log(E3(i)); } //T0 = -T0.apply(std::log); // Summeiere Zeilenweise über alle Shells sum = E1+E2+E3 for(unsigned int i = 0 ; i < m_MaxDirections; i++) { s0[i] = T0(i,0) + T0(i,1) + T0(i,2); } for(unsigned int i = 0; i < m_MaxDirections; i ++) { // Alle Signal-Werte auf der Ersten shell E(N,0) normiert auf s0 a0[i] = T0(i,0) / s0[i]; // Alle Signal-Werte auf der Zweiten shell E(N,1) normiert auf s0 b0[i] = T0(i,1) / s0[i]; } ta = a0 * 3.0; tb = b0 * 3.0; e = tb - (ta * 2.0); m = (tb * 2.0 ) + ta; for(unsigned int i = 0; i =1-3*(sF+2)*delta); C(i,2) = (m[i] > 3-3*sF*delta) && (-1+3*(2*sF+5)*delta= 3-3*sF*delta && e[i] >= -3 *sF * delta); C(i,4) = (2.5 + 1.5*(5+sF)*delta < m[i] && m[i] < 3-3*sF*delta && e[i] > -3*sF*delta); C(i,5) = (ta[i] <= 0.5+1.5 *(sF+1)*delta && m[i] <= 2.5 + 1.5 *(5+sF) * delta); C(i,6) = !((bool) C(i,0) ||(bool) C(i,1) ||(bool) C(i,2) ||(bool) C(i,3) ||(bool) C(i,4) ||(bool) C(i,5) ); // ~ANY(C(i,[0-5] ),2) A(i,0)=(bool)C(i,0) * a0(i); A(i,1)=(bool)C(i,1) * (1.0/3.0-(sF+2)*delta); A(i,2)=(bool)C(i,2) * (0.2+0.8*a0(i)-0.4*b0(i)-delta/sF); A(i,3)=(bool)C(i,3) * (0.2+delta/sF); A(i,4)=(bool)C(i,4) * (0.2*a0(i)+0.4*b0(i)+2*delta/sF); A(i,5)=(bool)C(i,5) * (1.0/6.0+0.5*(sF+1)*delta); A(i,6)=(bool)C(i,6) * a0(i); B(i,0)=(bool)C(i,0) * (1.0/3.0+delta); B(i,1)=(bool)C(i,1) * (1.0/3.0+delta); B(i,2)=(bool)C(i,2) * (0.4-0.4*a0(i)+0.2*b0(i)-2*delta/sF); B(i,3)=(bool)C(i,3) * (0.4-3*delta/sF); B(i,4)=(bool)C(i,4) * (0.4*a0(i)+0.8*b0(i)-delta/sF); B(i,5)=(bool)C(i,5) * (1.0/3.0+delta); B(i,6)=(bool)C(i,6) * b0(i); } for(unsigned int i = 0 ; i < m_MaxDirections; i++) { double sumA = 0; double sumB = 0; for(int j = 0 ; j < 7; j++) { sumA += A(i,j); sumB += B(i,j); } a[i] = sumA; b[i] = sumB; } for(unsigned int i = 0; i < m_MaxDirections; i++) { E1(i) = exp(-(a[i]*s0[i])); E2(i) = exp(-(b[i]*s0[i])); E3(i) = exp(-((1-a[i]-b[i])*s0[i])); } } template void DiffusionMultiShellQballReconstructionImageFilter ::Projection3( vnl_vector & A, vnl_vector & a, vnl_vector & b, double delta0) { const double s6 = sqrt(6.0); const double s15 = s6/2.0; vnl_vector delta(a.size()); delta.fill(delta0); vnl_matrix AM(a.size(), 15); vnl_matrix aM(a.size(), 15); vnl_matrix bM(a.size(), 15); vnl_matrix B(a.size(), 15); AM.set_column(0, A); AM.set_column(1, A); AM.set_column(2, A); AM.set_column(3, delta); AM.set_column(4, (A+a-b - (delta*s6))/3.0); AM.set_column(5, delta); AM.set_column(6, delta); AM.set_column(7, delta); AM.set_column(8, A); AM.set_column(9, 0.2*(a*2+A-2*(s6+1)*delta)); AM.set_column(10,0.2*(b*(-2)+A+2-2*(s6+1)*delta)); AM.set_column(11, delta); AM.set_column(12, delta); AM.set_column(13, delta); AM.set_column(14, 0.5-(1+s15)*delta); aM.set_column(0, a); aM.set_column(1, a); aM.set_column(2, -delta + 1); aM.set_column(3, a); aM.set_column(4, (A*2+a*5+b+s6*delta)/6.0); aM.set_column(5, a); aM.set_column(6, -delta + 1); aM.set_column(7, 0.5*(a+b)+(1+s15)*delta); aM.set_column(8, -delta + 1); aM.set_column(9, 0.2*(a*4+A*2+(s6+1)*delta)); aM.set_column(10, -delta + 1); aM.set_column(11, (s6+3)*delta); aM.set_column(12, -delta + 1); aM.set_column(13, -delta + 1); aM.set_column(14, -delta + 1); bM.set_column(0, b); bM.set_column(1, delta); bM.set_column(2, b); bM.set_column(3, b); bM.set_column(4, (A*(-2)+a+b*5-s6*delta)/6.0); bM.set_column(5, delta); bM.set_column(6, b); bM.set_column(7, 0.5*(a+b)-(1+s15)*delta); bM.set_column(8, delta); bM.set_column(9, delta); bM.set_column(10, 0.2*(b*4-A*2+1-(s6+1)*delta)); bM.set_column(11, delta); bM.set_column(12, delta); bM.set_column(13, -delta*(s6+3) + 1); bM.set_column(14, delta); delta0 *= 0.99; vnl_matrix R2(a.size(), 15); std::vector I(a.size()); for (unsigned int i=0; idelta0 && aM(i,j)<1-delta0) R2(i,j) = (AM(i,j)-A(i))*(AM(i,j)-A(i))+ (aM(i,j)-a(i))*(aM(i,j)-a(i))+(bM(i,j)-b(i))*(bM(i,j)-b(i)); else R2(i,j) = 1e20; } unsigned int index = 0; double minvalue = 999; for(int j = 0 ; j < 15 ; j++) { if(R2(i,j) < minvalue){ minvalue = R2(i,j); index = j; } } I[i] = index; } for (unsigned int i=0; i < A.size(); i++){ A(i) = AM(i,(int)I[i]); a(i) = aM(i,(int)I[i]); b(i) = bM(i,(int)I[i]); } } template void DiffusionMultiShellQballReconstructionImageFilter ::S_S0Normalization( vnl_vector & vec, double S0 ) { for(unsigned int i = 0; i < vec.size(); i++) { if (S0==0) S0 = 0.01; vec[i] /= S0; } } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::DoubleLogarithm(vnl_vector & vec) { for(unsigned int i = 0; i < vec.size(); i++) { vec[i] = log(-log(vec[i])); } } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::AfterThreadedGenerateData() { MITK_INFO << "Finished reconstruction"; } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::BeforeThreadedGenerateData() { m_ReconstructionType = Mode_Standard1Shell; if(m_BValueMap.size() == 4 ){ BValueMapIteraotr it = m_BValueMap.begin(); it++; // skip b0 entry const unsigned int bValue_shell1 = it->first; const unsigned int size_shell1 = it->second.size(); IndiciesVector shell1 = it->second; it++; const unsigned int bValue_shell2 = it->first; const unsigned int size_shell2 = it->second.size(); IndiciesVector shell2 = it->second; it++; const unsigned int bValue_shell3 = it->first; const unsigned int size_shell3 = it->second.size(); IndiciesVector shell3 = it->second; // arithmetic progrssion if(bValue_shell2 - bValue_shell1 == bValue_shell1 && bValue_shell3 - bValue_shell2 == bValue_shell1 ) { // check if Interpolation is needed // if shells with different numbers of directions exist m_Interpolation_Flag = false; if(size_shell1 != size_shell2 || size_shell2 != size_shell3 || size_shell1 != size_shell3) { m_Interpolation_Flag = true; MITK_INFO << "Shell interpolation: shells with different numbers of directions"; } else { // else if each shell holds same numbers of directions, but the gradient direction differ more than one 1 degree m_Interpolation_Flag = CheckForDifferingShellDirections(); if(m_Interpolation_Flag) MITK_INFO << "Shell interpolation: gradient direction differ more than one 1 degree"; } m_ReconstructionType = Mode_Analytical3Shells; if(m_Interpolation_Flag) { unsigned int interp_SHOrder_shell1 = 12; while( ((interp_SHOrder_shell1+1)*(interp_SHOrder_shell1+2)/2) > size_shell1 && interp_SHOrder_shell1 > L ) interp_SHOrder_shell1 -= 2 ; const int number_coeffs_shell1 = (int)(interp_SHOrder_shell1*interp_SHOrder_shell1 + interp_SHOrder_shell1 + 2.0)/2.0 + interp_SHOrder_shell1; unsigned int interp_SHOrder_shell2 = 12; while( ((interp_SHOrder_shell2+1)*(interp_SHOrder_shell2+2)/2) > size_shell2 && interp_SHOrder_shell2 > L ) interp_SHOrder_shell2 -= 2 ; const int number_coeffs_shell2 = (int)(interp_SHOrder_shell2*interp_SHOrder_shell2 + interp_SHOrder_shell2 + 2.0)/2.0 + interp_SHOrder_shell2; unsigned int interp_SHOrder_shell3 = 12; while( ((interp_SHOrder_shell3+1)*(interp_SHOrder_shell3+2)/2) > size_shell3 && interp_SHOrder_shell3 > L ) interp_SHOrder_shell3 -= 2 ; const int number_coeffs_shell3 = (int)(interp_SHOrder_shell3*interp_SHOrder_shell3 + interp_SHOrder_shell3 + 2.0)/2.0 + interp_SHOrder_shell3; // Create direction container for all directions (no duplicates, different directions from all shells) IndiciesVector all_directions_container = GetAllDirections(); m_MaxDirections = all_directions_container.size(); // create target SH-Basis // initialize empty target matrix and set the wanted directions vnl_matrix * Q = new vnl_matrix(3, m_MaxDirections); ComputeSphericalFromCartesian(Q, all_directions_container); // initialize a SH Basis, neede to interpolate from oldDirs -> newDirs m_TARGET_SH_shell1 = new vnl_matrix(m_MaxDirections, number_coeffs_shell1); ComputeSphericalHarmonicsBasis(Q, m_TARGET_SH_shell1, interp_SHOrder_shell1); delete Q; Q = new vnl_matrix(3, m_MaxDirections); ComputeSphericalFromCartesian(Q, all_directions_container); m_TARGET_SH_shell2 = new vnl_matrix(m_MaxDirections, number_coeffs_shell2); ComputeSphericalHarmonicsBasis(Q, m_TARGET_SH_shell2, interp_SHOrder_shell2); delete Q; Q = new vnl_matrix(3, m_MaxDirections); ComputeSphericalFromCartesian(Q, all_directions_container); m_TARGET_SH_shell3 = new vnl_matrix(m_MaxDirections, number_coeffs_shell3); ComputeSphericalHarmonicsBasis(Q, m_TARGET_SH_shell3, interp_SHOrder_shell3); delete Q; // end creat target SH-Basis // create measured-SHBasis // Shell 1 vnl_matrix * tempSHBasis; vnl_matrix_inverse * temp; // initialize empty matrix and set the measured directions of shell1 Q = new vnl_matrix(3, shell1.size()); ComputeSphericalFromCartesian(Q, shell1); // initialize a SH Basis, need to get the coeffs from measuredShell tempSHBasis = new vnl_matrix(shell1.size(), number_coeffs_shell1); ComputeSphericalHarmonicsBasis(Q, tempSHBasis, interp_SHOrder_shell1); // inversion of the SH=Basis // c_s1 = B^-1 * shell1 // interp_Values = targetSHBasis * c_s1 // Values = m_TARGET_SH_shell1 * Interpolation_SHT1_inv * DataShell1; temp = new vnl_matrix_inverse((*tempSHBasis)); m_Interpolation_SHT1_inv = new vnl_matrix(temp->inverse()); delete Q; delete temp; delete tempSHBasis; // Shell 2 Q = new vnl_matrix(3, shell2.size()); ComputeSphericalFromCartesian(Q, shell2); tempSHBasis = new vnl_matrix(shell2.size(), number_coeffs_shell2); ComputeSphericalHarmonicsBasis(Q, tempSHBasis, interp_SHOrder_shell2); temp = new vnl_matrix_inverse((*tempSHBasis)); m_Interpolation_SHT2_inv = new vnl_matrix(temp->inverse()); delete Q; delete temp; delete tempSHBasis; // Shell 3 Q = new vnl_matrix(3, shell3.size()); ComputeSphericalFromCartesian(Q, shell3); tempSHBasis = new vnl_matrix(shell3.size(), number_coeffs_shell3); ComputeSphericalHarmonicsBasis(Q, tempSHBasis, interp_SHOrder_shell3); temp = new vnl_matrix_inverse((*tempSHBasis)); m_Interpolation_SHT3_inv = new vnl_matrix(temp->inverse()); delete Q; delete temp; delete tempSHBasis; ComputeReconstructionMatrix(all_directions_container); MITK_INFO << "Reconstruction information: Multishell Reconstruction filter - Interpolation"; MITK_INFO << "Shell 1"; MITK_INFO << " SHOrder: " << interp_SHOrder_shell1; MITK_INFO << " Number of Coeffs: " << number_coeffs_shell1; MITK_INFO << " Number of Gradientdirections: " << size_shell1; MITK_INFO << "Shell 2"; MITK_INFO << " SHOrder: " << interp_SHOrder_shell2; MITK_INFO << " Number of Coeffs: " << number_coeffs_shell2; MITK_INFO << " Number of Gradientdirections: " << size_shell2; MITK_INFO << "Shell 3"; MITK_INFO << " SHOrder: " << interp_SHOrder_shell3; MITK_INFO << " Number of Coeffs: " << number_coeffs_shell3; MITK_INFO << " Number of Gradientdirections: " << size_shell3; MITK_INFO << "Overall"; MITK_INFO << " SHOrder: " << L; MITK_INFO << " Number of Coeffs: " << (L+1)*(L+2)*0.5; MITK_INFO << " Number of Gradientdirections: " << m_MaxDirections; return; }else { ComputeReconstructionMatrix(shell1); } } } if(m_BValueMap.size() > 2 && m_ReconstructionType != Mode_Analytical3Shells) { m_ReconstructionType = Mode_NumericalNShells; } if(m_BValueMap.size() == 2){ BValueMapIteraotr it = m_BValueMap.begin(); it++; // skip b0 entry IndiciesVector shell = it->second; ComputeReconstructionMatrix(shell); } } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter -::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType /*NumberOfThreads*/) +::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread /*NumberOfThreads*/) { itk::TimeProbe clock; clock.Start(); switch(m_ReconstructionType) { case Mode_Standard1Shell: StandardOneShellReconstruction(outputRegionForThread); break; case Mode_Analytical3Shells: AnalyticalThreeShellReconstruction(outputRegionForThread); break; case Mode_NumericalNShells: break; } clock.Stop(); } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::StandardOneShellReconstruction(const OutputImageRegionType& outputRegionForThread) { // Get output image pointer typename OdfImageType::Pointer outputImage = static_cast< OdfImageType * >(ProcessObject::GetPrimaryOutput()); // Get input gradient image pointer typename GradientImagesType::Pointer gradientImagePointer = static_cast< GradientImagesType * >( ProcessObject::GetInput(0) ); // ImageRegionIterator for the output image ImageRegionIterator< OdfImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); // ImageRegionIterator for the BZero (output) image ImageRegionIterator< BZeroImageType > bzeroIterator(m_BZeroImage, outputRegionForThread); bzeroIterator.GoToBegin(); // Const ImageRegionIterator for input gradient image typedef ImageRegionConstIterator< GradientImagesType > GradientIteratorType; GradientIteratorType git(gradientImagePointer, outputRegionForThread ); git.GoToBegin(); BValueMapIteraotr it = m_BValueMap.begin(); it++; // skip b0 entry IndiciesVector SignalIndicies = it->second; IndiciesVector BZeroIndicies = m_BValueMap[0]; unsigned int NumbersOfGradientIndicies = SignalIndicies.size(); typedef typename GradientImagesType::PixelType GradientVectorType; // iterate overall voxels of the gradient image region while( ! git.IsAtEnd() ) { GradientVectorType b = git.Get(); // ODF Vector OdfPixelType odf(0.0); double b0average = 0; const unsigned int b0size = BZeroIndicies.size(); for(unsigned int i = 0; i < b0size ; ++i) { b0average += b[BZeroIndicies[i]]; } b0average /= b0size; bzeroIterator.Set(b0average); ++bzeroIterator; // Create the Signal Vector vnl_vector SignalVector(NumbersOfGradientIndicies); if( (b0average != 0) && (b0average >= m_Threshold) ) { for( unsigned int i = 0; i< SignalIndicies.size(); i++ ) { SignalVector[i] = static_cast(b[SignalIndicies[i]]); } // apply threashold an generate ln(-ln(E)) signal // Replace SignalVector with PreNormalized SignalVector S_S0Normalization(SignalVector, b0average); Projection1(SignalVector); DoubleLogarithm(SignalVector); // approximate ODF coeffs vnl_vector coeffs = ( (*m_CoeffReconstructionMatrix) * SignalVector ); coeffs[0] = 1.0/(2.0*sqrt(itk::Math::pi)); odf = element_cast(( (*m_ODFSphericalHarmonicBasisMatrix) * coeffs )).data_block(); odf *= (itk::Math::pi*4/NODF); } // set ODF to ODF-Image oit.Set( odf ); ++oit; ++git; } } //#include "itkLevenbergMarquardtOptimizer.h" template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::NumericalNShellReconstruction(const OutputImageRegionType& /*outputRegionForThread*/) { /* itk::LevenbergMarquardtOptimizer::Pointer optimizer = itk::LevenbergMarquardtOptimizer::New(); optimizer->SetUseCostFunctionGradient(false); // Scale the translation components of the Transform in the Optimizer itk::LevenbergMarquardtOptimizer::ScalesType scales(transform->GetNumberOfParameters()); scales.Fill(0.01); unsigned long numberOfIterations = 80000; double gradientTolerance = 1e-10; // convergence criterion double valueTolerance = 1e-10; // convergence criterion double epsilonFunction = 1e-10; // convergence criterion optimizer->SetScales( scales ); optimizer->SetNumberOfIterations( numberOfIterations ); optimizer->SetValueTolerance( valueTolerance ); optimizer->SetGradientTolerance( gradientTolerance ); optimizer->SetEpsilonFunction( epsilonFunction );*/ } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::AnalyticalThreeShellReconstruction(const OutputImageRegionType& outputRegionForThread) { // Input Gradient Image and Output ODF Image typedef typename GradientImagesType::PixelType GradientVectorType; typename OdfImageType::Pointer outputImage = static_cast< OdfImageType * >(ProcessObject::GetPrimaryOutput()); typename GradientImagesType::Pointer gradientImagePointer = static_cast< GradientImagesType * >( ProcessObject::GetInput(0) ); // Define Image iterators ImageRegionIterator< OdfImageType > odfOutputImageIterator(outputImage, outputRegionForThread); ImageRegionConstIterator< GradientImagesType > gradientInputImageIterator(gradientImagePointer, outputRegionForThread ); ImageRegionIterator< BZeroImageType > bzeroIterator(m_BZeroImage, outputRegionForThread); ImageRegionIterator< CoefficientImageType > coefficientImageIterator(m_CoefficientImage, outputRegionForThread); // All iterators seht to Begin of the specific OutputRegion coefficientImageIterator.GoToBegin(); bzeroIterator.GoToBegin(); odfOutputImageIterator.GoToBegin(); gradientInputImageIterator.GoToBegin(); // Get Shell Indicies for all non-BZero Gradients // it MUST be a arithmetic progression eg.: 1000, 2000, 3000 BValueMapIteraotr it = m_BValueMap.begin(); it++; // it = b-value = 1000 IndiciesVector Shell1Indiecies = it->second; it++; // it = b-value = 2000 IndiciesVector Shell2Indiecies = it->second; it++; // it = b-value = 3000 IndiciesVector Shell3Indiecies = it->second; IndiciesVector BZeroIndicies = m_BValueMap[0]; if(!m_Interpolation_Flag) { m_MaxDirections = Shell1Indiecies.size(); }// else: m_MaxDirection is set in BeforeThreadedGenerateData // Nx3 Signal Matrix with E(0) = Shell 1, E(1) = Shell 2, E(2) = Shell 3 vnl_vector< double > E1(m_MaxDirections); vnl_vector< double > E2(m_MaxDirections); vnl_vector< double > E3(m_MaxDirections); vnl_vector AlphaValues(m_MaxDirections); vnl_vector BetaValues(m_MaxDirections); vnl_vector LAValues(m_MaxDirections); vnl_vector PValues(m_MaxDirections); vnl_vector DataShell1(Shell1Indiecies.size()); vnl_vector DataShell2(Shell2Indiecies.size()); vnl_vector DataShell3(Shell3Indiecies.size()); vnl_matrix tempInterpolationMatrixShell1,tempInterpolationMatrixShell2,tempInterpolationMatrixShell3; if(m_Interpolation_Flag) { tempInterpolationMatrixShell1 = (*m_TARGET_SH_shell1) * (*m_Interpolation_SHT1_inv); tempInterpolationMatrixShell2 = (*m_TARGET_SH_shell2) * (*m_Interpolation_SHT2_inv); tempInterpolationMatrixShell3 = (*m_TARGET_SH_shell3) * (*m_Interpolation_SHT3_inv); } OdfPixelType odf(0.0); typename CoefficientImageType::PixelType coeffPixel(0.0); double P2,A,B2,B,P,alpha,beta,lambda, ER1, ER2; // iterate overall voxels of the gradient image region while( ! gradientInputImageIterator.IsAtEnd() ) { odf = 0.0; coeffPixel = 0.0; GradientVectorType b = gradientInputImageIterator.Get(); // calculate for each shell the corresponding b0-averages double shell1b0Norm =0; double shell2b0Norm =0; double shell3b0Norm =0; double b0average = 0; const unsigned int b0size = BZeroIndicies.size(); if(b0size == 1) { shell1b0Norm = b[BZeroIndicies[0]]; shell2b0Norm = b[BZeroIndicies[0]]; shell3b0Norm = b[BZeroIndicies[0]]; b0average = b[BZeroIndicies[0]]; }else if(b0size % 3 ==0) { for(unsigned int i = 0; i < b0size ; ++i) { if(i < b0size / 3) shell1b0Norm += b[BZeroIndicies[i]]; if(i >= b0size / 3 && i < (b0size / 3)*2) shell2b0Norm += b[BZeroIndicies[i]]; if(i >= (b0size / 3) * 2) shell3b0Norm += b[BZeroIndicies[i]]; } shell1b0Norm /= (b0size/3); shell2b0Norm /= (b0size/3); shell3b0Norm /= (b0size/3); b0average = (shell1b0Norm + shell2b0Norm+ shell3b0Norm)/3; }else { for(unsigned int i = 0; i = m_Threshold) ) { // Get the Signal-Value for each Shell at each direction (specified in the ShellIndicies Vector .. this direction corresponse to this shell...) /*//fsl fix --------------------------------------------------- for(int i = 0 ; i < Shell1Indiecies.size(); i++) DataShell1[i] = static_cast(b[Shell1Indiecies[i]]); for(int i = 0 ; i < Shell2Indiecies.size(); i++) DataShell2[i] = static_cast(b[Shell2Indiecies[i]]); for(int i = 0 ; i < Shell3Indiecies.size(); i++) DataShell3[i] = static_cast(b[Shell2Indiecies[i]]); // Normalize the Signal: Si/S0 S_S0Normalization(DataShell1, shell1b0Norm); S_S0Normalization(DataShell2, shell2b0Norm); S_S0Normalization(DataShell3, shell2b0Norm); *///fsl fix -------------------------------------------ende-- ///correct version for(unsigned int i = 0 ; i < Shell1Indiecies.size(); i++) DataShell1[i] = static_cast(b[Shell1Indiecies[i]]); for(unsigned int i = 0 ; i < Shell2Indiecies.size(); i++) DataShell2[i] = static_cast(b[Shell2Indiecies[i]]); for(unsigned int i = 0 ; i < Shell3Indiecies.size(); i++) DataShell3[i] = static_cast(b[Shell3Indiecies[i]]); // Normalize the Signal: Si/S0 S_S0Normalization(DataShell1, shell1b0Norm); S_S0Normalization(DataShell2, shell2b0Norm); S_S0Normalization(DataShell3, shell3b0Norm); if(m_Interpolation_Flag) { E1 = tempInterpolationMatrixShell1 * DataShell1; E2 = tempInterpolationMatrixShell2 * DataShell2; E3 = tempInterpolationMatrixShell3 * DataShell3; }else{ E1 = (DataShell1); E2 = (DataShell2); E3 = (DataShell3); } //Implements Eq. [19] and Fig. 4. Projection1(E1); Projection1(E2); Projection1(E3); //inqualities [31]. Taking the lograithm of th first tree inqualities //convert the quadratic inqualities to linear ones. Projection2(E1,E2,E3); for( unsigned int i = 0; i< m_MaxDirections; i++ ) { double e1 = E1.get(i); double e2 = E2.get(i); double e3 = E3.get(i); P2 = e2-e1*e1; A = (e3 -e1*e2) / ( 2* P2); B2 = A * A -(e1 * e3 - e2 * e2) /P2; B = 0; if(B2 > 0) B = sqrt(B2); P = 0; if(P2 > 0) P = sqrt(P2); alpha = A + B; beta = A - B; PValues.put(i, P); AlphaValues.put(i, alpha); BetaValues.put(i, beta); } Projection3(PValues, AlphaValues, BetaValues); for(unsigned int i = 0 ; i < m_MaxDirections; i++) { const double fac = (PValues[i] * 2 ) / (AlphaValues[i] - BetaValues[i]); lambda = 0.5 + 0.5 * std::sqrt(1 - fac * fac);; ER1 = std::fabs(lambda * (AlphaValues[i] - BetaValues[i]) + (BetaValues[i] - E1.get(i) )) + std::fabs(lambda * (AlphaValues[i] * AlphaValues[i] - BetaValues[i] * BetaValues[i]) + (BetaValues[i] * BetaValues[i] - E2.get(i) )) + std::fabs(lambda * (AlphaValues[i] * AlphaValues[i] * AlphaValues[i] - BetaValues[i] * BetaValues[i] * BetaValues[i]) + (BetaValues[i] * BetaValues[i] * BetaValues[i] - E3.get(i) )); ER2 = std::fabs((1-lambda) * (AlphaValues[i] - BetaValues[i]) + (BetaValues[i] - E1.get(i) )) + std::fabs((1-lambda) * (AlphaValues[i] * AlphaValues[i] - BetaValues[i] * BetaValues[i]) + (BetaValues[i] * BetaValues[i] - E2.get(i) )) + std::fabs((1-lambda) * (AlphaValues[i] * AlphaValues[i] * AlphaValues[i] - BetaValues[i] * BetaValues[i] * BetaValues[i]) + (BetaValues[i] * BetaValues[i] * BetaValues[i] - E3.get(i))); if(ER1 < ER2) LAValues.put(i, lambda); else LAValues.put(i, 1-lambda); } DoubleLogarithm(AlphaValues); DoubleLogarithm(BetaValues); vnl_vector SignalVector(element_product((LAValues) , (AlphaValues)-(BetaValues)) + (BetaValues)); vnl_vector coeffs((*m_CoeffReconstructionMatrix) *SignalVector ); // the first coeff is a fix value coeffs[0] = 1.0/(2.0*sqrt(itk::Math::pi)); coeffPixel = element_cast(coeffs).data_block(); // Cast the Signal-Type from double to float for the ODF-Image odf = element_cast( (*m_ODFSphericalHarmonicBasisMatrix) * coeffs ).data_block(); odf *= ((itk::Math::pi*4)/NODF); } // set ODF to ODF-Image coefficientImageIterator.Set(coeffPixel); odfOutputImageIterator.Set( odf ); ++odfOutputImageIterator; ++coefficientImageIterator; ++gradientInputImageIterator; } } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter:: ComputeSphericalHarmonicsBasis(vnl_matrix * QBallReference, vnl_matrix *SHBasisOutput, int LOrder , vnl_matrix* LaplaciaBaltramiOutput, vnl_vector* SHOrderAssociation, vnl_matrix* SHEigenvalues) { for(unsigned int i=0; i< (*SHBasisOutput).rows(); i++) { for(int k = 0; k <= LOrder; k += 2) { for(int m =- k; m <= k; m++) { int j = ( k * k + k + 2 ) / 2 + m - 1; // Compute SHBasisFunctions if(QBallReference){ double phi = (*QBallReference)(0,i); double th = (*QBallReference)(1,i); (*SHBasisOutput)(i,j) = mitk::sh::Yj(m,k,th,phi); } // Laplacian Baltrami Order Association if(LaplaciaBaltramiOutput) (*LaplaciaBaltramiOutput)(j,j) = k*k*(k + 1)*(k+1); // SHEigenvalues with order Accosiation kj if(SHEigenvalues) (*SHEigenvalues)(j,j) = -k* (k+1); // Order Association if(SHOrderAssociation) (*SHOrderAssociation)[j] = k; } } } } template< class T, class TG, class TO, int L, int NOdfDirections> void DiffusionMultiShellQballReconstructionImageFilter ::ComputeReconstructionMatrix(IndiciesVector const & refVector) { typedef std::unique_ptr< vnl_matrix< double> > MatrixDoublePtr; typedef std::unique_ptr< vnl_vector< int > > VectorIntPtr; typedef std::unique_ptr< vnl_matrix_inverse< double > > InverseMatrixDoublePtr; int numberOfGradientDirections = refVector.size(); if( numberOfGradientDirections <= (((L+1)*(L+2))/2) || numberOfGradientDirections < 6 ) { itkExceptionMacro( << "At least (L+1)(L+2)/2 gradient directions for each shell are required; current : " << numberOfGradientDirections ); } CheckDuplicateDiffusionGradients(); const int LOrder = L; int NumberOfCoeffs = (int)(LOrder*LOrder + LOrder + 2.0)/2.0 + LOrder; MatrixDoublePtr SHBasisMatrix(new vnl_matrix(numberOfGradientDirections,NumberOfCoeffs)); SHBasisMatrix->fill(0.0); VectorIntPtr SHOrderAssociation(new vnl_vector(NumberOfCoeffs)); SHOrderAssociation->fill(0.0); MatrixDoublePtr LaplacianBaltrami(new vnl_matrix(NumberOfCoeffs,NumberOfCoeffs)); LaplacianBaltrami->fill(0.0); MatrixDoublePtr FRTMatrix(new vnl_matrix(NumberOfCoeffs,NumberOfCoeffs)); FRTMatrix->fill(0.0); MatrixDoublePtr SHEigenvalues(new vnl_matrix(NumberOfCoeffs,NumberOfCoeffs)); SHEigenvalues->fill(0.0); MatrixDoublePtr Q(new vnl_matrix(3, numberOfGradientDirections)); // Convert Cartesian to Spherical Coordinates refVector -> Q ComputeSphericalFromCartesian(Q.get(), refVector); // SHBasis-Matrix + LaplacianBaltrami-Matrix + SHOrderAssociationVector ComputeSphericalHarmonicsBasis(Q.get() ,SHBasisMatrix.get() , LOrder , LaplacianBaltrami.get(), SHOrderAssociation.get(), SHEigenvalues.get()); // Compute FunkRadon Transformation Matrix Associated to SHBasis Order lj for(int i=0; i(((SHBasisMatrix->transpose()) * (*SHBasisMatrix)) + (m_Lambda * (*LaplacianBaltrami)))); InverseMatrixDoublePtr pseudo_inv(new vnl_matrix_inverse((*temp))); MatrixDoublePtr inverse(new vnl_matrix(NumberOfCoeffs,NumberOfCoeffs)); (*inverse) = pseudo_inv->inverse(); const double factor = (1.0/(16.0*itk::Math::pi*itk::Math::pi)); MatrixDoublePtr SignalReonstructionMatrix (new vnl_matrix((*inverse) * (SHBasisMatrix->transpose()))); m_CoeffReconstructionMatrix = new vnl_matrix(( factor * ((*FRTMatrix) * ((*SHEigenvalues) * (*SignalReonstructionMatrix))) )); // SH Basis for ODF-reconstruction vnl_matrix_fixed* U = PointShell >::DistributePointShell(); for(int i=0; i( U->as_matrix() )); m_ODFSphericalHarmonicBasisMatrix = new vnl_matrix(NOdfDirections,NumberOfCoeffs); ComputeSphericalHarmonicsBasis(tempPtr.get(), m_ODFSphericalHarmonicBasisMatrix, LOrder); } template< class T, class TG, class TO, int L, int NOdfDirections> void DiffusionMultiShellQballReconstructionImageFilter ::ComputeSphericalFromCartesian(vnl_matrix * Q, IndiciesVector const & refShell) { for(unsigned int i = 0; i < refShell.size(); i++) { double x = m_GradientDirectionContainer->ElementAt(refShell[i]).normalize().get(0); double y = m_GradientDirectionContainer->ElementAt(refShell[i]).normalize().get(1); double z = m_GradientDirectionContainer->ElementAt(refShell[i]).normalize().get(2); double cart[3]; mitk::sh::Cart2Sph(x,y,z,cart); (*Q)(0,i) = cart[0]; (*Q)(1,i) = cart[1]; (*Q)(2,i) = cart[2]; } } template< class T, class TG, class TO, int L, int NODF> bool DiffusionMultiShellQballReconstructionImageFilter ::CheckDuplicateDiffusionGradients() { bool value = false; BValueMapIteraotr mapIterator = m_BValueMap.begin(); mapIterator++; while(mapIterator != m_BValueMap.end()) { std::vector::const_iterator it1 = mapIterator->second.begin(); std::vector::const_iterator it2 = mapIterator->second.begin(); for(; it1 != mapIterator->second.end(); ++it1) { for(; it2 != mapIterator->second.end(); ++it2) { if(m_GradientDirectionContainer->ElementAt(*it1) == m_GradientDirectionContainer->ElementAt(*it2) && it1 != it2) { itkWarningMacro( << "Some of the Diffusion Gradients equal each other. Corresponding image data should be averaged before calling this filter." ); value = true; } } } ++mapIterator; } return value; } template< class T, class TG, class TO, int L, int NODF> std::vector DiffusionMultiShellQballReconstructionImageFilter ::GetAllDirections() { IndiciesVector directioncontainer; BValueMapIteraotr mapIterator = m_BValueMap.begin(); mapIterator++; IndiciesVector shell1 = mapIterator->second; mapIterator++; IndiciesVector shell2 = mapIterator->second; mapIterator++; IndiciesVector shell3 = mapIterator->second; while(shell1.size()>0) { unsigned int wntIndex = shell1.back(); shell1.pop_back(); IndiciesVector::iterator containerIt = directioncontainer.begin(); bool directionExist = false; while(containerIt != directioncontainer.end()) { if (fabs(dot(m_GradientDirectionContainer->ElementAt(*containerIt), m_GradientDirectionContainer->ElementAt(wntIndex))) > 0.9998) { directionExist = true; break; } containerIt++; } if(!directionExist) { directioncontainer.push_back(wntIndex); } } while(shell2.size()>0) { unsigned int wntIndex = shell2.back(); shell2.pop_back(); IndiciesVector::iterator containerIt = directioncontainer.begin(); bool directionExist = false; while(containerIt != directioncontainer.end()) { if (fabs(dot(m_GradientDirectionContainer->ElementAt(*containerIt), m_GradientDirectionContainer->ElementAt(wntIndex))) > 0.9998) { directionExist = true; break; } containerIt++; } if(!directionExist) { directioncontainer.push_back(wntIndex); } } while(shell3.size()>0) { unsigned int wntIndex = shell3.back(); shell3.pop_back(); IndiciesVector::iterator containerIt = directioncontainer.begin(); bool directionExist = false; while(containerIt != directioncontainer.end()) { if (fabs(dot(m_GradientDirectionContainer->ElementAt(*containerIt), m_GradientDirectionContainer->ElementAt(wntIndex))) > 0.9998) { directionExist = true; break; } containerIt++; } if(!directionExist) { directioncontainer.push_back(wntIndex); } } return directioncontainer; } // corresponding directions between shells (e.g. dir1_shell1 vs dir1_shell2) differ more than 1 degree. template< class T, class TG, class TO, int L, int NODF> bool DiffusionMultiShellQballReconstructionImageFilter ::CheckForDifferingShellDirections() { bool interp_flag = false; BValueMapIteraotr mapIterator = m_BValueMap.begin(); mapIterator++; IndiciesVector shell1 = mapIterator->second; mapIterator++; IndiciesVector shell2 = mapIterator->second; mapIterator++; IndiciesVector shell3 = mapIterator->second; for (unsigned int i=0; i< shell1.size(); i++) if (fabs(dot(m_GradientDirectionContainer->ElementAt(shell1[i]), m_GradientDirectionContainer->ElementAt(shell2[i]))) <= 0.9998) {interp_flag=true; break;} for (unsigned int i=0; i< shell1.size(); i++) if (fabs(dot(m_GradientDirectionContainer->ElementAt(shell1[i]), m_GradientDirectionContainer->ElementAt(shell3[i]))) <= 0.9998) {interp_flag=true; break;} for (unsigned int i=0; i< shell1.size(); i++) if (fabs(dot(m_GradientDirectionContainer->ElementAt(shell2[i]), m_GradientDirectionContainer->ElementAt(shell3[i]))) <= 0.9998) {interp_flag=true; break;} return interp_flag; } template< class T, class TG, class TO, int L, int NODF> void DiffusionMultiShellQballReconstructionImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { std::locale C("C"); std::locale originalLocale = os.getloc(); os.imbue(C); Superclass::PrintSelf(os,indent); //os << indent << "OdfReconstructionMatrix: " << m_ReconstructionMatrix << std::endl; if ( m_GradientDirectionContainer ) { os << indent << "GradientDirectionContainer: " << m_GradientDirectionContainer << std::endl; } else { os << indent << "GradientDirectionContainer: (Gradient directions not set)" << std::endl; } os << indent << "NumberOfGradientDirections: " << m_NumberOfGradientDirections << std::endl; os << indent << "NumberOfBaselineImages: " << m_NumberOfBaselineImages << std::endl; os << indent << "Threshold for reference B0 image: " << m_Threshold << std::endl; os << indent << "BValue: " << m_BValue << std::endl; os.imbue( originalLocale ); } } #endif // __itkDiffusionMultiShellQballReconstructionImageFilter_cpp diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.h b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.h index 99341f1..0958599 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.h @@ -1,221 +1,221 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkDiffusionMultiShellQballReconstructionImageFilter_h_ #define __itkDiffusionMultiShellQballReconstructionImageFilter_h_ #include namespace itk{ /** \class DiffusionMultiShellQballReconstructionImageFilter I. Aganj, C. Lenglet, G. Sapiro, E. Yacoub, K. Ugurbil, and N. Harel, “Reconstruction of the orientation distribution function in single and multiple shell q-ball imaging within constant solid angle,” Magnetic Resonance in Medicine, vol. 64, no. 2, pp. 554–566, 2010. */ template< class TReferenceImagePixelType, class TGradientImagePixelType, class TOdfPixelType, int NOrderL, int NrOdfDirections> class DiffusionMultiShellQballReconstructionImageFilter : public ImageToImageFilter< Image< TReferenceImagePixelType, 3 >, Image< Vector< TOdfPixelType, NrOdfDirections >, 3 > > { public: typedef DiffusionMultiShellQballReconstructionImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< TReferenceImagePixelType, 3>, Image< Vector< TOdfPixelType, NrOdfDirections >, 3 > > Superclass; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef TReferenceImagePixelType ReferencePixelType; /** GradientImageType * (e.g. type short)*/ typedef TGradientImagePixelType GradientPixelType; /** GradientImageType * 3D VectorImage containing GradientPixelTypes */ typedef VectorImage< GradientPixelType, 3 > GradientImagesType; /** ODF PixelType */ typedef Vector< TOdfPixelType, NrOdfDirections > OdfPixelType; /** ODF ImageType */ typedef Image< OdfPixelType, 3 > OdfImageType; /** BzeroImageType */ typedef Image< TOdfPixelType, 3 > BZeroImageType; /** Container to hold gradient directions of the 'n' DW measurements */ typedef VectorContainer< unsigned int, vnl_vector_fixed< double, 3 > > GradientDirectionContainerType; typedef Image< Vector< TOdfPixelType, (NOrderL*NOrderL + NOrderL + 2)/2 + NOrderL >, 3 > CoefficientImageType; typedef std::map > BValueMap; typedef std::map >::iterator BValueMapIteraotr; typedef std::vector IndiciesVector; // --------------------------------------------------------------------------------------------// /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DiffusionMultiShellQballReconstructionImageFilter, ImageToImageFilter) /** Get reference image */ virtual typename Superclass::InputImageType * GetInputImage() { return ( static_cast< typename Superclass::InputImageType *>(this->ProcessObject::GetInput(0)) ); } /** Replaces the Input method. * Var vols = mitk::Image * ----------------------------------------------------- * GradientDirectionContainerType-Input gradientDirectionContainer (e.g. GradientDirectionsContainerProperty) * GradientImagesType-Input gradientImage (e.g. itkVectorImage) * float-Input bvalue (e.g. ReferenceBValueProperty) */ void SetGradientImage( const GradientDirectionContainerType * gradientDirectionContainer, const GradientImagesType *gradientImage , float bvalue);//, std::vector listOfUserSelctedBValues ); /** Set a BValue Map (key = bvalue, value = indicies splittet for each shell) * If the input image containes more than three q-shells * (e.g. b-Values of 0, 1000, 2000, 3000, 4000, ...). * For the Analytical-Reconstruction it is needed to set a * BValue Map containing three shells in an arithmetic series * (e.g. 0, 1000, 2000, 3000). */ inline void SetBValueMap(BValueMap map){this->m_BValueMap = map;} /** Threshold on the reference image data. The output ODF will be a null * pdf for pixels in the reference image that have a value less than this * threshold. */ itkSetMacro( Threshold, ReferencePixelType ) itkGetMacro( Threshold, ReferencePixelType ) itkGetMacro( CoefficientImage, typename CoefficientImageType::Pointer ) /** Return non-diffusion weighted images */ itkGetMacro( BZeroImage, typename BZeroImageType::Pointer) /** Factor for Laplacian-Baltrami smoothing of the SH-coefficients*/ itkSetMacro( Lambda, double ) itkGetMacro( Lambda, double ) protected: DiffusionMultiShellQballReconstructionImageFilter(); ~DiffusionMultiShellQballReconstructionImageFilter() { } void PrintSelf(std::ostream& os, Indent indent) const; void BeforeThreadedGenerateData(); void AfterThreadedGenerateData(); - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType NumberOfThreads ); + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread); private: enum ReconstructionType { Mode_Analytical3Shells, Mode_NumericalNShells, Mode_Standard1Shell }; ReconstructionType m_ReconstructionType; // Interpolation bool m_Interpolation_Flag; vnl_matrix< double > * m_Interpolation_SHT1_inv; vnl_matrix< double > * m_Interpolation_SHT2_inv; vnl_matrix< double > * m_Interpolation_SHT3_inv; vnl_matrix< double > * m_TARGET_SH_shell1; vnl_matrix< double > * m_TARGET_SH_shell2; vnl_matrix< double > * m_TARGET_SH_shell3; unsigned int m_MaxDirections; vnl_matrix< double > * m_CoeffReconstructionMatrix; vnl_matrix< double > * m_ODFSphericalHarmonicBasisMatrix; /** container to hold gradient directions */ GradientDirectionContainerType::Pointer m_GradientDirectionContainer; /** Number of gradient measurements */ unsigned int m_NumberOfGradientDirections; /** Number of baseline images */ unsigned int m_NumberOfBaselineImages; /** Threshold on the reference image data */ ReferencePixelType m_Threshold; typename BZeroImageType::Pointer m_BZeroImage; typename CoefficientImageType::Pointer m_CoefficientImage; float m_BValue; BValueMap m_BValueMap; double m_Lambda; bool m_IsHemisphericalArrangementOfGradientDirections; bool m_IsArithmeticProgession; void ComputeReconstructionMatrix(IndiciesVector const & refVector); void ComputeODFSHBasis(); bool CheckDuplicateDiffusionGradients(); bool CheckForDifferingShellDirections(); IndiciesVector GetAllDirections(); void ComputeSphericalHarmonicsBasis(vnl_matrix* QBallReference, vnl_matrix* SHBasisOutput, int Lorder , vnl_matrix* LaplaciaBaltramiOutput =0 , vnl_vector* SHOrderAssociation =0 , vnl_matrix * SHEigenvalues =0); void Normalize(OdfPixelType & odf ); void S_S0Normalization( vnl_vector & vec, double b0 = 0 ); void DoubleLogarithm(vnl_vector & vec); double CalculateThreashold(const double value, const double delta); void Projection1(vnl_vector & vec, double delta = 0.01); void Projection2( vnl_vector & E1, vnl_vector & E2, vnl_vector & E3, double delta = 0.01); void Projection3( vnl_vector & A, vnl_vector & alpha, vnl_vector & beta, double delta = 0.01); void StandardOneShellReconstruction(const OutputImageRegionType& outputRegionForThread); void AnalyticalThreeShellReconstruction(const OutputImageRegionType& outputRegionForThread); void NumericalNShellReconstruction(const OutputImageRegionType& outputRegionForThread); void GenerateAveragedBZeroImage(const OutputImageRegionType& outputRegionForThread); void ComputeSphericalFromCartesian(vnl_matrix * Q, const IndiciesVector & refShell); //------------------------- VNL-function ------------------------------------ template vnl_vector< WntValue> element_cast (vnl_vector< CurrentValue> const& v1) { vnl_vector result(v1.size()); for(unsigned int i = 0 ; i < v1.size(); i++) result[i] = static_cast< WntValue>(v1[i]); return result; } template double dot (vnl_vector_fixed< type ,3> const& v1, vnl_vector_fixed< type ,3 > const& v2 ) { double result = (v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]) / (v1.two_norm() * v2.two_norm()); return result ; } }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkDiffusionMultiShellQballReconstructionImageFilter.cpp" #endif #endif //__itkDiffusionMultiShellQballReconstructionImageFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionQballReconstructionImageFilter.h b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionQballReconstructionImageFilter.h index 37612a5..72dda06 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionQballReconstructionImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionQballReconstructionImageFilter.h @@ -1,341 +1,341 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkDiffusionQballReconstructionImageFilter_h_ #define __itkDiffusionQballReconstructionImageFilter_h_ #include "itkImageToImageFilter.h" //#include "vnl/vnl_matrix.h" #include "vnl/vnl_vector_fixed.h" #include "vnl/vnl_matrix.h" #include "vnl/algo/vnl_svd.h" #include "itkVectorContainer.h" #include "itkVectorImage.h" namespace itk{ /** \class DiffusionQballReconstructionImageFilter * \brief This class takes as input one or more reference images (acquired in the * absence of diffusion sensitizing gradients) and 'n' diffusion * weighted images and their gradient directions and computes an image of * orientation distribution functions (ODFs). * * \par Inputs and Usage * There are two ways to use this class. When you have one reference image and \c n * gradient images, you would use the class as * \code * filter->SetReferenceImage( image0 ); * filter->AddGradientImage( direction1, image1 ); * filter->AddGradientImage( direction2, image2 ); * ... * \endcode * * \par * When you have the 'n' gradient and one or more reference images in a single * multi-component image (VectorImage), you can specify the images simply as * \code * filter->SetGradientImage( directionsContainer, vectorImage ); * \endcode * Note that this method is used to specify both the reference and gradient images. * This is convenient when the DWI images are read in using the * NRRD * format. Like the Nrrd format, the reference images are those components of the * vectorImage whose gradient direction is (0,0,0). If more than one reference image * is present, they are averaged prior to the reconstruction. * * \par Outputs * The output image is an image of vectors that must be understood as ODFs: * \code * Image< Vector< TPixelType, OdfNrDirections >, 3 > * \endcode * * \par Parameters * \li Threshold - Threshold on the reference image data. The output ODF will * be a null pdf for pixels in the reference image that have a value less * than this. * \li BValue - See the documentation of SetBValue(). * \li At least 6 gradient images must be specified for the filter to be able * to run. If the input gradient directions g_i are majorly sampled on one half * of the sqhere, then each input image I_i will be duplicated and assign -g_i * in order to guarantee stability of the Tuch-Algorithm. * \li OdfDirections - directions of resulting orientation distribution function * \li EquatorNrSamplingPoints - number of sampling points on equator when * performing Funk Radeon Transform (FRT) * \li BasisFunctionCenters - the centers of the basis functions are used for * the sRBF (spherical radial basis functions interpolation). If not set, they * will be defaulted to equal m_EquatorNrSamplingPoints * * \par Template parameters * The class is templated over * \li the pixel type of the reference and gradient images * (expected to be scalar data types) * \li the internal representation of the ODF pixels (double, float etc). * \li the number of OdfDirections * \li the number of basis function centers for the sRBF * * \par References: * \li[1] * Tuch DS, * "Q-ball imaging", Magn Reson Med. 2004 Dec;52(6):1358-72. * */ template< class TReferenceImagePixelType, class TGradientImagePixelType, class TOdfPixelType, int NrOdfDirections, int NrBasisFunctionCenters = NrOdfDirections> class DiffusionQballReconstructionImageFilter : public ImageToImageFilter< Image< TReferenceImagePixelType, 3 >, Image< Vector< TOdfPixelType, NrOdfDirections >, 3 > > { public: /** \class DiffusionQballReconstructionImageFilter * \brief This enum defines the normalization of the ODFs. * \par * Standard normalization simply divides by sum of ODF-values * to ensure properties of a probability density function. * \par * B-zero/b-value normalization is ADC-style log of ratio * between b-zero and b_i normalized by b-value. * \par * B-zero normalization simply divides by b-zero reference value */ enum Normalization { QBR_STANDARD, QBR_B_ZERO_B_VALUE, QBR_B_ZERO, QBR_NONE }; typedef DiffusionQballReconstructionImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< TReferenceImagePixelType, 3>, Image< Vector< TOdfPixelType, NrOdfDirections >, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DiffusionQballReconstructionImageFilter, ImageToImageFilter); typedef TReferenceImagePixelType ReferencePixelType; typedef TGradientImagePixelType GradientPixelType; typedef Vector< TOdfPixelType, NrOdfDirections > OdfPixelType; /** Reference image data, This image is aquired in the absence * of a diffusion sensitizing field gradient */ typedef typename Superclass::InputImageType ReferenceImageType; typedef Image< OdfPixelType, 3 > OdfImageType; typedef OdfImageType OutputImageType; typedef TOdfPixelType BZeroPixelType; typedef Image< BZeroPixelType, 3 > BZeroImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; /** Typedef defining one (of the many) gradient images. */ typedef Image< GradientPixelType, 3 > GradientImageType; /** An alternative typedef defining one (of the many) gradient images. * It will be assumed that the vectorImage has the same dimension as the * Reference image and a vector length parameter of \c n (number of * gradient directions)*/ typedef VectorImage< GradientPixelType, 3 > GradientImagesType; /** Holds the ODF reconstruction matrix */ typedef vnl_matrix< TOdfPixelType >* OdfReconstructionMatrixType; /** Holds each magnetic field gradient used to acquire one DWImage */ typedef vnl_vector_fixed< double, 3 > GradientDirectionType; /** Container to hold gradient directions of the 'n' DW measurements */ typedef VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; itkStaticConstMacro(NOdfDirections,int,NrOdfDirections); itkStaticConstMacro(NBasisFunctionCenters,int,NrBasisFunctionCenters); /** Set method to add a gradient direction and its corresponding image. */ void AddGradientImage( const GradientDirectionType &, const GradientImageType *image); /** Another set method to add a gradient directions and its corresponding * image. The image here is a VectorImage. The user is expected to pass the * gradient directions in a container. The ith element of the container * corresponds to the gradient direction of the ith component image the * VectorImage. For the baseline image, a vector of all zeros * should be set.*/ void SetGradientImage( const GradientDirectionContainerType *, const GradientImagesType *image); /** Set method to set the reference image. */ void SetReferenceImage( ReferenceImageType *referenceImage ) { if( m_GradientImageTypeEnumeration == GradientIsInASingleImage) { itkExceptionMacro( << "Cannot call both methods:" << "AddGradientImage and SetGradientImage. Please call only one of them."); } this->ProcessObject::SetNthInput( 0, referenceImage ); m_GradientImageTypeEnumeration = GradientIsInManyImages; } /** Get reference image */ virtual ReferenceImageType * GetReferenceImage() { return ( static_cast< ReferenceImageType *>(this->ProcessObject::GetInput(0)) ); } /** Return the gradient direction. idx is 0 based */ virtual GradientDirectionType GetGradientDirection( unsigned int idx) const { if( idx >= m_NumberOfGradientDirections ) { itkExceptionMacro( << "Gradient direction " << idx << "does not exist" ); } return m_GradientDirectionContainer->ElementAt( idx+1 ); } /** Normalization performed on the reconstructed ODF according * to method set in m_NormalizationMethod */ OdfPixelType Normalize(OdfPixelType odf, typename NumericTraits::AccumulateType b0 ); /** Normalization performed on diffusion signal vector according * to method set in m_NormalizationMethod */ vnl_vector PreNormalize( vnl_vector vec ); /** Threshold on the reference image data. The output ODF will be a null * pdf for pixels in the reference image that have a value less than this * threshold. */ itkSetMacro( Threshold, ReferencePixelType ); itkGetMacro( Threshold, ReferencePixelType ); /** Normalization applied to ODFs */ itkSetMacro( NormalizationMethod, Normalization); itkGetMacro( NormalizationMethod, Normalization ); /** Output image with b-zero weighted images */ itkGetMacro( BZeroImage, typename BZeroImageType::Pointer); /** B-value used to acquire the diffusion signal */ itkSetMacro( BValue, TOdfPixelType); #ifdef GetBValue #undef GetBValue #endif itkGetConstReferenceMacro( BValue, TOdfPixelType); #ifdef ITK_USE_CONCEPT_CHECKING /** Begin concept checking */ itkConceptMacro(ReferenceEqualityComparableCheck, (Concept::EqualityComparable)); itkConceptMacro(TensorEqualityComparableCheck, (Concept::EqualityComparable)); itkConceptMacro(GradientConvertibleToDoubleCheck, (Concept::Convertible)); itkConceptMacro(DoubleConvertibleToTensorCheck, (Concept::Convertible)); itkConceptMacro(GradientReferenceAdditiveOperatorsCheck, (Concept::AdditiveOperators)); itkConceptMacro(ReferenceOStreamWritableCheck, (Concept::OStreamWritable)); itkConceptMacro(TensorOStreamWritableCheck, (Concept::OStreamWritable)); /** End concept checking */ #endif protected: DiffusionQballReconstructionImageFilter(); ~DiffusionQballReconstructionImageFilter() override {}; void PrintSelf(std::ostream& os, Indent indent) const override; /** constructs reconstrion matrix according to Tuch's algorithm */ void ComputeReconstructionMatrix(); void BeforeThreadedGenerateData() override; - void ThreadedGenerateData( const - OutputImageRegionType &outputRegionForThread, ThreadIdType) override; + void DynamicThreadedGenerateData( const + OutputImageRegionType &outputRegionForThread) override; /** enum to indicate if the gradient image is specified as a single multi- * component image or as several separate images */ typedef enum { GradientIsInASingleImage = 1, GradientIsInManyImages, Else } GradientImageTypeEnumeration; private: /* Tensor basis coeffs */ OdfReconstructionMatrixType m_ReconstructionMatrix; /** container to hold gradient directions */ GradientDirectionContainerType::Pointer m_GradientDirectionContainer; /** Number of gradient measurements */ unsigned int m_NumberOfGradientDirections; /** Number of Equator Sampling Points (StdValue sqrt(8*pi*NGradDirs)) */ unsigned int m_NumberOfEquatorSamplingPoints; /** Number of baseline images */ unsigned int m_NumberOfBaselineImages; /** Threshold on the reference image data */ ReferencePixelType m_Threshold; /** LeBihan's b-value for normalizing tensors */ TOdfPixelType m_BValue; /** Gradient image was specified in a single image or in multiple images */ GradientImageTypeEnumeration m_GradientImageTypeEnumeration; /** Output of b-zero reference image */ typename BZeroImageType::Pointer m_BZeroImage; /** Flag wether half shell was duplicated to ensure evenly * distributed directions on the sphere */ bool m_DirectionsDuplicated; /** Normalization method to be applied */ Normalization m_NormalizationMethod; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkDiffusionQballReconstructionImageFilter.txx" #endif #endif //__itkDiffusionQballReconstructionImageFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionQballReconstructionImageFilter.txx b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionQballReconstructionImageFilter.txx index e829a2b..9bb7c15 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionQballReconstructionImageFilter.txx +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionQballReconstructionImageFilter.txx @@ -1,853 +1,852 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkDiffusionQballReconstructionImageFilter_txx #define __itkDiffusionQballReconstructionImageFilter_txx #include "itkDiffusionQballReconstructionImageFilter.h" #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" #include "itkArray.h" #include "vnl/vnl_vector.h" #include "itkPointShell.h" namespace itk { template< class TReferenceImagePixelType, class TGradientImagePixelType, class TOdfPixelType, int NrOdfDirections, int NrBasisFunctionCenters> DiffusionQballReconstructionImageFilter< TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType, NrOdfDirections, NrBasisFunctionCenters> ::DiffusionQballReconstructionImageFilter() : m_GradientDirectionContainer(nullptr), m_NumberOfGradientDirections(0), m_NumberOfEquatorSamplingPoints(0), m_NumberOfBaselineImages(1), m_Threshold(NumericTraits< ReferencePixelType >::NonpositiveMin()), m_BValue(1.0), m_GradientImageTypeEnumeration(Else), m_DirectionsDuplicated(false) { // At least 1 inputs is necessary for a vector image. // For images added one at a time we need at least six this->SetNumberOfRequiredInputs( 1 ); - this->DynamicMultiThreadingOff(); + } template< class TReferenceImagePixelType, class TGradientImagePixelType, class TOdfPixelType, int NrOdfDirections, int NrBasisFunctionCenters> void DiffusionQballReconstructionImageFilter< TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType, NrOdfDirections, NrBasisFunctionCenters> ::BeforeThreadedGenerateData() { // If we have more than 2 inputs, then each input, except the first is a // gradient image. The number of gradient images must match the number of // gradient directions. const unsigned int numberOfInputs = this->GetNumberOfInputs(); // There need to be at least 6 gradient directions to be able to compute the // tensor basis if( m_NumberOfGradientDirections < 1 ) { itkExceptionMacro( << "Your image contains no diffusion gradients!" ); } // If there is only 1 gradient image, it must be an itk::VectorImage. Otherwise // we must have a container of (numberOfInputs-1) itk::Image. Check to make sure if ( numberOfInputs == 1 && m_GradientImageTypeEnumeration != GradientIsInASingleImage ) { std::string gradientImageClassName( this->ProcessObject::GetInput(0)->GetNameOfClass()); if ( strcmp(gradientImageClassName.c_str(),"VectorImage") != 0 ) { itkExceptionMacro( << "There is only one Gradient image. I expect that to be a VectorImage. " << "But its of type: " << gradientImageClassName ); } } // Compute reconstruction matrix that is multiplied to the data-vector // each voxel in order to reconstruct the ODFs this->ComputeReconstructionMatrix(); // Allocate the b-zero image m_BZeroImage = BZeroImageType::New(); if( m_GradientImageTypeEnumeration == GradientIsInManyImages ) { typename ReferenceImageType::Pointer img = static_cast< ReferenceImageType * >(this->ProcessObject::GetInput(0)); m_BZeroImage->SetSpacing( img->GetSpacing() ); // Set the image spacing m_BZeroImage->SetOrigin( img->GetOrigin() ); // Set the image origin m_BZeroImage->SetDirection( img->GetDirection() ); // Set the image direction m_BZeroImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion()); m_BZeroImage->SetBufferedRegion( img->GetLargestPossibleRegion() ); } // The gradients are specified in a single multi-component image else if( m_GradientImageTypeEnumeration == GradientIsInASingleImage ) { typename GradientImagesType::Pointer img = static_cast< GradientImagesType * >( this->ProcessObject::GetInput(0) ); m_BZeroImage->SetSpacing( img->GetSpacing() ); // Set the image spacing m_BZeroImage->SetOrigin( img->GetOrigin() ); // Set the image origin m_BZeroImage->SetDirection( img->GetDirection() ); // Set the image direction m_BZeroImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion()); m_BZeroImage->SetBufferedRegion( img->GetLargestPossibleRegion() ); } m_BZeroImage->Allocate(); } template< class TReferenceImagePixelType, class TGradientImagePixelType, class TOdfPixelType, int NrOdfDirections, int NrBasisFunctionCenters> typename itk::DiffusionQballReconstructionImageFilter::OdfPixelType itk::DiffusionQballReconstructionImageFilter::Normalize( OdfPixelType odf, typename NumericTraits::AccumulateType b0 ) { switch( m_NormalizationMethod ) { // divide by sum to retreive a PDF case QBR_STANDARD: { odf.Normalize(); return odf; break; } // ADC style case QBR_B_ZERO_B_VALUE: { for(int i=0; i vnl_vector itk::DiffusionQballReconstructionImageFilter::PreNormalize( vnl_vector vec ) { switch( m_NormalizationMethod ) { // standard: no normalization before reconstruction case QBR_STANDARD: { return vec; break; } // log of signal case QBR_B_ZERO_B_VALUE: { int n = vec.size(); for(int i=0; i void DiffusionQballReconstructionImageFilter< TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType, NrOdfDirections, NrBasisFunctionCenters> - ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, - ThreadIdType ) + ::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread) { // init output and b-zero iterators typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); ImageRegionIterator< BZeroImageType > oit2(m_BZeroImage, outputRegionForThread); oit2.GoToBegin(); vnl_vector B(m_NumberOfGradientDirections); // Two cases here: // 1. Gradients specified in multiple images // 'n' iterators for each of the gradient images // 2. Gradients specified in a single multi-component image // one iterator for all gradient directions if( m_GradientImageTypeEnumeration == GradientIsInManyImages ) { // b-zero reference image iterator ImageRegionConstIterator< ReferenceImageType > it(static_cast< ReferenceImageType * >(this->ProcessObject::GetInput(0)), outputRegionForThread); it.GoToBegin(); // fill vector with gradient iterators typedef ImageRegionConstIterator< GradientImageType > GradientIteratorType; std::vector< GradientIteratorType * > gradientItContainer; for( unsigned int i = 1; i<= m_NumberOfGradientDirections; i++ ) { // adapt index in case we have a duplicated shell int index = i; if(m_DirectionsDuplicated) index = i % (m_NumberOfGradientDirections/2); // init and pushback current input image iterator typename GradientImageType::Pointer gradientImagePointer = nullptr; // dynamic_cast would be nice, static because of SGI gradientImagePointer = static_cast< GradientImageType * >( this->ProcessObject::GetInput(index) ); GradientIteratorType *git = new GradientIteratorType( gradientImagePointer, outputRegionForThread ); git->GoToBegin(); gradientItContainer.push_back(git); } // Following loop does the actual reconstruction work in each voxel // (Tuch, Q-Ball Reconstruction [1]) while( !it.IsAtEnd() ) { // b-zero reference value ReferencePixelType b0 = it.Get(); // init ODF OdfPixelType odf(0.0); // threshold on reference value to suppress noisy regions if( (b0 != 0) && (b0 >= m_Threshold) ) { // fill array of diffusion measurements for( unsigned int i = 0; i< m_NumberOfGradientDirections; i++ ) { GradientPixelType b = gradientItContainer[i]->Get(); B[i] = static_cast(b); ++(*gradientItContainer[i]); } // pre-normalization according to m_NormalizationMethod B = PreNormalize(B); // actual reconstruction odf = ( (*m_ReconstructionMatrix) * B ).data_block(); // post-normalization according to m_NormalizationMethod odf.Normalize(); } else { // in case we fall below threshold, we just increment to next voxel for( unsigned int i = 0; i< m_NumberOfGradientDirections; i++ ) { ++(*gradientItContainer[i]); } } for (unsigned int i=0; i GradientIteratorType; typedef typename GradientImagesType::PixelType GradientVectorType; typename GradientImagesType::Pointer gradientImagePointer = nullptr; // dynamic_cast would be nice, static because of SGI gradientImagePointer = static_cast< GradientImagesType * >( this->ProcessObject::GetInput(0) ); GradientIteratorType git(gradientImagePointer, outputRegionForThread ); git.GoToBegin(); // set of indicies each for the baseline images and gradient images std::vector baselineind; // contains baseline indicies std::vector gradientind; // contains gradient indicies for(GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin(); gdcit != this->m_GradientDirectionContainer->End(); ++gdcit) { if(gdcit.Value().one_norm() <= 0.0) { baselineind.push_back(gdcit.Index()); } else { gradientind.push_back(gdcit.Index()); } } // in case we have a duplicated shell, we also duplicate or indices if( m_DirectionsDuplicated ) { int gradIndSize = gradientind.size(); for(int i=0; i::AccumulateType b0 = NumericTraits::Zero; for(unsigned int i = 0; i < baselineind.size(); ++i) { b0 += b[baselineind[i]]; } b0 /= this->m_NumberOfBaselineImages; // init resulting ODF OdfPixelType odf(0.0); // threshold on reference value to suppress noisy regions if( (b0 != 0) && (b0 >= m_Threshold) ) { for( unsigned int i = 0; i< m_NumberOfGradientDirections; i++ ) { B[i] = static_cast(b[gradientind[i]]); } // pre-normalization according to m_NormalizationMethod B = PreNormalize(B); // actual reconstruction odf = ( (*m_ReconstructionMatrix) * B ).data_block(); // post-normalization according to m_NormalizationMethod odf = Normalize(odf, b0); } for (unsigned int i=0; i void DiffusionQballReconstructionImageFilter< TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType, NrOdfDirections, NrBasisFunctionCenters> ::ComputeReconstructionMatrix() { if( m_NumberOfGradientDirections < 1 ) { itkExceptionMacro( << "Your image contains no diffusion gradients!" ); } { // check for duplicate diffusion gradients bool warning = false; for(GradientDirectionContainerType::ConstIterator gdcit1 = this->m_GradientDirectionContainer->Begin(); gdcit1 != this->m_GradientDirectionContainer->End(); ++gdcit1) { for(GradientDirectionContainerType::ConstIterator gdcit2 = this->m_GradientDirectionContainer->Begin(); gdcit2 != this->m_GradientDirectionContainer->End(); ++gdcit2) { if(gdcit1.Value() == gdcit2.Value() && gdcit1.Index() != gdcit2.Index()) { itkWarningMacro( << "Some of the Diffusion Gradients equal each other. Corresponding image data should be averaged before calling this filter." ); warning = true; break; } } if (warning) break; } // handle acquisition schemes where only half of the spherical // shell is sampled by the gradient directions. In this case, // each gradient direction is duplicated in negative direction. vnl_vector centerMass(3); centerMass.fill(0.0); int count = 0; for(GradientDirectionContainerType::ConstIterator gdcit1 = this->m_GradientDirectionContainer->Begin(); gdcit1 != this->m_GradientDirectionContainer->End(); ++gdcit1) { if(gdcit1.Value().one_norm() > 0.0) { centerMass += gdcit1.Value(); count ++; } } centerMass /= count; if(centerMass.two_norm() > 0.1) { m_DirectionsDuplicated = true; m_NumberOfGradientDirections *= 2; } } // set default number of equator sampling points if needed if(!this->m_NumberOfEquatorSamplingPoints) this->m_NumberOfEquatorSamplingPoints = (int) ceil((double)sqrt(8*itk::Math::pi*this->m_NumberOfGradientDirections)); vnl_matrix* Q = new vnl_matrix(3, m_NumberOfGradientDirections); { // Fill matrix Q with gradient directions int i = 0; for(GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin(); gdcit != this->m_GradientDirectionContainer->End(); ++gdcit) { if(gdcit.Value().one_norm() > 0.0) { (*Q)(0,i) = gdcit.Value().get(0); (*Q)(1,i) = gdcit.Value().get(1); (*Q)(2,i++) = gdcit.Value().get(2); } } if(m_DirectionsDuplicated) { for(GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin(); gdcit != this->m_GradientDirectionContainer->End(); ++gdcit) { if(gdcit.Value().one_norm() > 0.0) { (*Q)(0,i) = -gdcit.Value().get(0); (*Q)(1,i) = -gdcit.Value().get(1); (*Q)(2,i++) = -gdcit.Value().get(2); } } } } vnl_matrix_fixed* U = itk::PointShell >::DistributePointShell(); vnl_matrix_fixed* V = itk::PointShell >::DistributePointShell(); // calculate sampling points on the equator perpendicular to z-axis vnl_matrix *C = new vnl_matrix(3, m_NumberOfEquatorSamplingPoints); for(unsigned int i=0; i::Zero; } // rotate the sampling points to each directions of interest vnl_matrix *S = new vnl_matrix(3,m_NumberOfEquatorSamplingPoints*NOdfDirections); { vnl_vector_fixed z(NumericTraits::Zero); z.put(2,NumericTraits::One); vnl_matrix_fixed eye(NumericTraits::Zero); eye.fill_diagonal(NumericTraits::One); for(int i=0; i ui = (*U).get_column(i); vnl_matrix *RC = new vnl_matrix(3,m_NumberOfEquatorSamplingPoints); if( (z(0)*ui(0)+z(1)*ui(1)+z(2)*ui(2)+1) != 0 ) { vnl_matrix_fixed R; R.set_column(0, (z+ui)*(z(0)+ui(0))); R.set_column(1, (z+ui)*(z(1)+ui(1))); R.set_column(2, (z+ui)*(z(2)+ui(2))); R /= (z(0)*ui(0)+z(1)*ui(1)+z(2)*ui(2)+1); R -= eye; (*RC) = R*(*C); } else { RC = C; } (*S).set_columns(i*m_NumberOfEquatorSamplingPoints, *RC); } } // determine interpolation kernel width first // use to determine diffusion measurement contribution to each of the kernels vnl_matrix *H_plus = new vnl_matrix(NBasisFunctionCenters,m_NumberOfGradientDirections); double maxSigma = itk::Math::pi/6; double bestSigma = maxSigma; { double stepsize = 0.01; double start = 0.01; double minCondition = NumericTraits::max(); vnl_matrix *H = new vnl_matrix(m_NumberOfGradientDirections,NBasisFunctionCenters,(double)0); { int increasing = 0; for( double sigma=start; sigma *tmpH = new vnl_matrix(m_NumberOfGradientDirections,NBasisFunctionCenters); for(unsigned int r=0; r1.0) ? 1.0 : qtv); double x = acos(qtv); (*tmpH)(r,c) = (1.0/(sigma*sqrt(2.0*itk::Math::pi))) *exp((-x*x)/(2*sigma*sigma)); } } vnl_svd *solver; if(m_NumberOfGradientDirections>NBasisFunctionCenters) { solver = new vnl_svd(*tmpH); } else { solver = new vnl_svd(tmpH->transpose()); } double condition = solver->sigma_max() / solver->sigma_min(); std::cout << sigma << ": " << condition << std::endl; if( condition < minCondition ) { minCondition = condition; bestSigma = sigma; H->update(*tmpH); } else { // optimum assumed to be hit after condition increased 3 times if (++increasing>3) break; } } } vnl_matrix_inverse *pseudoInverse = new vnl_matrix_inverse(*H); (*H_plus) = pseudoInverse->pinverse(); std::cout << "choosing sigma = " << bestSigma << std::endl; } // this is the contribution of each kernel to each sampling point on the // equator vnl_matrix *G = new vnl_matrix(m_NumberOfEquatorSamplingPoints*NOdfDirections,NBasisFunctionCenters); { for(unsigned int r=0; r1.0) ? 1.0 : stv); double x = acos(stv); (*G)(r,c) = (1.0/(bestSigma*sqrt(2.0*itk::Math::pi))) *exp((-x*x)/(2*bestSigma*bestSigma)); } } } vnl_matrix *GH_plus = new vnl_matrix(m_NumberOfEquatorSamplingPoints*NOdfDirections,m_NumberOfGradientDirections); // simple matrix multiplication, manual cause of stack overflow using operator for (unsigned i = 0; i < m_NumberOfEquatorSamplingPoints*NOdfDirections; ++i) { for (unsigned j = 0; j < m_NumberOfGradientDirections; ++j) { double accum = (*G)(i,0) * (*H_plus)(0,j); for (unsigned k = 1; k < NOdfDirections; ++k) accum += (*G)(i,k) * (*H_plus)(k,j); (*GH_plus)(i,j) = accum; } } typename vnl_matrix::iterator it3; for( it3 = (*GH_plus).begin(); it3 != (*GH_plus).end(); it3++) { if(*it3<0.0) *it3 = 0; } // this is an addition to the original tuch algorithm for(unsigned int i=0; i r = GH_plus->get_row(i); r /= r.sum(); GH_plus->set_row(i,r); } m_ReconstructionMatrix = new vnl_matrix(NOdfDirections,m_NumberOfGradientDirections,0.0); for(int i=0; i r = m_ReconstructionMatrix->get_row(i); r /= r.sum(); m_ReconstructionMatrix->set_row(i,r); } std::cout << "Reconstruction Matrix computed." << std::endl; } template< class TReferenceImagePixelType, class TGradientImagePixelType, class TOdfPixelType, int NrOdfDirections, int NrBasisFunctionCenters> void DiffusionQballReconstructionImageFilter< TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType, NrOdfDirections, NrBasisFunctionCenters> ::AddGradientImage( const GradientDirectionType &gradientDirection, const GradientImageType *gradientImage ) { // Make sure crazy users did not call both AddGradientImage and // SetGradientImage if( m_GradientImageTypeEnumeration == GradientIsInASingleImage) { itkExceptionMacro( << "Cannot call both methods:" << "AddGradientImage and SetGradientImage. Please call only one of them."); } // If the container to hold the gradient directions hasn't been allocated // yet, allocate it. if( !this->m_GradientDirectionContainer ) { this->m_GradientDirectionContainer = GradientDirectionContainerType::New(); } this->m_NumberOfGradientDirections = m_GradientDirectionContainer->Size(); m_GradientDirectionContainer->InsertElement( this->m_NumberOfGradientDirections, gradientDirection / gradientDirection.two_norm() ); this->ProcessObject::SetNthInput( this->m_NumberOfGradientDirections, const_cast< GradientImageType* >(gradientImage) ); m_GradientImageTypeEnumeration = GradientIsInManyImages; } template< class TReferenceImagePixelType, class TGradientImagePixelType, class TOdfPixelType, int NrOdfDirections, int NrBasisFunctionCenters> void DiffusionQballReconstructionImageFilter< TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType, NrOdfDirections, NrBasisFunctionCenters> ::SetGradientImage(const GradientDirectionContainerType *gradientDirection, const GradientImagesType *gradientImage ) { // Make sure crazy users did not call both AddGradientImage and // SetGradientImage if( m_GradientImageTypeEnumeration == GradientIsInManyImages ) { itkExceptionMacro( << "Cannot call both methods:" << "AddGradientImage and SetGradientImage. Please call only one of them."); } this->m_GradientDirectionContainer = GradientDirectionContainerType::New(); for(GradientDirectionContainerType::ConstIterator it = gradientDirection->Begin(); it != gradientDirection->End(); it++) { this->m_GradientDirectionContainer->push_back(it.Value()); } unsigned int numImages = gradientDirection->Size(); this->m_NumberOfBaselineImages = 0; for(GradientDirectionContainerType::Iterator it = this->m_GradientDirectionContainer->Begin(); it != this->m_GradientDirectionContainer->End(); it++) { if(it.Value().one_norm() <= 0.0) { this->m_NumberOfBaselineImages++; } else // Normalize non-zero gradient directions { it.Value() = it.Value() / it.Value().two_norm(); } } this->m_NumberOfGradientDirections = numImages - this->m_NumberOfBaselineImages; // ensure that the gradient image we received has as many components as // the number of gradient directions if( gradientImage->GetVectorLength() != this->m_NumberOfBaselineImages + m_NumberOfGradientDirections ) { itkExceptionMacro( << m_NumberOfGradientDirections << " gradients + " << this->m_NumberOfBaselineImages << "baselines = " << m_NumberOfGradientDirections + this->m_NumberOfBaselineImages << " directions specified but image has " << gradientImage->GetVectorLength() << " components."); } this->ProcessObject::SetNthInput( 0, const_cast< GradientImagesType* >(gradientImage) ); m_GradientImageTypeEnumeration = GradientIsInASingleImage; } template< class TReferenceImagePixelType, class TGradientImagePixelType, class TOdfPixelType, int NrOdfDirections, int NrBasisFunctionCenters> void DiffusionQballReconstructionImageFilter< TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType, NrOdfDirections, NrBasisFunctionCenters> ::PrintSelf(std::ostream& os, Indent indent) const { std::locale C("C"); std::locale originalLocale = os.getloc(); os.imbue(C); Superclass::PrintSelf(os,indent); os << indent << "OdfReconstructionMatrix: " << m_ReconstructionMatrix << std::endl; if ( m_GradientDirectionContainer ) { os << indent << "GradientDirectionContainer: " << m_GradientDirectionContainer << std::endl; } else { os << indent << "GradientDirectionContainer: (Gradient directions not set)" << std::endl; } os << indent << "NumberOfGradientDirections: " << m_NumberOfGradientDirections << std::endl; os << indent << "NumberOfBaselineImages: " << m_NumberOfBaselineImages << std::endl; os << indent << "Threshold for reference B0 image: " << m_Threshold << std::endl; os << indent << "BValue: " << m_BValue << std::endl; if ( this->m_GradientImageTypeEnumeration == GradientIsInManyImages ) { os << indent << "Gradient images haven been supplied " << std::endl; } else if ( this->m_GradientImageTypeEnumeration == GradientIsInManyImages ) { os << indent << "A multicomponent gradient image has been supplied" << std::endl; } os.imbue( originalLocale ); } } #endif // __itkDiffusionQballReconstructionImageFilter_txx diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkMultiTensorImageFilter.h b/Modules/DiffusionCore/Algorithms/Reconstruction/itkMultiTensorImageFilter.h index d18d173..90da56c 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkMultiTensorImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkMultiTensorImageFilter.h @@ -1,200 +1,200 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkMultiTensorImageFilter_h_ #define __itkMultiTensorImageFilter_h_ #include "itkImageToImageFilter.h" #include "itkVectorImage.h" #include #include #include #include #include namespace itk{ /** \class MultiTensorImageFilter */ template< class TInPixelType, class TOutPixelType > class MultiTensorImageFilter : public ImageToImageFilter< VectorImage< TInPixelType, 3 >, Image< TOutPixelType, 3 > > { public: typedef MultiTensorImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< TInPixelType, 3 >, Image< TOutPixelType, 3 > > Superclass; typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType GradientContainerType; typedef itk::Image< unsigned char, 3> ItkUcharImageType; typedef mitk::PeakImage::ItkPeakImageType PeakImageType; typedef mitk::TensorImage::PixelType TensorType; typedef mitk::TensorImage::ItkTensorImageType TensorImageType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(MultiTensorImageFilter, ImageToImageFilter) typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; itkSetMacro( MaskImage, ItkUcharImageType::Pointer ) itkSetMacro( B_value, double ) itkSetMacro( GradientDirections, GradientContainerType::Pointer ) itkGetMacro( PeakImage, PeakImageType::Pointer ) std::vector< TensorImageType::Pointer > GetTensorImages(){ return m_TensorImages; } protected: MultiTensorImageFilter(); ~MultiTensorImageFilter() {} void PrintSelf(std::ostream& os, Indent indent) const override; void BeforeThreadedGenerateData() override; - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType) override; + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread) override; double m_B_value; std::vector m_B_values; std::vector m_WeightedIndices; std::vector m_UnWeightedIndices; GradientContainerType::Pointer m_GradientDirections; ItkUcharImageType::Pointer m_MaskImage; PeakImageType::Pointer m_PeakImage; std::vector< TensorImageType::Pointer > m_TensorImages; int m_NumTensors; vnl_vector FitSingleVoxel( const typename InputImageType::PixelType &input); // struct multiTensorLeastSquaresFunction: public vnl_least_squares_function // { // GradientContainerType::Pointer gradientDirections; // typename InputImageType::PixelType measurements; // std::vector bValues; // double S0; // int num_tensors; // std::vector weightedIndices; // void set_S0(double val) // { // S0 = val; // } // void set_measurements(const typename InputImageType::PixelType& m) // { // measurements = m; // } // void set_bvalues(std::vector& x) // { // bValues = x; // } // void set_weightedIndices(std::vector& x) // { // weightedIndices = x; // } // void set_gradient_directions(const GradientContainerType::Pointer& directions) // { // gradientDirections = directions; // } // int check(int n) // { // if (n==1) // return 6; // return n*7; // } // multiTensorLeastSquaresFunction(unsigned int number_of_tensors=2, unsigned int number_of_measurements=1) : // vnl_least_squares_function(check(number_of_tensors), number_of_measurements, no_gradient) // { // num_tensors = number_of_tensors; // } // void f(const vnl_vector& x, vnl_vector& fx) override // { // int elements = 7; // for(auto s : weightedIndices) // { // GradientDirectionType g = gradientDirections->GetElement(s); // g.normalize(); // itk::DiffusionTensor3D< double > S; // S[0] = g[0]*g[0]; // S[1] = g[1]*g[0]; // S[2] = g[2]*g[0]; // S[3] = g[1]*g[1]; // S[4] = g[2]*g[1]; // S[5] = g[2]*g[2]; // double approx = 0; // double penalty = 0; // double f = 0; // if (num_tensors==1 && x.size()==6) // f = 1; // for (int i=0; i1 && x.size()>6 && x[elements-1+i*elements]<0) // penalty if volume fractiuon is < 0 // penalty += 10e6; // if (num_tensors>1 && x.size()>6) // f += fabs(x[elements-1+i*elements]); // double D = x[0+i*elements]*S[0] + x[1+i*elements]*S[1] + x[2+i*elements]*S[2] + // x[1+i*elements]*S[1] + x[3+i*elements]*S[3] + x[4+i*elements]*S[4] + // x[2+i*elements]*S[2] + x[4+i*elements]*S[4] + x[5+i*elements]*S[5]; // double signal = S0 * std::exp ( -bValues[s] * D ); // if (num_tensors>1 && x.size()>6) // signal *= x[elements-1+i*elements]; // approx += signal; // } // const double factor = measurements[s] - approx; // penalty += fabs(f-1)*10e7; // penalty if volume fractiuon sum is != 1 // fx[s] = factor*factor + penalty; // } // } // }; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkMultiTensorImageFilter.txx" #endif #endif //__itkMultiTensorImageFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkMultiTensorImageFilter.txx b/Modules/DiffusionCore/Algorithms/Reconstruction/itkMultiTensorImageFilter.txx index 2b2322b..b751efd 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkMultiTensorImageFilter.txx +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkMultiTensorImageFilter.txx @@ -1,255 +1,255 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkMultiTensorImageFilter_txx #define __itkMultiTensorImageFilter_txx #include #include #include #define _USE_MATH_DEFINES #include #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" #include #include namespace itk { template< class TInPixelType, class TOutPixelType > MultiTensorImageFilter< TInPixelType, TOutPixelType> ::MultiTensorImageFilter() : m_B_value(0) , m_NumTensors(2) { this->SetNumberOfRequiredInputs( 1 ); - this->DynamicMultiThreadingOff(); + } template< class TInPixelType, class TOutPixelType > void MultiTensorImageFilter< TInPixelType, TOutPixelType> ::BeforeThreadedGenerateData() { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); outputImage->FillBuffer(0.0); m_UnWeightedIndices.clear(); m_WeightedIndices.clear(); m_B_values.clear(); for (unsigned int i=0; iSize(); i++) { GradientDirectionType g = m_GradientDirections->GetElement(i); double twonorm = g.two_norm(); double b = m_B_value*twonorm*twonorm; m_B_values.push_back(b); if (b>100) m_WeightedIndices.push_back(i); else m_UnWeightedIndices.push_back(i); } if (m_UnWeightedIndices.empty()) mitkThrow() << "Unweighted (b=0 s/mm²) image volume missing!"; itk::Vector spacing3 = outputImage->GetSpacing(); itk::Point origin3 = outputImage->GetOrigin(); itk::Matrix direction3 = outputImage->GetDirection(); itk::ImageRegion<3> imageRegion3 = outputImage->GetLargestPossibleRegion(); itk::Vector spacing4; itk::Point origin4; itk::Matrix direction4; itk::ImageRegion<4> imageRegion4; spacing4[0] = spacing3[0]; spacing4[1] = spacing3[1]; spacing4[2] = spacing3[2]; spacing4[3] = 1; origin4[0] = origin3[0]; origin4[1] = origin3[1]; origin4[2] = origin3[2]; origin4[3] = 0; for (int r=0; r<3; r++) for (int c=0; c<3; c++) direction4[r][c] = direction3[r][c]; direction4[3][3] = 1; imageRegion4.SetSize(0, imageRegion3.GetSize()[0]); imageRegion4.SetSize(1, imageRegion3.GetSize()[1]); imageRegion4.SetSize(2, imageRegion3.GetSize()[2]); imageRegion4.SetSize(3, 3*m_NumTensors); m_PeakImage = PeakImageType::New(); m_PeakImage->SetSpacing( spacing4 ); m_PeakImage->SetOrigin( origin4 ); m_PeakImage->SetDirection( direction4 ); m_PeakImage->SetRegions( imageRegion4 ); m_PeakImage->Allocate(); m_PeakImage->FillBuffer(0.0); m_TensorImages.clear(); for (int i=0; iSetSpacing( spacing3 ); tImg->SetOrigin( origin3 ); tImg->SetDirection( direction3 ); tImg->SetRegions( imageRegion3 ); tImg->Allocate(); m_TensorImages.push_back(tImg); } } template< class TInPixelType, class TOutPixelType > vnl_vector MultiTensorImageFilter< TInPixelType, TOutPixelType>::FitSingleVoxel( const typename InputImageType::PixelType &input) { double S0 = 0; for (auto i : m_UnWeightedIndices) S0 += input[i]; S0 /= m_UnWeightedIndices.size(); // signle tensor fit mitk::MultiTensorFitter ls_fit(1, m_GradientDirections->size()); ls_fit.set_S0(S0); ls_fit.set_weightedIndices(m_WeightedIndices); ls_fit.set_bvalues(m_B_values); ls_fit.set_gradient_directions(m_GradientDirections); ls_fit.set_measurements(input); vnl_levenberg_marquardt lm(ls_fit); vnl_vector x; x.set_size(6); x.fill(0.0); lm.minimize(x); // TensorType tensor; vnl_vector y; y.set_size(7*m_NumTensors); y.fill(0.0); for (int i=0; i<6; i++) { y[i] = x[i]; // tensor[i] = x[i]; } y[6]=1; // double fa = tensor.GetFractionalAnisotropy(); if (m_NumTensors>1) { mitk::MultiTensorFitter ls_fit(m_NumTensors, m_GradientDirections->size()); ls_fit.set_S0(S0); ls_fit.set_weightedIndices(m_WeightedIndices); ls_fit.set_bvalues(m_B_values); ls_fit.set_gradient_directions(m_GradientDirections); ls_fit.set_measurements(input); vnl_levenberg_marquardt lm(ls_fit); for (int i=0; i void MultiTensorImageFilter< TInPixelType, TOutPixelType> -::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) +::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread ) { typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); InputIteratorType git( inputImagePointer, outputRegionForThread ); git.GoToBegin(); while( !git.IsAtEnd() ) { typename InputImageType::PixelType pix = git.Get(); vnl_vector x = FitSingleVoxel(pix); typedef itk::DiffusionTensor3D TensorType; int elements = 7; for (int t=0; tSetPixel(git.GetIndex(), tensor); } // TensorType tensor; // tensor.Fill(0.0); // tensor[0] = x[0]*x[1]; // tensor[3] = tensor[0]; // tensor[5] = tensor[0]; // m_TensorImages.at(m_NumTensors+1)->SetPixel(git.GetIndex(), tensor); // /// DWI from tensor // int elements = 7; // int num_ten = m_NumTensors; // typename DiffusionImageType::PixelType dPix; dPix.SetSize(m_GradientDirections->Size()); dPix.Fill(0.0); // for (unsigned int i=0; iSize(); i++) // { // GradientDirectionType g = m_GradientDirections->GetElement(i); // double twonorm = g.two_norm(); // double b = m_B_value*twonorm*twonorm; // itk::DiffusionTensor3D< double > S; // S[0] = g[0]*g[0]; // S[1] = g[1]*g[0]; // S[2] = g[2]*g[0]; // S[3] = g[1]*g[1]; // S[4] = g[2]*g[1]; // S[5] = g[2]*g[2]; // double approx = 0; // for (int i=0; iSetPixel(oit.GetIndex(), dPix); ++git; } std::cout << "One Thread finished calculation" << std::endl; } template< class TInPixelType, class TOutPixelType > void MultiTensorImageFilter< TInPixelType, TOutPixelType> ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); } } #endif // __itkMultiTensorImageFilter_txx diff --git a/Modules/DiffusionCore/Algorithms/itkAdcImageFilter.h b/Modules/DiffusionCore/Algorithms/itkAdcImageFilter.h index e0d509d..6dae5e3 100644 --- a/Modules/DiffusionCore/Algorithms/itkAdcImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkAdcImageFilter.h @@ -1,136 +1,136 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkAdcImageFilter_h_ #define __itkAdcImageFilter_h_ #include "itkImageToImageFilter.h" #include "itkVectorImage.h" #include #include #include namespace itk{ /** \class AdcImageFilter */ template< class TInPixelType, class TOutPixelType > class AdcImageFilter : public ImageToImageFilter< VectorImage< TInPixelType, 3 >, Image< TOutPixelType, 3 > > { public: typedef AdcImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< TInPixelType, 3 >, Image< TOutPixelType, 3 > > Superclass; typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer GradientContainerType; typedef itk::Image< unsigned char, 3> ItkUcharImageType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(AdcImageFilter, ImageToImageFilter) typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; itkSetMacro( MaskImage, ItkUcharImageType::Pointer ) itkSetMacro( FitSignal, bool ) itkSetMacro( B_value, double ) itkSetMacro( GradientDirections, GradientContainerType ) /** * \brief The lestSquaresFunction struct for Non-Linear-Least-Squres fit of monoexponential model Si = S0*exp(-b*ADC) */ struct adcLeastSquaresFunction: public vnl_least_squares_function { void set_S0(double val) { S0 = val; } void set_measurements(const vnl_vector& m) { measurements.set_size(m.size()); measurements.copy_in(m.data_block()); } void set_bvalues(const vnl_vector& x) { bValues.set_size(x.size()); bValues.copy_in(x.data_block()); } vnl_vector measurements; vnl_vector bValues; double S0; adcLeastSquaresFunction(unsigned int number_of_measurements=1) : vnl_least_squares_function(1, number_of_measurements, no_gradient) { } void f(const vnl_vector& x, vnl_vector& fx) override { const double & ADC = x[0]; for(unsigned int s=0; s m_B_values; vnl_vector m_Nonzero_B_values; GradientContainerType m_GradientDirections; ItkUcharImageType::Pointer m_MaskImage; double FitSingleVoxel( const typename InputImageType::PixelType &input); }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkAdcImageFilter.txx" #endif #endif //__itkAdcImageFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/itkAdcImageFilter.txx b/Modules/DiffusionCore/Algorithms/itkAdcImageFilter.txx index c3b2f94..2925bfd 100644 --- a/Modules/DiffusionCore/Algorithms/itkAdcImageFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkAdcImageFilter.txx @@ -1,210 +1,210 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkAdcImageFilter_txx #define __itkAdcImageFilter_txx #include #include #include #define _USE_MATH_DEFINES #include #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" namespace itk { template< class TInPixelType, class TOutPixelType > AdcImageFilter< TInPixelType, TOutPixelType> ::AdcImageFilter() : m_FitSignal(true) , m_B_value(0) { this->SetNumberOfRequiredInputs( 1 ); - this->DynamicMultiThreadingOff(); + } template< class TInPixelType, class TOutPixelType > void AdcImageFilter< TInPixelType, TOutPixelType> ::BeforeThreadedGenerateData() { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); outputImage->FillBuffer(0.0); m_B_values.set_size(m_GradientDirections->Size()); int nonzero = 0; for (unsigned int i=0; iSize(); i++) { GradientDirectionType g = m_GradientDirections->GetElement(i); double twonorm = g.two_norm(); double b = m_B_value*twonorm*twonorm; m_B_values[i] = b; if (g.magnitude()>0.001) nonzero++; } m_Nonzero_B_values.set_size(nonzero); nonzero = 0; for (unsigned int i=0; i1) { m_Nonzero_B_values[nonzero] = m_B_values[i]; nonzero++; } } if (m_B_values.size() == m_Nonzero_B_values.size()) mitkThrow() << "Unweighted (b=0 s/mm²) image volume missing!"; } template< class TInPixelType, class TOutPixelType > double AdcImageFilter< TInPixelType, TOutPixelType>::FitSingleVoxel( const typename InputImageType::PixelType &input) { double S0 = 0; int nonzero = 0; vnl_vector m; m.set_size(m_Nonzero_B_values.size()); for (unsigned int i=0; i1) { m[nonzero] = input[i]; nonzero++; } else S0 += input[i]; } S0 /= (m_B_values.size() - m_Nonzero_B_values.size()); adcLeastSquaresFunction f(m_Nonzero_B_values.size()); f.set_bvalues(m_Nonzero_B_values); f.set_S0(S0); f.set_measurements(m); vnl_levenberg_marquardt lm(f); vnl_vector_fixed x; x.fill(0); lm.minimize(x); return x[0]; } template< class TInPixelType, class TOutPixelType > void AdcImageFilter< TInPixelType, TOutPixelType> -::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) +::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread ) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typename InputImageType::Pointer inputImagePointer = nullptr; inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); InputIteratorType git( inputImagePointer, outputRegionForThread ); git.GoToBegin(); while( !git.IsAtEnd() ) { typename InputImageType::PixelType pix = git.Get(); TOutPixelType outval = 0; if (!m_FitSignal) { double S0 = 0; int c = 0; for (unsigned int i=0; iGetVectorLength(); i++) { GradientDirectionType g = m_GradientDirections->GetElement(i); if (g.magnitude()<0.001) { if (pix[i]>0) { S0 += pix[i]; c++; } } } if (c>0) S0 /= c; if (S0>0) { c = 0; for (unsigned int i=0; iGetVectorLength(); i++) { GradientDirectionType g = m_GradientDirections->GetElement(i); if (g.magnitude()>0.001) { double twonorm = g.two_norm(); double b = m_B_value*twonorm*twonorm; if (b>0) { double S = pix[i]; if (S>0 && S0>0) { outval -= std::log(S/S0)/b; c++; } } } } if (c>0) outval /= c; } } else { outval = FitSingleVoxel(pix); } // if (outval<-0.00001) // outval = -0.00001; if (outval==outval && outval<1000) oit.Set( outval ); // else // oit.Set( -0.00001 ); ++oit; ++git; } } template< class TInPixelType, class TOutPixelType > void AdcImageFilter< TInPixelType, TOutPixelType> ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); } } #endif // __itkAdcImageFilter_txx diff --git a/Modules/DiffusionCore/Algorithms/itkDiffusionOdfGeneralizedFaImageFilter.h b/Modules/DiffusionCore/Algorithms/itkDiffusionOdfGeneralizedFaImageFilter.h index 55165cc..2af3b92 100644 --- a/Modules/DiffusionCore/Algorithms/itkDiffusionOdfGeneralizedFaImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkDiffusionOdfGeneralizedFaImageFilter.h @@ -1,128 +1,127 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkDiffusionOdfGeneralizedFaImageFilter_h_ #define __itkDiffusionOdfGeneralizedFaImageFilter_h_ //#include "MitkDiffusionImagingMBIExports.h" #include "itkImageToImageFilter.h" //#include "vnl/vnl_matrix.h" #include "vnl/vnl_vector_fixed.h" #include "vnl/vnl_matrix.h" #include "vnl/algo/vnl_svd.h" #include "itkVectorContainer.h" #include "itkVectorImage.h" namespace itk{ /** \class DiffusionOdfGeneralizedFaImageFilter */ template< class TOdfPixelType, class TGfaPixelType, unsigned int NrOdfDirections> class DiffusionOdfGeneralizedFaImageFilter : public ImageToImageFilter< Image< Vector< TOdfPixelType, NrOdfDirections >, 3 >, Image< TGfaPixelType, 3 > > { public: enum GfaComputationMethod { GFA_STANDARD, GFA_QUANTILES_HIGH_LOW, GFA_QUANTILE_HIGH, GFA_MAX_ODF_VALUE, GFA_DECONVOLUTION_COEFFS, GFA_MIN_MAX_NORMALIZED_STANDARD, GFA_NORMALIZED_ENTROPY, GFA_NEMATIC_ORDER_PARAMETER, GFA_QUANTILE_LOW, GFA_MIN_ODF_VALUE, GFA_QUANTILES_LOW_HIGH, GFA_STD_BY_MAX, GFA_PRINCIPLE_CURVATURE, GFA_GENERALIZED_GFA }; typedef DiffusionOdfGeneralizedFaImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< Vector< TOdfPixelType, NrOdfDirections >, 3 >, Image< TGfaPixelType, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DiffusionOdfGeneralizedFaImageFilter, ImageToImageFilter); typedef TOdfPixelType OdfComponentType; typedef TGfaPixelType DirectionPixelType; typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; itkStaticConstMacro(NOdfDirections,int,NrOdfDirections); void SetOdfImage( const InputImageType *image ); itkGetMacro(ComputationMethod, GfaComputationMethod); itkSetMacro(ComputationMethod, GfaComputationMethod); itkGetMacro(Param1, double); itkSetMacro(Param1, double); itkGetMacro(Param2, double); itkSetMacro(Param2, double); protected: DiffusionOdfGeneralizedFaImageFilter(); ~DiffusionOdfGeneralizedFaImageFilter() override {}; void PrintSelf(std::ostream& os, Indent indent) const override; void BeforeThreadedGenerateData() override; - void ThreadedGenerateData( const - OutputImageRegionType &outputRegionForThread, ThreadIdType) override; + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread) override; GfaComputationMethod m_ComputationMethod; double m_Param1; double m_Param2; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkDiffusionOdfGeneralizedFaImageFilter.txx" #endif #endif //__itkDiffusionOdfGeneralizedFaImageFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/itkDiffusionOdfGeneralizedFaImageFilter.txx b/Modules/DiffusionCore/Algorithms/itkDiffusionOdfGeneralizedFaImageFilter.txx index 929505e..ba9f7c0 100644 --- a/Modules/DiffusionCore/Algorithms/itkDiffusionOdfGeneralizedFaImageFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkDiffusionOdfGeneralizedFaImageFilter.txx @@ -1,224 +1,221 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkDiffusionOdfGeneralizedFaImageFilter_txx #define __itkDiffusionOdfGeneralizedFaImageFilter_txx #include #include #include #define _USE_MATH_DEFINES #include #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" #include "itkArray.h" #include "vnl/vnl_vector.h" #include "vnl/vnl_vector_fixed.h" #include #include "itkOrientationDistributionFunction.h" namespace itk { template< class TOdfPixelType, class TGfaPixelType, unsigned int NrOdfDirections> DiffusionOdfGeneralizedFaImageFilter< TOdfPixelType, TGfaPixelType, NrOdfDirections> ::DiffusionOdfGeneralizedFaImageFilter() : m_ComputationMethod(GFA_STANDARD) { // At least 1 inputs is necessary for a vector image. // For images added one at a time we need at least six this->SetNumberOfRequiredInputs( 1 ); - - this->DynamicMultiThreadingOff(); } template< class TOdfPixelType, class TGfaPixelType, unsigned int NrOdfDirections> void DiffusionOdfGeneralizedFaImageFilter< TOdfPixelType, TGfaPixelType, NrOdfDirections> ::BeforeThreadedGenerateData() { } template< class TOdfPixelType, class TGfaPixelType, unsigned int NrOdfDirections> void DiffusionOdfGeneralizedFaImageFilter< TOdfPixelType, TGfaPixelType, NrOdfDirections> - ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, - ThreadIdType ) + ::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); typedef itk::OrientationDistributionFunction OdfType; typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typedef typename InputImageType::PixelType OdfVectorType; typename InputImageType::Pointer inputImagePointer = nullptr; inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); InputIteratorType git(inputImagePointer, outputRegionForThread ); git.GoToBegin(); while( !git.IsAtEnd() ) { OdfVectorType b = git.Get(); TGfaPixelType outval = -1; switch( m_ComputationMethod ) { case GFA_STANDARD: { OdfType odf = b.GetDataPointer(); outval = odf.GetGeneralizedFractionalAnisotropy(); break; } case GFA_QUANTILES_HIGH_LOW: { vnl_vector_fixed sorted; for(unsigned int i=0; i sorted; for(unsigned int i=0; i sorted; for(unsigned int i=0; i sorted; for(unsigned int i=0; i void DiffusionOdfGeneralizedFaImageFilter< TOdfPixelType, TGfaPixelType, NrOdfDirections> ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); } } #endif // __itkDiffusionOdfGeneralizedFaImageFilter_txx diff --git a/Modules/DiffusionCore/Algorithms/itkDiffusionOdfPrepareVisualizationImageFilter.cpp b/Modules/DiffusionCore/Algorithms/itkDiffusionOdfPrepareVisualizationImageFilter.cpp index 5e5b438..15797c0 100644 --- a/Modules/DiffusionCore/Algorithms/itkDiffusionOdfPrepareVisualizationImageFilter.cpp +++ b/Modules/DiffusionCore/Algorithms/itkDiffusionOdfPrepareVisualizationImageFilter.cpp @@ -1,183 +1,182 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkDiffusionOdfPrepareVisualizationImageFilter_cpp #define __itkDiffusionOdfPrepareVisualizationImageFilter_cpp #include #include #include #include "itkDiffusionOdfPrepareVisualizationImageFilter.h" #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" #include "itkArray.h" #include "vnl/vnl_vector.h" #include "itkOrientationDistributionFunction.h" namespace itk { - template< class TOdfPixelType, int NrOdfDirections> - DiffusionOdfPrepareVisualizationImageFilter< TOdfPixelType, NrOdfDirections> - ::DiffusionOdfPrepareVisualizationImageFilter() : +template< class TOdfPixelType, int NrOdfDirections> +DiffusionOdfPrepareVisualizationImageFilter< TOdfPixelType, NrOdfDirections> +::DiffusionOdfPrepareVisualizationImageFilter() : m_Threshold(0), - m_ScaleByGfaType(GfaFilterType::GFA_STANDARD), - m_DoScaleGfa(false), - m_GfaParam1(2), - m_GfaParam2(1) - { - // At least 1 inputs is necessary for a vector image. - // For images added one at a time we need at least six - this->SetNumberOfRequiredInputs( 1 ); + m_ScaleByGfaType(GfaFilterType::GFA_STANDARD), + m_DoScaleGfa(false), + m_GfaParam1(2), + m_GfaParam2(1) +{ + // At least 1 inputs is necessary for a vector image. + // For images added one at a time we need at least six + this->SetNumberOfRequiredInputs( 1 ); - this->DynamicMultiThreadingOff(); - } - template< class TOdfPixelType, - int NrOdfDirections> - void DiffusionOdfPrepareVisualizationImageFilter< TOdfPixelType, - NrOdfDirections> - ::BeforeThreadedGenerateData() +} + +template< class TOdfPixelType, + int NrOdfDirections> +void DiffusionOdfPrepareVisualizationImageFilter< TOdfPixelType, +NrOdfDirections> +::BeforeThreadedGenerateData() +{ + if( m_NormalizationMethod == PV_GLOBAL_MAX ) { - if( m_NormalizationMethod == PV_GLOBAL_MAX ) - { - typename InputImageType::Pointer inputImagePointer = nullptr; - inputImagePointer = static_cast< InputImageType * >( - this->ProcessObject::GetInput(0) ); + typename InputImageType::Pointer inputImagePointer = nullptr; + inputImagePointer = static_cast< InputImageType * >( + this->ProcessObject::GetInput(0) ); - typename GfaFilterType::Pointer filter = GfaFilterType::New(); - filter->SetInput(inputImagePointer); - filter->SetNumberOfThreads(4); - filter->SetComputationMethod(GfaFilterType::GFA_MAX_ODF_VALUE); - filter->Update(); + typename GfaFilterType::Pointer filter = GfaFilterType::New(); + filter->SetInput(inputImagePointer); + filter->SetNumberOfThreads(4); + filter->SetComputationMethod(GfaFilterType::GFA_MAX_ODF_VALUE); + filter->Update(); - typedef typename itk::MinimumMaximumImageCalculator< typename GfaFilterType::OutputImageType > + typedef typename itk::MinimumMaximumImageCalculator< typename GfaFilterType::OutputImageType > MaxFilterType; - typename MaxFilterType::Pointer maxFilter = MaxFilterType::New(); - maxFilter->SetImage(filter->GetOutput()); - maxFilter->ComputeMaximum(); + typename MaxFilterType::Pointer maxFilter = MaxFilterType::New(); + maxFilter->SetImage(filter->GetOutput()); + maxFilter->ComputeMaximum(); - m_GlobalInputMaximum = maxFilter->GetMaximum(); - } - - //if(m_DoScaleGfa) - { - typename InputImageType::Pointer inputImagePointer = nullptr; - inputImagePointer = static_cast< InputImageType * >( - this->ProcessObject::GetInput(0) ); - - typename GfaFilterType::Pointer filter = GfaFilterType::New(); - filter->SetInput(inputImagePointer); - filter->SetNumberOfThreads(4); - filter->SetComputationMethod(m_ScaleByGfaType); - filter->SetParam1(m_GfaParam1); - filter->SetParam2(m_GfaParam2); - filter->Update(); - m_GfaImage = filter->GetOutput(); - } + m_GlobalInputMaximum = maxFilter->GetMaximum(); } - template< class TOdfPixelType, - int NrOdfDirections> - void DiffusionOdfPrepareVisualizationImageFilter< TOdfPixelType, - NrOdfDirections> - ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, - ThreadIdType ) + //if(m_DoScaleGfa) { - typename OutputImageType::Pointer outputImage = - static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); - ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); - oit.GoToBegin(); - - typedef itk::OrientationDistributionFunction OdfType; - typedef ImageRegionConstIterator< InputImageType > InputIteratorType; - typedef typename InputImageType::PixelType OdfVectorType; typename InputImageType::Pointer inputImagePointer = nullptr; inputImagePointer = static_cast< InputImageType * >( - this->ProcessObject::GetInput(0) ); - InputIteratorType git(inputImagePointer, outputRegionForThread ); - git.GoToBegin(); + this->ProcessObject::GetInput(0) ); + + typename GfaFilterType::Pointer filter = GfaFilterType::New(); + filter->SetInput(inputImagePointer); + filter->SetNumberOfThreads(4); + filter->SetComputationMethod(m_ScaleByGfaType); + filter->SetParam1(m_GfaParam1); + filter->SetParam2(m_GfaParam2); + filter->Update(); + m_GfaImage = filter->GetOutput(); + } +} - typedef ImageRegionConstIterator< GfaImageType > GfaIteratorType; - GfaIteratorType gfaIt(m_GfaImage, outputRegionForThread); +template< class TOdfPixelType, + int NrOdfDirections> +void DiffusionOdfPrepareVisualizationImageFilter< TOdfPixelType, +NrOdfDirections> +::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread) +{ + typename OutputImageType::Pointer outputImage = + static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); + ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); + oit.GoToBegin(); + + typedef itk::OrientationDistributionFunction OdfType; + typedef ImageRegionConstIterator< InputImageType > InputIteratorType; + typedef typename InputImageType::PixelType OdfVectorType; + typename InputImageType::Pointer inputImagePointer = nullptr; + inputImagePointer = static_cast< InputImageType * >( + this->ProcessObject::GetInput(0) ); + InputIteratorType git(inputImagePointer, outputRegionForThread ); + git.GoToBegin(); - while( !git.IsAtEnd() ) - { - OdfVectorType b = git.Get(); - OdfType odf = b.GetDataPointer(); + typedef ImageRegionConstIterator< GfaImageType > GfaIteratorType; + GfaIteratorType gfaIt(m_GfaImage, outputRegionForThread); - switch( m_NormalizationMethod ) - { - case PV_NONE: - { - break; - } - case PV_MAX: - { - odf = odf.MaxNormalize(); - break; - } - case PV_MIN_MAX: - { - odf = odf.MinMaxNormalize(); - break; - } - case PV_GLOBAL_MAX: - { - odf *= 1.0/m_GlobalInputMaximum; - break; - } - case PV_MIN_MAX_INVERT: - { - odf = odf.MinMaxNormalize(); - for(int i=0; i - void DiffusionOdfPrepareVisualizationImageFilter< TOdfPixelType, - NrOdfDirections> - ::PrintSelf(std::ostream& os, Indent indent) const - { - Superclass::PrintSelf(os,indent); - os << indent << "m_Threshold: " << - m_Threshold << std::endl; - } + std::cout << "One Thread finished extraction" << std::endl; +} + +template< class TOdfPixelType, + int NrOdfDirections> +void DiffusionOdfPrepareVisualizationImageFilter< TOdfPixelType, +NrOdfDirections> +::PrintSelf(std::ostream& os, Indent indent) const +{ + Superclass::PrintSelf(os,indent); + os << indent << "m_Threshold: " << + m_Threshold << std::endl; +} } #endif // __itkDiffusionOdfPrepareVisualizationImageFilter_cpp diff --git a/Modules/DiffusionCore/Algorithms/itkDiffusionOdfPrepareVisualizationImageFilter.h b/Modules/DiffusionCore/Algorithms/itkDiffusionOdfPrepareVisualizationImageFilter.h index 39a5900..09b778f 100644 --- a/Modules/DiffusionCore/Algorithms/itkDiffusionOdfPrepareVisualizationImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkDiffusionOdfPrepareVisualizationImageFilter.h @@ -1,142 +1,142 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkDiffusionOdfPrepareVisualizationImageFilter_h_ #define __itkDiffusionOdfPrepareVisualizationImageFilter_h_ #include #include "itkImageToImageFilter.h" //#include "vnl/vnl_matrix.h" #include "vnl/vnl_vector_fixed.h" #include "vnl/vnl_matrix.h" #include "vnl/algo/vnl_svd.h" #include "itkVectorContainer.h" #include "itkVectorImage.h" #include "itkDiffusionOdfGeneralizedFaImageFilter.h" namespace itk{ /** \class DiffusionOdfPrepareVisualizationImageFilter */ template< class TOdfPixelType, int NrOdfDirections> class MITKDIFFUSIONCORE_EXPORT DiffusionOdfPrepareVisualizationImageFilter : public ImageToImageFilter< Image< Vector< TOdfPixelType, NrOdfDirections >, 3 >, Image< Vector< TOdfPixelType, NrOdfDirections >, 3 > > { public: enum NormalizationMethods { PV_NONE, PV_MAX, PV_MIN_MAX, PV_GLOBAL_MAX, PV_MIN_MAX_INVERT }; typedef DiffusionOdfPrepareVisualizationImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< Vector< TOdfPixelType, NrOdfDirections >, 3 >, Image< Vector< TOdfPixelType, NrOdfDirections >, 3 > > Superclass; typedef DiffusionOdfGeneralizedFaImageFilter GfaFilterType; typedef typename GfaFilterType::OutputImageType GfaImageType; typedef typename GfaFilterType::GfaComputationMethod GfaComputationMethod; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DiffusionOdfPrepareVisualizationImageFilter, ImageToImageFilter); typedef TOdfPixelType OdfComponentType; typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; itkStaticConstMacro(NOdfDirections,int,NrOdfDirections); itkSetMacro( Threshold, OdfComponentType ); itkGetMacro( Threshold, OdfComponentType ); itkSetMacro( NormalizationMethod, NormalizationMethods ); itkGetMacro( NormalizationMethod, NormalizationMethods ); itkSetMacro( ScaleByGfaType, GfaComputationMethod ); itkGetMacro( ScaleByGfaType, GfaComputationMethod ); itkSetMacro( DoScaleGfa, bool ); itkGetMacro( DoScaleGfa, bool ); itkSetMacro( GfaParam1, double ); itkGetMacro( GfaParam1, double ); itkSetMacro( GfaParam2, double ); itkGetMacro( GfaParam2, double ); protected: DiffusionOdfPrepareVisualizationImageFilter(); ~DiffusionOdfPrepareVisualizationImageFilter() {}; void PrintSelf(std::ostream& os, Indent indent) const; void BeforeThreadedGenerateData(); - void ThreadedGenerateData( const - OutputImageRegionType &outputRegionForThread, ThreadIdType); + void DynamicThreadedGenerateData( const + OutputImageRegionType &outputRegionForThread); private: /** Threshold on the reference image data */ OdfComponentType m_Threshold; NormalizationMethods m_NormalizationMethod; OdfComponentType m_GlobalInputMaximum; GfaComputationMethod m_ScaleByGfaType; bool m_DoScaleGfa; typename GfaImageType::Pointer m_GfaImage; double m_GfaParam1; double m_GfaParam2; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkDiffusionOdfPrepareVisualizationImageFilter.cpp" #endif #endif //__itkDiffusionOdfPrepareVisualizationImageFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.h b/Modules/DiffusionCore/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.h index 506e166..244562d 100644 --- a/Modules/DiffusionCore/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.h @@ -1,102 +1,102 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkDiffusionTensorPrincipalDirectionImageFilter_h_ #define __itkDiffusionTensorPrincipalDirectionImageFilter_h_ #include #include #include #include #include #include #include #include #include namespace itk{ /** \brief Extracts principal eigenvectors of the input tensors */ template< class TTensorPixelType> class DiffusionTensorPrincipalDirectionImageFilter : public ImageToImageFilter< Image< DiffusionTensor3D, 3 >, Image< unsigned char, 3 > > { public: typedef DiffusionTensorPrincipalDirectionImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< DiffusionTensor3D, 3 >, Image< unsigned char, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DiffusionTensorPrincipalDirectionImageFilter, ImageToImageFilter) typedef TTensorPixelType TensorComponentType; typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef itk::Image ItkUcharImgType; typedef vnl_vector_fixed< double, 3 > DirectionType; typedef Image< float, 4 > PeakImageType; void SetImage( const InputImageType *image ); // input itkSetMacro( MaskImage, ItkUcharImgType::Pointer) itkSetMacro( NormalizeVectors, bool) itkSetMacro( UsePolarCoordinates, bool) itkSetMacro( FaThreshold, float) // output itkGetMacro( PeakImage, PeakImageType::Pointer) protected: DiffusionTensorPrincipalDirectionImageFilter(); ~DiffusionTensorPrincipalDirectionImageFilter() {} void PrintSelf(std::ostream& os, Indent indent) const; void BeforeThreadedGenerateData(); - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType ); + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread ); void AfterThreadedGenerateData(); private: bool m_NormalizeVectors; ///< Normalizes the output vector to length 1 ItkUcharImgType::Pointer m_MaskImage; ///< Extraction is only performed inside of the binary mask PeakImageType::Pointer m_PeakImage; bool m_UsePolarCoordinates; float m_FaThreshold; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkDiffusionTensorPrincipalDirectionImageFilter.txx" #endif #endif //__itkDiffusionTensorPrincipalDirectionImageFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.txx b/Modules/DiffusionCore/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.txx index cd52121..2733bc8 100644 --- a/Modules/DiffusionCore/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.txx @@ -1,217 +1,217 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkDiffusionTensorPrincipalDirectionImageFilter_txx #define __itkDiffusionTensorPrincipalDirectionImageFilter_txx #include #include #include #include "itkDiffusionTensorPrincipalDirectionImageFilter.h" #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" #include "itkArray.h" #include "vnl/vnl_vector.h" #include #include #include #include #include #include namespace itk { template< class TTensorPixelType> DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType>::DiffusionTensorPrincipalDirectionImageFilter() : m_NormalizeVectors(true) , m_UsePolarCoordinates(false) , m_FaThreshold(0.2) { this->SetNumberOfRequiredInputs( 1 ); - this->DynamicMultiThreadingOff(); + } template< class TTensorPixelType> void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType>::BeforeThreadedGenerateData() { typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); Vector spacing3 = inputImagePointer->GetSpacing(); mitk::Point3D origin3 = inputImagePointer->GetOrigin(); itk::Matrix direction3 = inputImagePointer->GetDirection(); ImageRegion<3> imageRegion3 = inputImagePointer->GetLargestPossibleRegion(); if (m_MaskImage.IsNull()) { m_MaskImage = ItkUcharImgType::New(); m_MaskImage->SetSpacing( spacing3 ); m_MaskImage->SetOrigin( origin3 ); m_MaskImage->SetDirection( direction3 ); m_MaskImage->SetRegions( imageRegion3 ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } typename OutputImageType::Pointer outputImage = OutputImageType::New(); outputImage->SetSpacing( spacing3 ); outputImage->SetOrigin( origin3 ); outputImage->SetDirection( direction3 ); outputImage->SetRegions( imageRegion3 ); outputImage->Allocate(); outputImage->FillBuffer(0); this->SetNthOutput(0, outputImage); itk::Vector spacing4; itk::Point origin4; itk::Matrix direction4; itk::ImageRegion<4> imageRegion4; spacing4[0] = spacing3[0]; spacing4[1] = spacing3[1]; spacing4[2] = spacing3[2]; spacing4[3] = 1; origin4[0] = origin3[0]; origin4[1] = origin3[1]; origin4[2] = origin3[2]; origin3[3] = 0; for (int r=0; r<3; r++) for (int c=0; c<3; c++) direction4[r][c] = direction3[r][c]; direction4[3][3] = 1; imageRegion4.SetSize(0, imageRegion3.GetSize()[0]); imageRegion4.SetSize(1, imageRegion3.GetSize()[1]); imageRegion4.SetSize(2, imageRegion3.GetSize()[2]); imageRegion4.SetSize(3, 3); m_PeakImage = PeakImageType::New(); m_PeakImage->SetSpacing( spacing4 ); m_PeakImage->SetOrigin( origin4 ); m_PeakImage->SetDirection( direction4 ); m_PeakImage->SetRegions( imageRegion4 ); m_PeakImage->Allocate(); m_PeakImage->FillBuffer(0.0); } template< class TTensorPixelType> void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType> ::AfterThreadedGenerateData() { } template< class TTensorPixelType> void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType> -::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) +::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread ) { typedef itk::DiffusionTensor3D TensorType; typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); ImageRegionIterator< OutputImageType > numDirectionsIterator(outputImage, outputRegionForThread); InputIteratorType tensorIterator(inputImagePointer, outputRegionForThread ); while( !tensorIterator.IsAtEnd() ) { typename InputImageType::IndexType index = tensorIterator.GetIndex(); if (m_MaskImage->GetPixel(index)==0) { ++tensorIterator; ++numDirectionsIterator; continue; } typename InputImageType::PixelType b = tensorIterator.Get(); TensorType tensor = b.GetDataPointer(); typename PeakImageType::IndexType peakIndex; peakIndex[0] = tensorIterator.GetIndex()[0]; peakIndex[1] = tensorIterator.GetIndex()[1]; peakIndex[2] = tensorIterator.GetIndex()[2]; typename TensorType::EigenValuesArrayType eigenvalues; typename TensorType::EigenVectorsMatrixType eigenvectors; if(tensor.GetTrace()!=0) { tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors); vnl_vector_fixed vec; vec[0] = eigenvectors(2,0); vec[1] = eigenvectors(2,1); vec[2] = eigenvectors(2,2); vec.normalize(); vnl_vector_fixed out; out.fill(0); float fa = tensor.GetFractionalAnisotropy(); if (faitk::Math::pi) { out[1] = out[1] - itk::Math::pi; } } else { out[0] = 0; out[1] = 0; out[2] = 0; } } else { out = vec; } } peakIndex[3] = 0; m_PeakImage->SetPixel(peakIndex, out[0]); peakIndex[3] = 1; m_PeakImage->SetPixel(peakIndex, out[1]); peakIndex[3] = 2; m_PeakImage->SetPixel(peakIndex, out[2]); numDirectionsIterator.Set( 1 ); } ++numDirectionsIterator; ++tensorIterator; } std::cout << "One Thread finished extraction" << std::endl; } template< class TTensorPixelType> void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType> ::PrintSelf(std::ostream& , Indent ) const { } } #endif diff --git a/Modules/DiffusionCore/Algorithms/itkDwiNormilzationFilter.h b/Modules/DiffusionCore/Algorithms/itkDwiNormilzationFilter.h index 4ffc8dd..68184b8 100644 --- a/Modules/DiffusionCore/Algorithms/itkDwiNormilzationFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkDwiNormilzationFilter.h @@ -1,101 +1,101 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkDwiNormilzationFilter_h_ #define __itkDwiNormilzationFilter_h_ #include "itkImageToImageFilter.h" #include "itkVectorImage.h" #include #include #include #include namespace itk{ /** \class DwiNormilzationFilter * \brief Normalizes the data vectors either using the specified reference value or the voxelwise baseline value. */ template< class TInPixelType > class DwiNormilzationFilter : public ImageToImageFilter< VectorImage< TInPixelType, 3 >, VectorImage< TInPixelType, 3 > > { public: typedef DwiNormilzationFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< TInPixelType, 3 >, VectorImage< TInPixelType, 3 > > Superclass; typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DwiNormilzationFilter, ImageToImageFilter) typedef itk::Image< double, 3 > DoubleImageType; typedef itk::Image< unsigned char, 3 > UcharImageType; typedef itk::Image< unsigned short, 3 > BinImageType; typedef itk::Image< TInPixelType, 3 > TInPixelImageType; typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer GradientContainerType; typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typedef ImageRegionConstIterator< UcharImageType > MaskIteratorType; itkSetMacro( GradientDirections, GradientContainerType ) itkSetMacro( ScalingFactor, TInPixelType ) itkSetMacro( MaskImage, UcharImageType::Pointer ) itkSetMacro( NewMean, double ) itkSetMacro( NewStdev, double ) protected: DwiNormilzationFilter(); ~DwiNormilzationFilter() {} void PrintSelf(std::ostream& os, Indent indent) const; void BeforeThreadedGenerateData(); - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType); + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread); UcharImageType::Pointer m_MaskImage; GradientContainerType m_GradientDirections; int m_B0Index; TInPixelType m_ScalingFactor; double m_Mean; double m_Stdev; double m_NewMean; double m_NewStdev; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkDwiNormilzationFilter.txx" #endif #endif //__itkDwiNormilzationFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/itkDwiNormilzationFilter.txx b/Modules/DiffusionCore/Algorithms/itkDwiNormilzationFilter.txx index 165d52e..5b5e29e 100644 --- a/Modules/DiffusionCore/Algorithms/itkDwiNormilzationFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkDwiNormilzationFilter.txx @@ -1,185 +1,185 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkDwiNormilzationFilter_txx #define __itkDwiNormilzationFilter_txx #include #include #include #define _USE_MATH_DEFINES #include #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" #include namespace itk { template< class TInPixelType > DwiNormilzationFilter< TInPixelType>::DwiNormilzationFilter() : m_B0Index(-1) , m_NewMean(1000) , m_NewStdev(500) { this->SetNumberOfRequiredInputs( 1 ); - this->DynamicMultiThreadingOff(); + } template< class TInPixelType > void DwiNormilzationFilter< TInPixelType>::BeforeThreadedGenerateData() { typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); m_B0Index = -1; for (unsigned int i=0; iGetVectorLength(); i++) { GradientDirectionType g = m_GradientDirections->GetElement(i); if (g.magnitude()<0.001) m_B0Index = i; } if (m_B0Index==-1) itkExceptionMacro(<< "DwiNormilzationFilter: No b-Zero indecies found!"); if (m_MaskImage.IsNull()) { // initialize mask image m_MaskImage = UcharImageType::New(); m_MaskImage->SetSpacing( inputImagePointer->GetSpacing() ); m_MaskImage->SetOrigin( inputImagePointer->GetOrigin() ); m_MaskImage->SetDirection( inputImagePointer->GetDirection() ); m_MaskImage->SetRegions( inputImagePointer->GetLargestPossibleRegion() ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } else std::cout << "DwiNormilzationFilter: using mask image" << std::endl; InputIteratorType git( inputImagePointer, inputImagePointer->GetLargestPossibleRegion() ); MaskIteratorType mit( m_MaskImage, m_MaskImage->GetLargestPossibleRegion() ); git.GoToBegin(); mit.GoToBegin(); int n = 0; m_Mean = 0; m_Stdev = 0; while( !git.IsAtEnd() ) { if (mit.Get()>0) { for (unsigned int i=0; iGetVectorLength(); i++) { if ((int)i==m_B0Index) continue; m_Mean += git.Get()[i]; n++; } } ++git; ++mit; } m_Mean /= n; git.GoToBegin(); mit.GoToBegin(); while( !git.IsAtEnd() ) { if (mit.Get()>0) { for (unsigned int i=0; iGetVectorLength(); i++) { if ((int)i==m_B0Index) continue; double diff = (double)(git.Get()[i]) - m_Mean; m_Stdev += diff*diff; } } ++git; ++mit; } m_Stdev = std::sqrt(m_Stdev/(n-1)); MITK_INFO << "Mean: " << m_Mean; MITK_INFO << "Stdev: " << m_Stdev; } template< class TInPixelType > -void DwiNormilzationFilter< TInPixelType>::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) +void DwiNormilzationFilter< TInPixelType>::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread ) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); MaskIteratorType mit( m_MaskImage, outputRegionForThread ); mit.GoToBegin(); InputIteratorType git( inputImagePointer, outputRegionForThread ); git.GoToBegin(); while( !git.IsAtEnd() ) { typename InputImageType::PixelType pix = git.Get(); typename OutputImageType::PixelType outPix; outPix.SetSize(inputImagePointer->GetVectorLength()); for (unsigned int i=0; iGetVectorLength(); i++) { double val = (double)pix[i] - m_Mean; val /= m_Stdev; val *= m_NewStdev; val += m_NewMean; if (val<0) { val = 0; MITK_INFO << "Negative value."; } if (val>32767) { val = 32767; MITK_INFO << "Range overflow. Value is too large for datatype short."; } outPix[i] = (TInPixelType)val; } oit.Set(outPix); ++mit; ++oit; ++git; } std::cout << "One Thread finished calculation" << std::endl; } template< class TInPixelType > void DwiNormilzationFilter< TInPixelType> ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); } } #endif // __itkDwiNormilzationFilter_txx diff --git a/Modules/DiffusionCore/Algorithms/itkExtractDwiChannelFilter.h b/Modules/DiffusionCore/Algorithms/itkExtractDwiChannelFilter.h index afc1834..b2d5471 100644 --- a/Modules/DiffusionCore/Algorithms/itkExtractDwiChannelFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkExtractDwiChannelFilter.h @@ -1,77 +1,77 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkExtractDwiChannelFilter_h_ #define __itkExtractDwiChannelFilter_h_ #include "itkImageToImageFilter.h" #include "itkVectorImage.h" #include #include namespace itk{ /** \class ExtractDwiChannelFilter * \brief Remove specified channels from diffusion-weighted image. */ template< class TInPixelType > class ExtractDwiChannelFilter : public ImageToImageFilter< VectorImage< TInPixelType, 3 >, Image< TInPixelType, 3 > > { public: typedef ExtractDwiChannelFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< TInPixelType, 3 >, Image< TInPixelType, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(ExtractDwiChannelFilter, ImageToImageFilter) typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; itkSetMacro( ChannelIndex, unsigned int ) protected: ExtractDwiChannelFilter(); ~ExtractDwiChannelFilter() override {} void BeforeThreadedGenerateData() override; - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType ) override; + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread ) override; unsigned int m_ChannelIndex; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkExtractDwiChannelFilter.txx" #endif #endif //__itkExtractDwiChannelFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/itkExtractDwiChannelFilter.txx b/Modules/DiffusionCore/Algorithms/itkExtractDwiChannelFilter.txx index 2af8a0a..af4e303 100644 --- a/Modules/DiffusionCore/Algorithms/itkExtractDwiChannelFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkExtractDwiChannelFilter.txx @@ -1,73 +1,73 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkExtractDwiChannelFilter_txx #define __itkExtractDwiChannelFilter_txx #include #include #include #define _USE_MATH_DEFINES #include #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" namespace itk { template< class TInPixelType > ExtractDwiChannelFilter< TInPixelType>::ExtractDwiChannelFilter() { this->SetNumberOfRequiredInputs( 1 ); - this->DynamicMultiThreadingOff(); + } template< class TInPixelType > void ExtractDwiChannelFilter< TInPixelType>::BeforeThreadedGenerateData() { typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); if ( inputImagePointer->GetVectorLength()<=m_ChannelIndex ) itkExceptionMacro("Index out of bounds!"); } template< class TInPixelType > -void ExtractDwiChannelFilter< TInPixelType>::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) +void ExtractDwiChannelFilter< TInPixelType>::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread ) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); InputIteratorType git( inputImagePointer, outputRegionForThread ); git.GoToBegin(); while( !git.IsAtEnd() ) { oit.Set( git.Get()[m_ChannelIndex] ); ++oit; ++git; } } } #endif // __itkExtractDwiChannelFilter_txx diff --git a/Modules/DiffusionCore/Algorithms/itkFlipPeaksFilter.cpp b/Modules/DiffusionCore/Algorithms/itkFlipPeaksFilter.cpp index 60b9e96..f79c134 100644 --- a/Modules/DiffusionCore/Algorithms/itkFlipPeaksFilter.cpp +++ b/Modules/DiffusionCore/Algorithms/itkFlipPeaksFilter.cpp @@ -1,101 +1,101 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkFlipPeaksFilter_cpp #define __itkFlipPeaksFilter_cpp #include "itkFlipPeaksFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace boost::math; namespace itk { template< class PixelType > FlipPeaksFilter< PixelType>::FlipPeaksFilter() { this->SetNumberOfRequiredInputs(1); - this->DynamicMultiThreadingOff(); + } template< class PixelType > void FlipPeaksFilter< PixelType> ::BeforeThreadedGenerateData() { typename InputImageType::Pointer input = static_cast< InputImageType* >( this->ProcessObject::GetInput(0) ); // typename OutputImageType::Pointer output = OutputImageType::New(); // output->SetSpacing( input->GetSpacing() ); // output->SetOrigin( input->GetOrigin() ); // output->SetDirection( input->GetDirection() ); // output->SetRegions( input->GetLargestPossibleRegion() ); // output->Allocate(); // output->FillBuffer(0.0); } template< class PixelType > void FlipPeaksFilter< PixelType> ::AfterThreadedGenerateData() { } template< class PixelType > void FlipPeaksFilter< PixelType> -::ThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, ThreadIdType ) +::DynamicThreadedGenerateData( const OutputImageRegionType& outputRegionForThread ) { typename InputImageType::Pointer input_image = static_cast< InputImageType* >( this->ProcessObject::GetInput(0) ); typename OutputImageType::Pointer output_image = static_cast< OutputImageType* >( this->ProcessObject::GetOutput(0) ); ImageRegionIterator< InputImageType > iit(input_image, outputRegionForThread ); ImageRegionIterator< OutputImageType > oit(output_image, outputRegionForThread ); while( !iit.IsAtEnd() ) { typename InputImageType::IndexType idx = iit.GetIndex(); oit.Set(iit.Get()); if (m_FlipX && idx[3]%3==0) oit.Set(-1*iit.Get()); if (m_FlipY && idx[3]%3==1) oit.Set(-1*iit.Get()); if (m_FlipZ && idx[3]%3==2) oit.Set(-1*iit.Get()); ++iit; ++oit; } } } #endif // __itkFlipPeaksFilter_cpp diff --git a/Modules/DiffusionCore/Algorithms/itkFlipPeaksFilter.h b/Modules/DiffusionCore/Algorithms/itkFlipPeaksFilter.h index 7caa0d4..560217f 100644 --- a/Modules/DiffusionCore/Algorithms/itkFlipPeaksFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkFlipPeaksFilter.h @@ -1,83 +1,83 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkFlipPeaksFilter_h_ #define __itkFlipPeaksFilter_h_ #include "itkImageToImageFilter.h" #include "vnl/vnl_vector_fixed.h" #include "vnl/vnl_matrix.h" #include "vnl/algo/vnl_svd.h" #include "itkVectorContainer.h" #include "itkVectorImage.h" #include #include #include namespace itk{ /** * \brief Flip peaks along specified axes */ template< class PixelType > class FlipPeaksFilter : public ImageToImageFilter< mitk::PeakImage::ItkPeakImageType, mitk::PeakImage::ItkPeakImageType > { public: typedef FlipPeaksFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< mitk::PeakImage::ItkPeakImageType, mitk::PeakImage::ItkPeakImageType > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(FlipPeaksFilter, ImageToImageFilter) typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename OutputImageType::RegionType OutputImageRegionType; itkSetMacro( FlipX, bool) ///< flip peaks in x direction itkSetMacro( FlipY, bool) ///< flip peaks in y direction itkSetMacro( FlipZ, bool) ///< flip peaks in z direction protected: FlipPeaksFilter(); ~FlipPeaksFilter(){} void BeforeThreadedGenerateData(); - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadID ); + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread); void AfterThreadedGenerateData(); private: bool m_FlipX; bool m_FlipY; bool m_FlipZ; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkFlipPeaksFilter.cpp" #endif #endif //__itkFlipPeaksFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/itkNonLocalMeansDenoisingFilter.h b/Modules/DiffusionCore/Algorithms/itkNonLocalMeansDenoisingFilter.h index 1fed001..39d22c9 100644 --- a/Modules/DiffusionCore/Algorithms/itkNonLocalMeansDenoisingFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkNonLocalMeansDenoisingFilter.h @@ -1,145 +1,145 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkNonLocalMeansDenoisingFilter_h_ #define __itkNonLocalMeansDenoisingFilter_h_ #include "itkImageToImageFilter.h" #include "itkVectorImage.h" namespace itk{ /** @class NonLocalMeansDenoisingFilter * @brief This class denoises a vectorimage according to the non-local means procedure. * * This Filter needs as an input a diffusion weigthed image, which will be denoised unsing the non-local means principle. * An input mask is optional to denoise only inside the mask range. All other voxels will be set to 0. */ template< class TPixelType > class NonLocalMeansDenoisingFilter : public ImageToImageFilter< VectorImage < TPixelType, 3 >, VectorImage < TPixelType, 3 > > { public: /** Typedefs */ typedef NonLocalMeansDenoisingFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage < TPixelType, 3 >, VectorImage < TPixelType, 3 > > Superclass; typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef Image MaskImageType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(NonLocalMeansDenoisingFilter, ImageToImageFilter) /** * @brief Set flag to use joint information */ itkSetMacro(UseJointInformation, bool) /** * @brief Set the searchradius * * The searchradius generates a neighborhood of size (2 * searchradius + 1)³. * Default is 4. */ itkSetMacro(SearchRadius, int) /** * @brief Set the comparisonradius * * The comparisonradius generates neighborhoods of size (2 * comparisonradius +1)³. * Default is 1. */ itkSetMacro(ComparisonRadius, int) /** * @brief Set the variance of the noise * * The variance of the noise needs to be estimated to use this filter properly. * Default is 1. */ itkSetMacro(Variance, double) /** * @brief Set flag to use a rician adaption * * If this flag is true the filter uses a method which is optimized for Rician distributed noise. */ itkSetMacro(UseRicianAdaption, bool) /** * @brief Get the amount of calculated Voxels * * @return the number of calculated Voxels until yet, useful for the use of a progressbars. */ itkGetMacro(CurrentVoxelCount, unsigned int) /** @brief Set the input image. **/ void SetInputImage(const InputImageType* image); /** * @brief Set a denoising mask * * optional * * Set a mask to denoise only the masked area, all voxel outside this area will be set to 0. */ void SetInputMask(MaskImageType* mask); protected: NonLocalMeansDenoisingFilter(); ~NonLocalMeansDenoisingFilter() override {} /** * @brief Calculations which need to be done before the denoising starts * * This method is called before the denoising starts. It calculates the ROI if a mask is used * and sets the number of processed voxels to zero. */ void BeforeThreadedGenerateData() override; /** * @brief Denoising procedure * * This method calculates the denoised voxelvalue for each voxel in the image in multiple threads. * If a mask is used, voxels outside the masked area will be set to 0. * * @param outputRegionForThread Region to denoise for each thread. */ - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType) override; + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread) override; private: int m_SearchRadius; ///< Radius of the searchblock. int m_ComparisonRadius; ///< Radius of the comparisonblock. bool m_UseJointInformation; ///< Flag to use joint information. bool m_UseRicianAdaption; ///< Flag to use rician adaption. unsigned int m_CurrentVoxelCount; ///< Amount of processed voxels. double m_Variance; ///< Estimated noise variance. typename MaskImageType::Pointer m_Mask; ///< Pointer to the mask image. }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkNonLocalMeansDenoisingFilter.txx" #endif #endif //__itkNonLocalMeansDenoisingFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/itkNonLocalMeansDenoisingFilter.txx b/Modules/DiffusionCore/Algorithms/itkNonLocalMeansDenoisingFilter.txx index 51ec43b..5f42864 100644 --- a/Modules/DiffusionCore/Algorithms/itkNonLocalMeansDenoisingFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkNonLocalMeansDenoisingFilter.txx @@ -1,390 +1,390 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkNonLocalMeansDenoisingFilter_txx #define __itkNonLocalMeansDenoisingFilter_txx #include #include #include #define _USE_MATH_DEFINES #include #include "itkImageRegionIterator.h" #include "itkNeighborhoodIterator.h" #include #include namespace itk { template< class TPixelType > NonLocalMeansDenoisingFilter< TPixelType > ::NonLocalMeansDenoisingFilter() : m_SearchRadius(4), m_ComparisonRadius(1), m_UseJointInformation(false), m_UseRicianAdaption(false), m_Variance(1), m_Mask(nullptr) { this->SetNumberOfRequiredInputs( 1 ); - this->DynamicMultiThreadingOff(); + } template< class TPixelType > void NonLocalMeansDenoisingFilter< TPixelType > ::BeforeThreadedGenerateData() { MITK_INFO << "SearchRadius: " << m_SearchRadius; MITK_INFO << "ComparisonRadius: " << m_ComparisonRadius; MITK_INFO << "Noisevariance: " << m_Variance; MITK_INFO << "Use Rician Adaption: " << std::boolalpha << m_UseRicianAdaption; MITK_INFO << "Use Joint Information: " << std::boolalpha << m_UseJointInformation; typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); if (m_Mask.IsNull()) { // If no mask is used generate a mask of the complete image m_Mask = MaskImageType::New(); m_Mask->SetRegions(inputImagePointer->GetLargestPossibleRegion()); m_Mask->Allocate(); m_Mask->FillBuffer(1); } else { // Calculation of the smallest masked region typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outputImage, inputImagePointer->GetLargestPossibleRegion()); oit.GoToBegin(); ImageRegionIterator< MaskImageType > mit(m_Mask, m_Mask->GetLargestPossibleRegion()); mit.GoToBegin(); typename MaskImageType::IndexType minIndex; typename MaskImageType::IndexType maxIndex; minIndex.Fill(10000); maxIndex.Fill(0); typename OutputImageType::PixelType outpix; outpix.SetSize(inputImagePointer->GetVectorLength()); outpix.Fill(0); while (!mit.IsAtEnd()) { if (mit.Get()) { // calculation of the start & end index of the smallest masked region minIndex[0] = minIndex[0] < mit.GetIndex()[0] ? minIndex[0] : mit.GetIndex()[0]; minIndex[1] = minIndex[1] < mit.GetIndex()[1] ? minIndex[1] : mit.GetIndex()[1]; minIndex[2] = minIndex[2] < mit.GetIndex()[2] ? minIndex[2] : mit.GetIndex()[2]; maxIndex[0] = maxIndex[0] > mit.GetIndex()[0] ? maxIndex[0] : mit.GetIndex()[0]; maxIndex[1] = maxIndex[1] > mit.GetIndex()[1] ? maxIndex[1] : mit.GetIndex()[1]; maxIndex[2] = maxIndex[2] > mit.GetIndex()[2] ? maxIndex[2] : mit.GetIndex()[2]; } else { oit.Set(outpix); } ++mit; ++oit; } // calculation of the masked region typename OutputImageType::SizeType size; size[0] = maxIndex[0] - minIndex[0] + 1; size[1] = maxIndex[1] - minIndex[1] + 1; size[2] = maxIndex[2] - minIndex[2] + 1; typename OutputImageType::RegionType region (minIndex, size); outputImage->SetRequestedRegion(region); } m_CurrentVoxelCount = 0; } template< class TPixelType > void NonLocalMeansDenoisingFilter< TPixelType > -::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) +::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread ) { // initialize iterators typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); ImageRegionIterator< MaskImageType > mit(m_Mask, outputRegionForThread); mit.GoToBegin(); typedef ImageRegionIteratorWithIndex InputIteratorType; typename InputImageType::Pointer inputImagePointer = nullptr; inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); InputIteratorType git(inputImagePointer, outputRegionForThread ); git.GoToBegin(); // iterate over complete image region while( !git.IsAtEnd() ) { typename OutputImageType::PixelType outpix; outpix.SetSize (inputImagePointer->GetVectorLength()); if (mit.Get() != 0 && !this->GetAbortGenerateData()) { if(!m_UseJointInformation) { for (int i = 0; i < (int)inputImagePointer->GetVectorLength(); ++i) { double summw = 0; double sumj = 0; double w = 0; std::vector wj; std::vector p; typename InputIteratorType::IndexType index; index = git.GetIndex(); for (int x = index.GetElement(0) - m_SearchRadius; x <= index.GetElement(0) + m_SearchRadius; ++x) { for (int y = index.GetElement(1) - m_SearchRadius; y <= index.GetElement(1) + m_SearchRadius; ++y) { for (int z = index.GetElement(2) - m_SearchRadius; z <= index.GetElement(2) + m_SearchRadius; ++z) { typename InputIteratorType::IndexType indexV; indexV.SetElement(0, x); indexV.SetElement(1, y); indexV.SetElement(2, z); if (inputImagePointer->GetLargestPossibleRegion().IsInside(indexV)) { TPixelType pixelJ = inputImagePointer->GetPixel(indexV)[i]; double sumk = 0; double size = 0; for (int xi = index.GetElement(0) - m_ComparisonRadius, xj = x - m_ComparisonRadius; xi <= index.GetElement(0) + m_ComparisonRadius; ++xi, ++xj) { for (int yi = index.GetElement(1) - m_ComparisonRadius, yj = y - m_ComparisonRadius; yi <= index.GetElement(1) + m_ComparisonRadius; ++yi, ++yj) { for (int zi = index.GetElement(2) - m_ComparisonRadius, zj = z - m_ComparisonRadius; zi <= index.GetElement(2) + m_ComparisonRadius; ++zi, ++zj) { typename InputIteratorType::IndexType indexI, indexJ; indexI.SetElement(0, xi); indexI.SetElement(1, yi); indexI.SetElement(2, zi); indexJ.SetElement(0, xj); indexJ.SetElement(1, yj); indexJ.SetElement(2, zj); // Compare neighborhoods ni & nj if (inputImagePointer->GetLargestPossibleRegion().IsInside(indexI) && inputImagePointer->GetLargestPossibleRegion().IsInside(indexJ)) { int diff = inputImagePointer->GetPixel(indexI)[i] - inputImagePointer->GetPixel(indexJ)[i]; sumk += (double)(diff*diff); ++size; } } } } // weight all neighborhoods w = std::exp( - sumk / size / m_Variance); wj.push_back(w); if (m_UseRicianAdaption) { p.push_back((double)(pixelJ*pixelJ)); } else { p.push_back((double)(pixelJ)); } summw += w; } } } } for (unsigned int n = 0; n < wj.size(); ++n) { sumj += (wj[n]/summw) * p[n]; } if (m_UseRicianAdaption) { sumj -=2 * m_Variance; } if (sumj < 0) { sumj = 0; } TPixelType outval; if (m_UseRicianAdaption) { outval = std::floor(std::sqrt(sumj) + 0.5); } else { outval = std::floor(sumj + 0.5); } outpix.SetElement(i, outval); } } else { // same procedure for vektoranalysis double Z = 0; itk::VariableLengthVector sumj; sumj.SetSize(inputImagePointer->GetVectorLength()); sumj.Fill(0.0); double w = 0; std::vector wj; std::vector > p; typename InputIteratorType::IndexType index; index = git.GetIndex(); for (int x = index.GetElement(0) - m_SearchRadius; x <= index.GetElement(0) + m_SearchRadius; ++x) { for (int y = index.GetElement(1) - m_SearchRadius; y <= index.GetElement(1) + m_SearchRadius; ++y) { for (int z = index.GetElement(2) - m_SearchRadius; z <= index.GetElement(2) + m_SearchRadius; ++z) { typename InputIteratorType::IndexType indexV; indexV.SetElement(0, x); indexV.SetElement(1, y); indexV.SetElement(2, z); if (inputImagePointer->GetLargestPossibleRegion().IsInside(indexV)) { typename InputImageType::PixelType pixelJ = inputImagePointer->GetPixel(indexV); double sumk = 0; double size = 0; for (int xi = index.GetElement(0) - m_ComparisonRadius, xj = x - m_ComparisonRadius; xi <= index.GetElement(0) + m_ComparisonRadius; ++xi, ++xj) { for (int yi = index.GetElement(1) - m_ComparisonRadius, yj = y - m_ComparisonRadius; yi <= index.GetElement(1) + m_ComparisonRadius; ++yi, ++yj) { for (int zi = index.GetElement(2) - m_ComparisonRadius, zj = z - m_ComparisonRadius; zi <= index.GetElement(2) + m_ComparisonRadius; ++zi, ++zj) { typename InputIteratorType::IndexType indexI, indexJ; indexI.SetElement(0, xi); indexI.SetElement(1, yi); indexI.SetElement(2, zi); indexJ.SetElement(0, xj); indexJ.SetElement(1, yj); indexJ.SetElement(2, zj); // Compare neighborhoods ni & nj if (inputImagePointer->GetLargestPossibleRegion().IsInside(indexI) && inputImagePointer->GetLargestPossibleRegion().IsInside(indexJ)) { typename InputImageType::PixelType diff = inputImagePointer->GetPixel(indexI) - inputImagePointer->GetPixel(indexJ); sumk += (double)(diff.GetSquaredNorm()); ++size; } } } } // weight all neighborhoods size *= inputImagePointer->GetVectorLength() + 1; w = std::exp( - (sumk / size) / m_Variance); wj.push_back(w); if (m_UseRicianAdaption) { itk::VariableLengthVector m; m.SetSize(inputImagePointer->GetVectorLength()); for (unsigned int i = 0; i < inputImagePointer->GetVectorLength(); ++i) { double sp = (double)(pixelJ.GetElement(i) * pixelJ.GetElement(i)); m.SetElement(i,sp); } p.push_back(m); } else ++size; { p.push_back(pixelJ); } Z += w; } } } } for (unsigned int n = 0; n < wj.size(); ++n) { sumj = sumj + ((wj[n]/Z) * p[n]); } if (m_UseRicianAdaption) { sumj = sumj - (2 * m_Variance); } for (unsigned int i = 0; i < inputImagePointer->GetVectorLength(); ++i) { double a = sumj.GetElement(i); if (a < 0) { a = 0; } TPixelType outval; if (m_UseRicianAdaption) { outval = std::floor(std::sqrt(a) + 0.5); } else { outval = std::floor(a + 0.5); } outpix.SetElement(i, outval); } } } else { outpix.Fill(0); } oit.Set(outpix); ++oit; ++m_CurrentVoxelCount; ++git; ++mit; } MITK_INFO << "One Thread finished calculation"; } template< class TPixelType > void NonLocalMeansDenoisingFilter< TPixelType >::SetInputImage(const InputImageType* image) { this->SetNthInput(0, const_cast< InputImageType* >(image)); } template< class TPixelType > void NonLocalMeansDenoisingFilter< TPixelType >::SetInputMask(MaskImageType* mask) { m_Mask = mask; } } #endif // __itkNonLocalMeansDenoisingFilter_txx diff --git a/Modules/DiffusionCore/Algorithms/itkOdfMaximaExtractionFilter.cpp b/Modules/DiffusionCore/Algorithms/itkOdfMaximaExtractionFilter.cpp index 497f24a..1a8e145 100644 --- a/Modules/DiffusionCore/Algorithms/itkOdfMaximaExtractionFilter.cpp +++ b/Modules/DiffusionCore/Algorithms/itkOdfMaximaExtractionFilter.cpp @@ -1,364 +1,364 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkOdfMaximaExtractionFilter_cpp #define __itkOdfMaximaExtractionFilter_cpp #include "itkOdfMaximaExtractionFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace boost::math; namespace itk { static bool CompareVectors(const vnl_vector_fixed< double, 3 >& v1, const vnl_vector_fixed< double, 3 >& v2) { return (v1.magnitude()>v2.magnitude()); } template< class PixelType, int ShOrder, int NrOdfDirections > OdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::OdfMaximaExtractionFilter() : m_NormalizationMethod(MAX_VEC_NORM) , m_MaxNumPeaks(2) , m_RelativePeakThreshold(0.4) , m_AbsolutePeakThreshold(0) , m_AngularThreshold(0.9) , m_NumCoeffs((ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder) , m_Toolkit(MRTRIX) , m_FlipX(false) , m_FlipY(false) , m_FlipZ(false) , m_ApplyDirectionMatrix(false) , m_ScaleByGfa(false) , m_Iterations(10) { this->SetNumberOfRequiredInputs(1); - this->DynamicMultiThreadingOff(); + } template< class PixelType, int ShOrder, int NrOdfDirections > double OdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::FindCandidatePeaks(OdfType& odf, double thr, std::vector< DirectionType >& container) { double gfa = 1.0; if (m_ScaleByGfa) gfa = odf.GetGeneralizedFractionalAnisotropy(); //Find the peaks using a finite difference method bool flag = true; vnl_vector_fixed< bool, NrOdfDirections > used; used.fill(false); //Find the peaks for (int i=0; ithr*0.9 && gfa*val>m_AbsolutePeakThreshold*0.9) { flag = true; std::vector< int > neighbours = odf.GetNeighbors(i); for (unsigned int j=0; j void OdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::BeforeThreadedGenerateData() { typename CoefficientImageType::Pointer ShCoeffImage = static_cast< CoefficientImageType* >( this->ProcessObject::GetInput(0) ); itk::Vector spacing = ShCoeffImage->GetSpacing(); double minSpacing = spacing[0]; if (spacing[1]GetOrigin(); itk::Matrix direction = ShCoeffImage->GetDirection(); ImageRegion<3> imageRegion = ShCoeffImage->GetLargestPossibleRegion(); if (m_MaskImage.IsNotNull()) { origin = m_MaskImage->GetOrigin(); direction = m_MaskImage->GetDirection(); imageRegion = m_MaskImage->GetLargestPossibleRegion(); } itk::Vector spacing3 = ShCoeffImage->GetSpacing(); itk::Point origin3 = ShCoeffImage->GetOrigin(); itk::Matrix direction3 = ShCoeffImage->GetDirection(); itk::ImageRegion<3> imageRegion3 = ShCoeffImage->GetLargestPossibleRegion(); itk::Vector spacing4; itk::Point origin4; itk::Matrix direction4; itk::ImageRegion<4> imageRegion4; spacing4[0] = spacing3[0]; spacing4[1] = spacing3[1]; spacing4[2] = spacing3[2]; spacing4[3] = 1; origin4[0] = origin3[0]; origin4[1] = origin3[1]; origin4[2] = origin3[2]; origin4[3] = 0; for (int r=0; r<3; r++) for (int c=0; c<3; c++) direction4[r][c] = direction3[r][c]; direction4[3][3] = 1; imageRegion4.SetSize(0, imageRegion3.GetSize()[0]); imageRegion4.SetSize(1, imageRegion3.GetSize()[1]); imageRegion4.SetSize(2, imageRegion3.GetSize()[2]); imageRegion4.SetSize(3, m_MaxNumPeaks*3); m_PeakImage = PeakImageType::New(); m_PeakImage->SetSpacing( spacing4 ); m_PeakImage->SetOrigin( origin4 ); m_PeakImage->SetDirection( direction4 ); m_PeakImage->SetRegions( imageRegion4 ); m_PeakImage->Allocate(); m_PeakImage->FillBuffer(0.0); if (m_MaskImage.IsNull()) { m_MaskImage = ItkUcharImgType::New(); m_MaskImage->SetSpacing( spacing ); m_MaskImage->SetOrigin( origin ); m_MaskImage->SetDirection( direction ); m_MaskImage->SetRegions( imageRegion ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } m_NumDirectionsImage = ItkUcharImgType::New(); m_NumDirectionsImage->SetSpacing( spacing ); m_NumDirectionsImage->SetOrigin( origin ); m_NumDirectionsImage->SetDirection( direction ); m_NumDirectionsImage->SetRegions( imageRegion ); m_NumDirectionsImage->Allocate(); m_NumDirectionsImage->FillBuffer(0); // calculate SH basis OdfType odf; vnl_matrix< double > dir_matrix; dir_matrix.set_size(3, NrOdfDirections); for (int i=0; iSetNumberOfWorkUnits(1); } template< class PixelType, int ShOrder, int NrOdfDirections > void OdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::AfterThreadedGenerateData() { } template< class PixelType, int ShOrder, int NrOdfDirections > void OdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> -::ThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, ThreadIdType threadID ) +::DynamicThreadedGenerateData( const OutputImageRegionType& outputRegionForThread) { typename CoefficientImageType::Pointer ShCoeffImage = static_cast< CoefficientImageType* >( this->ProcessObject::GetInput(0) ); ImageRegionConstIterator< CoefficientImageType > cit(ShCoeffImage, outputRegionForThread ); boost::progress_display disp(outputRegionForThread.GetSize()[0]*outputRegionForThread.GetSize()[1]*outputRegionForThread.GetSize()[2]); OdfType odf; while( !cit.IsAtEnd() ) { typename CoefficientImageType::IndexType idx3 = cit.GetIndex(); if (m_MaskImage->GetPixel(idx3)==0) { ++disp; ++cit; continue; } CoefficientPixelType c = cit.Get(); vnl_vector coeffs; coeffs.set_size((ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder); for (int j=0; jmax) max = odf[i]; } if (max<0.0001) { ++disp; ++cit; continue; } std::vector< DirectionType > candidates, final_peaks; double scale = FindCandidatePeaks(odf, max*m_RelativePeakThreshold, candidates); // find all local maxima max = 0; for (unsigned int i=0; i x; x.set_size(2); x[0] = spherical[1]; // theta x[1] = spherical[0]; // phi VnlCostFunction cost; if (m_Toolkit==Toolkit::MRTRIX) cost.SetProblem(coeffs, ShOrder, true, max); else cost.SetProblem(coeffs, ShOrder, false, max); vnl_lbfgsb minimizer(cost); minimizer.set_f_tolerance(1e-6); // minimizer.set_trace(true); vnl_vector l; l.set_size(2); l[0] = 0; l[1] = -itk::Math::pi; vnl_vector u; u.set_size(2); u[0] = itk::Math::pi; u[1] = itk::Math::pi; vnl_vector bound_selection; bound_selection.set_size(2); bound_selection.fill(2); minimizer.set_bound_selection(bound_selection); minimizer.set_lower_bound(l); minimizer.set_upper_bound(u); if (m_Iterations>0) minimizer.set_max_function_evals(m_Iterations); minimizer.minimize(x); float v = -minimizer.get_end_error()*scale; candidates[i] = mitk::sh::Sph2Cart(x[0], x[1], v); if (v>max) max = v; } std::sort( candidates.begin(), candidates.end(), CompareVectors ); // sort peaks // kick out directions to close to a larger direction for (unsigned int i=0; im_AngularThreshold && val idx4; idx4[0] = idx3[0]; idx4[1] = idx3[1]; idx4[2] = idx3[2]; // fill output image unsigned int num = final_peaks.size(); if ( num>m_MaxNumPeaks ) num = m_MaxNumPeaks; for (unsigned int i=0; iGetDirection()*dir; if (m_FlipX) dir[0] = -dir[0]; if (m_FlipY) dir[1] = -dir[1]; if (m_FlipZ) dir[2] = -dir[2]; for (unsigned int j = 0; j<3; j++) { idx4[3] = i*3 + j; m_PeakImage->SetPixel(idx4, dir[j]); } } m_NumDirectionsImage->SetPixel(idx3, num); ++disp; ++cit; } - MITK_INFO << "Thread " << threadID << " finished extraction"; + MITK_INFO << "One thread finished extraction"; } } #endif // __itkOdfMaximaExtractionFilter_cpp diff --git a/Modules/DiffusionCore/Algorithms/itkOdfMaximaExtractionFilter.h b/Modules/DiffusionCore/Algorithms/itkOdfMaximaExtractionFilter.h index f806907..0a614ee 100644 --- a/Modules/DiffusionCore/Algorithms/itkOdfMaximaExtractionFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkOdfMaximaExtractionFilter.h @@ -1,181 +1,181 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkOdfMaximaExtractionFilter_h_ #define __itkOdfMaximaExtractionFilter_h_ #include "itkImageToImageFilter.h" #include "vnl/vnl_vector_fixed.h" #include "vnl/vnl_matrix.h" #include "vnl/algo/vnl_svd.h" #include "itkVectorContainer.h" #include "itkVectorImage.h" #include #include #include #include #include #include class VnlCostFunction : public vnl_cost_function { public: bool mrtrix; int ShOrder; vnl_vector coeffs; double max; void SetProblem(vnl_vector& coeffs, int ShOrder, bool mrtrix, double max) { this->coeffs = coeffs; this->ShOrder = ShOrder; this->mrtrix = mrtrix; this->max = max; } VnlCostFunction(const int NumVars=2) : vnl_cost_function(NumVars) { } // cost function double f(vnl_vector const &x) { return -mitk::sh::GetValue(coeffs, ShOrder, x[0], x[1], mrtrix); } // gradient of cost function void gradf(vnl_vector const &x, vnl_vector &dx) { fdgradf(x, dx); } }; namespace itk{ /** * \brief Extract ODF peaks by searching all local maxima on a roughly sampled sphere and a successive gradient descent optimization */ template< class PixelType, int ShOrder, int NrOdfDirections > class OdfMaximaExtractionFilter : public ImageToImageFilter< Image< Vector< PixelType, (ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder >, 3 >, Image< unsigned char, 3 > > { public: enum Toolkit { ///< SH coefficient convention (depends on toolkit) FSL, MRTRIX }; enum NormalizationMethods { NO_NORM, ///< no length normalization of the output peaks SINGLE_VEC_NORM, ///< normalize the single peaks to length 1 MAX_VEC_NORM ///< normalize all peaks according to their length in comparison to the largest peak in the respective voxel (0-1) }; typedef OdfMaximaExtractionFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< Vector< PixelType, (ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder >, 3 >, Image< unsigned char, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(OdfMaximaExtractionFilter, ImageToImageFilter) typedef typename Superclass::InputImageType CoefficientImageType; typedef typename CoefficientImageType::RegionType CoefficientImageRegionType; typedef typename CoefficientImageType::PixelType CoefficientPixelType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef typename Superclass::InputImageRegionType InputImageRegionType; typedef mitk::PeakImage::ItkPeakImageType PeakImageType; typedef OrientationDistributionFunction OdfType; typedef itk::Image ItkUcharImgType; typedef vnl_vector_fixed< double, 3 > DirectionType; // input itkSetMacro( MaxNumPeaks, unsigned int) ///< maximum number of peaks per voxel. if more peaks are detected, only the largest are kept. itkSetMacro( RelativePeakThreshold, double) ///< threshold on the peak length relative to the largest peak inside the current voxel itkSetMacro( AbsolutePeakThreshold, double) ///< hard threshold on the peak length of all local maxima itkSetMacro( AngularThreshold, double) ///< directions closer together than the specified threshold are discarded itkSetMacro( MaskImage, ItkUcharImgType::Pointer) ///< only voxels inside the binary mask are processed itkSetMacro( NormalizationMethod, NormalizationMethods) ///< normalization method of ODF peaks itkSetMacro( FlipX, bool) ///< flip peaks in x direction itkSetMacro( FlipY, bool) ///< flip peaks in y direction itkSetMacro( FlipZ, bool) ///< flip peaks in z direction itkSetMacro( ApplyDirectionMatrix, bool) itkSetMacro( ScaleByGfa, bool) itkSetMacro( Iterations, int) // output itkGetMacro( NumDirectionsImage, ItkUcharImgType::Pointer ) itkGetMacro( PeakImage, PeakImageType::Pointer ) itkSetMacro( Toolkit, Toolkit) ///< define SH coefficient convention (depends on toolkit) itkGetMacro( Toolkit, Toolkit) ///< SH coefficient convention (depends on toolkit) protected: OdfMaximaExtractionFilter(); ~OdfMaximaExtractionFilter(){} void BeforeThreadedGenerateData(); - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadID ); + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread); void AfterThreadedGenerateData(); /** Extract all local maxima from the densely sampled ODF surface. Thresholding possible. **/ double FindCandidatePeaks(OdfType& odf, double odfMax, std::vector< DirectionType >& inDirs); /** Cluster input directions within a certain angular threshold **/ std::vector< DirectionType > MeanShiftClustering(std::vector< DirectionType >& inDirs); private: NormalizationMethods m_NormalizationMethod; ///< normalization method of ODF peaks unsigned int m_MaxNumPeaks; ///< maximum number of peaks per voxel. if more peaks are detected, only the largest are kept. double m_RelativePeakThreshold; ///< threshold on the peak length relative to the largest peak inside the current voxel double m_AbsolutePeakThreshold;///< hard threshold on the peak length of all local maxima vnl_matrix< float > m_ShBasis; ///< container for evaluated SH base functions double m_AngularThreshold; const int m_NumCoeffs; ///< number of spherical harmonics coefficients PeakImageType::Pointer m_PeakImage; ItkUcharImgType::Pointer m_NumDirectionsImage; ///< number of peaks per voxel ItkUcharImgType::Pointer m_MaskImage; ///< only voxels inside the binary mask are processed Toolkit m_Toolkit; bool m_FlipX; bool m_FlipY; bool m_FlipZ; bool m_ApplyDirectionMatrix; bool m_ScaleByGfa; int m_Iterations; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkOdfMaximaExtractionFilter.cpp" #endif #endif //__itkOdfMaximaExtractionFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMLocalVariationImageFilter.h b/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMLocalVariationImageFilter.h index 86dd916..312095e 100644 --- a/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMLocalVariationImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMLocalVariationImageFilter.h @@ -1,152 +1,151 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkRegularizedIVIMLocalVariationImageFilter_h #define __itkRegularizedIVIMLocalVariationImageFilter_h #include "itkImageToImageFilter.h" #include "itkImage.h" namespace itk { template class IVIMSquaredEuclideanMetric { public: static double Calc(TPixelType p) { return p*p; } }; template<> class IVIMSquaredEuclideanMetric > { public: static double Calc(itk::Vector p) { return p[1]*p[1]; } }; template<> class IVIMSquaredEuclideanMetric > { public: static double Calc(itk::VariableLengthVector p) { return p.GetSquaredNorm(); } }; template<> class IVIMSquaredEuclideanMetric > { public: static double Calc(itk::VariableLengthVector p) { return p.GetSquaredNorm(); } }; /** \class RegularizedIVIMLocalVariationImageFilter * \brief Calculates the local variation in each pixel * * Reference: Tony F. Chan et al., The digital TV filter and nonlinear denoising * * \sa Image * \sa Neighborhood * \sa NeighborhoodOperator * \sa NeighborhoodIterator * * \ingroup IntensityImageFilters */ template class RegularizedIVIMLocalVariationImageFilter : public ImageToImageFilter< TInputImage, TOutputImage > { public: /** Extract dimension from input and output image. */ itkStaticConstMacro(InputImageDimension, unsigned int, TInputImage::ImageDimension); itkStaticConstMacro(OutputImageDimension, unsigned int, TOutputImage::ImageDimension); /** Convenient typedefs for simplifying declarations. */ typedef TInputImage InputImageType; typedef TOutputImage OutputImageType; /** Standard class typedefs. */ typedef RegularizedIVIMLocalVariationImageFilter Self; typedef ImageToImageFilter< InputImageType, OutputImageType> Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Run-time type information (and related methods). */ itkTypeMacro(RegularizedIVIMLocalVariationImageFilter, ImageToImageFilter); /** Image typedef support. */ typedef typename InputImageType::PixelType InputPixelType; typedef typename OutputImageType::PixelType OutputPixelType; typedef typename InputImageType::RegionType InputImageRegionType; typedef typename OutputImageType::RegionType OutputImageRegionType; typedef typename InputImageType::SizeType InputSizeType; /** MedianImageFilter needs a larger input requested region than * the output requested region. As such, MedianImageFilter needs * to provide an implementation for GenerateInputRequestedRegion() * in order to inform the pipeline execution model. * * \sa ImageToImageFilter::GenerateInputRequestedRegion() */ virtual void GenerateInputRequestedRegion(); protected: RegularizedIVIMLocalVariationImageFilter(); virtual ~RegularizedIVIMLocalVariationImageFilter() {} void PrintSelf(std::ostream& os, Indent indent) const; /** MedianImageFilter can be implemented as a multithreaded filter. - * Therefore, this implementation provides a ThreadedGenerateData() + * Therefore, this implementation provides a DynamicThreadedGenerateData() * routine which is called for each processing thread. The output * image data is allocated automatically by the superclass prior to - * calling ThreadedGenerateData(). ThreadedGenerateData can only + * calling DynamicThreadedGenerateData(). DynamicThreadedGenerateData can only * write to the portion of the output image specified by the * parameter "outputRegionForThread" * - * \sa ImageToImageFilter::ThreadedGenerateData(), + * \sa ImageToImageFilter::DynamicThreadedGenerateData(), * ImageToImageFilter::GenerateData() */ - void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, - ThreadIdType threadId ); + void DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread); private: RegularizedIVIMLocalVariationImageFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkRegularizedIVIMLocalVariationImageFilter.txx" #endif #endif //RegularizedIVIMLocalVariationImageFilter diff --git a/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMLocalVariationImageFilter.txx b/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMLocalVariationImageFilter.txx index 35f1b39..35e78cd 100644 --- a/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMLocalVariationImageFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMLocalVariationImageFilter.txx @@ -1,194 +1,186 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _itkRegularizedIVIMLocalVariationImageFilter_txx #define _itkRegularizedIVIMLocalVariationImageFilter_txx #include "itkConstShapedNeighborhoodIterator.h" #include "itkNeighborhoodInnerProduct.h" #include "itkImageRegionIterator.h" #include "itkNeighborhoodAlgorithm.h" #include "itkZeroFluxNeumannBoundaryCondition.h" #include "itkOffset.h" #include "itkProgressReporter.h" #include "itkVectorImage.h" #include #include namespace itk { template RegularizedIVIMLocalVariationImageFilter ::RegularizedIVIMLocalVariationImageFilter() { - this->DynamicMultiThreadingOff(); + } template void RegularizedIVIMLocalVariationImageFilter ::GenerateInputRequestedRegion() { // call the superclass' implementation of this method Superclass::GenerateInputRequestedRegion(); // get pointers to the input and output typename Superclass::InputImagePointer inputPtr = const_cast< TInputImage * >( this->GetInput() ); typename Superclass::OutputImagePointer outputPtr = this->GetOutput(); if ( !inputPtr || !outputPtr ) { return; } // get a copy of the input requested region (should equal the output // requested region) typename TInputImage::RegionType inputRequestedRegion; inputRequestedRegion = inputPtr->GetRequestedRegion(); // pad the input requested region by 1 inputRequestedRegion.PadByRadius( 1 ); // crop the input requested region at the input's largest possible region if ( inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion()) ) { inputPtr->SetRequestedRegion( inputRequestedRegion ); return; } else { // Couldn't crop the region (requested region is outside the largest // possible region). Throw an exception. // store what we tried to request (prior to trying to crop) inputPtr->SetRequestedRegion( inputRequestedRegion ); // build an exception InvalidRequestedRegionError e(__FILE__, __LINE__); e.SetLocation(ITK_LOCATION); e.SetDescription("Requested region outside possible region."); e.SetDataObject(inputPtr); throw e; } } template< class TInputImage, class TOutputImage> void RegularizedIVIMLocalVariationImageFilter< TInputImage, TOutputImage> - ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, - ThreadIdType threadId) + ::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread) { // Allocate output typename OutputImageType::Pointer output = this->GetOutput(); typename InputImageType::ConstPointer input = this->GetInput(); itk::Size size; for(unsigned int i=0; i bC; typename NeighborhoodAlgorithm:: ImageBoundaryFacesCalculator::FaceListType faceList = bC(input, outputRegionForThread, size); - // support progress methods/callbacks - ProgressReporter progress( - this, threadId, outputRegionForThread.GetNumberOfPixels()); - ZeroFluxNeumannBoundaryCondition nbc; std::vector pixels; // Process each of the boundary faces. These are N-d regions which border // the edge of the buffer. for ( typename NeighborhoodAlgorithm:: ImageBoundaryFacesCalculator::FaceListType::iterator fit=faceList.begin(); fit != faceList.end(); ++fit) { // iterators over output and input ImageRegionIterator output_image_it(output, *fit); ImageRegionConstIterator input_image_it(input.GetPointer(), *fit); // neighborhood iterator for input image ConstShapedNeighborhoodIterator input_image_neighbors_it(size, input, *fit); typename ConstShapedNeighborhoodIterator:: OffsetType offset; input_image_neighbors_it.OverrideBoundaryCondition(&nbc); input_image_neighbors_it.ClearActiveList(); for(unsigned int i=0; i:: ConstIterator input_neighbors_it; for (input_neighbors_it = input_image_neighbors_it.Begin(); ! input_neighbors_it.IsAtEnd(); input_neighbors_it++) { typename TInputImage::PixelType diffVec = input_neighbors_it.Get()-input_image_it.Get(); locVariation += IVIMSquaredEuclideanMetric ::Calc(diffVec); } locVariation = sqrt(locVariation + 0.0001); output_image_it.Set(locVariation); // update iterators ++input_image_neighbors_it; ++output_image_it; ++input_image_it; - - // report progress - progress.CompletedPixel(); } } } /** * Standard "PrintSelf" method */ template void RegularizedIVIMLocalVariationImageFilter ::PrintSelf( std::ostream& os, Indent indent) const { Superclass::PrintSelf( os, indent ); } } // end namespace itk #endif //_itkRegularizedIVIMLocalVariationImageFilter_txx diff --git a/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMReconstructionSingleIteration.h b/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMReconstructionSingleIteration.h index fb9b9dc..afa25c0 100644 --- a/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMReconstructionSingleIteration.h +++ b/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMReconstructionSingleIteration.h @@ -1,141 +1,140 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkRegularizedIVIMReconstructionSingleIteration_h #define __itkRegularizedIVIMReconstructionSingleIteration_h #include "itkImageToImageFilter.h" #include "itkImage.h" #include "itkVectorImage.h" namespace itk { /** \class RegularizedIVIMReconstructionSingleIteration * \brief Applies a total variation denoising filter to an image * * Reference: Tony F. Chan et al., The digital TV filter and nonlinear denoising * * \sa Image * \sa Neighborhood * \sa NeighborhoodOperator * \sa NeighborhoodIterator * * \ingroup IntensityImageFilters */ template class RegularizedIVIMReconstructionSingleIteration : public ImageToImageFilter< itk::Image, 3>, itk::Image, 3> > { public: /** Convenient typedefs for simplifying declarations. */ typedef itk::Image, 3> InputImageType; typedef itk::Image, 3> OutputImageType; typedef itk::VectorImage RefImageType; /** Extract dimension from input and output image. */ itkStaticConstMacro(InputImageDimension, unsigned int, InputImageType::ImageDimension); itkStaticConstMacro(OutputImageDimension, unsigned int, OutputImageType::ImageDimension); typedef itk::Image LocalVariationImageType; /** Standard class typedefs. */ typedef RegularizedIVIMReconstructionSingleIteration Self; typedef ImageToImageFilter< InputImageType, OutputImageType> Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Run-time type information (and related methods). */ itkTypeMacro(RegularizedIVIMReconstructionSingleIteration, ImageToImageFilter); /** Image typedef support. */ typedef typename InputImageType::PixelType InputPixelType; typedef typename OutputImageType::PixelType OutputPixelType; typedef typename InputImageType::RegionType InputImageRegionType; typedef typename OutputImageType::RegionType OutputImageRegionType; typedef typename InputImageType::SizeType InputSizeType; /** A larger input requested region than * the output requested region is required. * Therefore, an implementation for GenerateInputRequestedRegion() * is provided. * * \sa ImageToImageFilter::GenerateInputRequestedRegion() */ virtual void GenerateInputRequestedRegion(); itkSetMacro(Lambda, double); itkGetMacro(Lambda, double); void SetBValues(vnl_vector bvals) { this->m_BValues = bvals; } vnl_vector GetBValues() { return this->m_BValues; } void SetOriginalImage(RefImageType* in) { this->m_OriginalImage = in; } typename RefImageType::Pointer GetOriginialImage() { return this->m_OriginalImage; } protected: RegularizedIVIMReconstructionSingleIteration(); virtual ~RegularizedIVIMReconstructionSingleIteration() {} void PrintSelf(std::ostream& os, Indent indent) const; /** MedianImageFilter can be implemented as a multithreaded filter. - * Therefore, this implementation provides a ThreadedGenerateData() + * Therefore, this implementation provides a DynamicThreadedGenerateData() * routine which is called for each processing thread. The output * image data is allocated automatically by the superclass prior to - * calling ThreadedGenerateData(). ThreadedGenerateData can only + * calling DynamicThreadedGenerateData(). DynamicThreadedGenerateData can only * write to the portion of the output image specified by the * parameter "outputRegionForThread" * - * \sa ImageToImageFilter::ThreadedGenerateData(), + * \sa ImageToImageFilter::DynamicThreadedGenerateData(), * ImageToImageFilter::GenerateData() */ - void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, - ThreadIdType threadId ); + void DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread); void BeforeThreadedGenerateData(); typename LocalVariationImageType::Pointer m_LocalVariation; typename RefImageType::Pointer m_OriginalImage; double m_Lambda; vnl_vector m_BValues; private: RegularizedIVIMReconstructionSingleIteration(const Self&); void operator=(const Self&); }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkRegularizedIVIMReconstructionSingleIteration.txx" #endif #endif //__itkRegularizedIVIMReconstructionSingleIteration__ diff --git a/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMReconstructionSingleIteration.txx b/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMReconstructionSingleIteration.txx index 6f52f4f..b9f2a47 100644 --- a/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMReconstructionSingleIteration.txx +++ b/Modules/DiffusionCore/Algorithms/itkRegularizedIVIMReconstructionSingleIteration.txx @@ -1,312 +1,311 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _itkRegularizedIVIMReconstructionSingleIteration_txx #define _itkRegularizedIVIMReconstructionSingleIteration_txx // itk includes #include "itkConstShapedNeighborhoodIterator.h" #include "itkNeighborhoodInnerProduct.h" #include "itkImageRegionIterator.h" #include "itkNeighborhoodAlgorithm.h" #include "itkZeroFluxNeumannBoundaryCondition.h" #include "itkOffset.h" #include "itkProgressReporter.h" #include "itkRegularizedIVIMLocalVariationImageFilter.h" // other includes #include #include #define IVIM_FOO -100000 namespace itk { /** * constructor */ template RegularizedIVIMReconstructionSingleIteration ::RegularizedIVIMReconstructionSingleIteration() { m_Lambda = 1.0; m_LocalVariation = LocalVariationImageType::New(); - this->DynamicMultiThreadingOff(); + } /** * generate requested region */ template void RegularizedIVIMReconstructionSingleIteration ::GenerateInputRequestedRegion() { // call the superclass' implementation of this method Superclass::GenerateInputRequestedRegion(); // get pointers to the input and output typename Superclass::InputImagePointer inputPtr = const_cast< InputImageType * >( this->GetInput() ); typename Superclass::OutputImagePointer outputPtr = this->GetOutput(); if ( !inputPtr || !outputPtr ) { return; } // get a copy of the input requested region (should equal the output // requested region) typename InputImageType::RegionType inputRequestedRegion; inputRequestedRegion = inputPtr->GetRequestedRegion(); // pad the input requested region by 1 inputRequestedRegion.PadByRadius( 1 ); // crop the input requested region at the input's largest possible region if ( inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion()) ) { inputPtr->SetRequestedRegion( inputRequestedRegion ); return; } else { // Couldn't crop the region (requested region is outside the largest // possible region). Throw an exception. // store what we tried to request (prior to trying to crop) inputPtr->SetRequestedRegion( inputRequestedRegion ); // build an exception InvalidRequestedRegionError e(__FILE__, __LINE__); e.SetLocation(ITK_LOCATION); e.SetDescription("Requested region outside possible region."); e.SetDataObject(inputPtr); throw e; } } /** * generate output */ template void RegularizedIVIMReconstructionSingleIteration - ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, - ThreadIdType) + ::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread) { typename OutputImageType::Pointer output = this->GetOutput(); typename InputImageType::ConstPointer input = this->GetInput(); // Find the data-set boundary "faces" itk::Size size; for( unsigned int i=0; i bC; typename NeighborhoodAlgorithm:: ImageBoundaryFacesCalculator::FaceListType faceList = bC(input, outputRegionForThread, size); NeighborhoodAlgorithm:: ImageBoundaryFacesCalculator lv_bC; typename NeighborhoodAlgorithm:: ImageBoundaryFacesCalculator::FaceListType lv_faceList = lv_bC(m_LocalVariation, outputRegionForThread, size); ZeroFluxNeumannBoundaryCondition nbc; ZeroFluxNeumannBoundaryCondition lv_nbc; std::vector ws; std::vector hs; typename NeighborhoodAlgorithm:: ImageBoundaryFacesCalculator::FaceListType::iterator lv_fit=lv_faceList.begin(); // Process each of the boundary faces. These are N-d regions which border // the edge of the buffer. for ( typename NeighborhoodAlgorithm:: ImageBoundaryFacesCalculator::FaceListType::iterator fit=faceList.begin(); fit != faceList.end(); ++fit) { // iterators over output, input, original and local variation image ImageRegionIterator output_image_it = ImageRegionIterator(output, *fit); ImageRegionConstIterator input_image_it = ImageRegionConstIterator(input, *fit); ImageRegionConstIterator orig_image_it = ImageRegionConstIterator(m_OriginalImage, *fit); ImageRegionConstIterator loc_var_image_it = ImageRegionConstIterator( m_LocalVariation, *fit); // neighborhood in input image ConstShapedNeighborhoodIterator input_image_neighbors_it(size, input, *fit); typename ConstShapedNeighborhoodIterator:: OffsetType offset; input_image_neighbors_it.OverrideBoundaryCondition(&nbc); input_image_neighbors_it.ClearActiveList(); for(unsigned int i=0; i loc_var_image_neighbors_it(size, m_LocalVariation, *lv_fit); loc_var_image_neighbors_it.OverrideBoundaryCondition(&lv_nbc); loc_var_image_neighbors_it.ClearActiveList(); for(unsigned int i=0; i:: ConstIterator loc_var_neighbors_it; for (loc_var_neighbors_it = loc_var_image_neighbors_it.Begin(); ! loc_var_neighbors_it.IsAtEnd(); loc_var_neighbors_it++) { // w_alphabeta(u) = // 1 / ||nabla_alpha(u)||_a + 1 / ||nabla_beta(u)||_a ws[count] = locvar_alpha_inv + (1.0/(double)loc_var_neighbors_it.Get()); wsum += ws[count++]; //MITK_INFO << "nb var: " << count << ": " << loc_var_neighbors_it.Get(); } //MITK_INFO << "wsum: " << wsum; // h_alphaalpha * u_alpha^zero typename RefImageType::PixelType orig = orig_image_it.Get(); // vnl_vector estim(orig.GetSize()); // vnl_matrix diff(orig.GetSize(),1); // vnl_matrix estimdash(orig.GetSize(),2); vnl_vector_fixed step; step[0] = 0; step[1]=0; for(size_t ind=0; ind:: ConstIterator input_neighbors_it; for (input_neighbors_it = input_image_neighbors_it.Begin(); ! input_neighbors_it.IsAtEnd(); input_neighbors_it++) { step[1] += (input_neighbors_it.Get()[1] - input_image_it.Get()[1]) * (ws[count++] / (m_Lambda+wsum)); } //MITK_INFO << "stepfinal: " << step[0] << "; " << step[1]; // set output result OutputPixelType out; out[0] = input_image_it.Get()[0] + .001*step[0]; out[1] = input_image_it.Get()[1] + .00001*step[1]; output_image_it.Set( out ); //MITK_INFO << "(" << input_image_it.Get()[0] << " ; " << input_image_it.Get()[1] << ") => (" << out[0] << " ; " << out[1] << ")"; // increment iterators ++output_image_it; ++input_image_it; ++orig_image_it; ++loc_var_image_it; ++input_image_neighbors_it; ++loc_var_image_neighbors_it; } ++lv_fit; } } /** * first calculate local variation in the image */ template void RegularizedIVIMReconstructionSingleIteration ::BeforeThreadedGenerateData() { typedef typename itk::RegularizedIVIMLocalVariationImageFilter FilterType; typename FilterType::Pointer filter = FilterType::New(); filter->SetInput(this->GetInput(0)); filter->SetNumberOfWorkUnits(this->GetNumberOfWorkUnits()); filter->Update(); this->m_LocalVariation = filter->GetOutput(); } /** * Standard "PrintSelf" method */ template void RegularizedIVIMReconstructionSingleIteration ::PrintSelf( std::ostream& os, Indent indent) const { Superclass::PrintSelf( os, indent ); } } // end namespace itk #endif diff --git a/Modules/DiffusionCore/Algorithms/itkRemoveDwiChannelFilter.h b/Modules/DiffusionCore/Algorithms/itkRemoveDwiChannelFilter.h index 9079886..aca4c41 100644 --- a/Modules/DiffusionCore/Algorithms/itkRemoveDwiChannelFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkRemoveDwiChannelFilter.h @@ -1,84 +1,84 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkRemoveDwiChannelFilter_h_ #define __itkRemoveDwiChannelFilter_h_ #include "itkImageToImageFilter.h" #include "itkVectorImage.h" #include #include namespace itk{ /** \class RemoveDwiChannelFilter * \brief Remove spcified channels from diffusion-weighted image. */ template< class TInPixelType > class RemoveDwiChannelFilter : public ImageToImageFilter< VectorImage< TInPixelType, 3 >, VectorImage< TInPixelType, 3 > > { public: typedef RemoveDwiChannelFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< TInPixelType, 3 >, VectorImage< TInPixelType, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(RemoveDwiChannelFilter, ImageToImageFilter) typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef typename mitk::DiffusionPropertyHelper::GradientDirectionType DirectionType; typedef typename mitk::DiffusionPropertyHelper::GradientDirectionsContainerType DirectionContainerType; void SetChannelIndices( std::vector< unsigned int > indices ){ m_ChannelIndices = indices; } void SetDirections( typename DirectionContainerType::ConstPointer directions ){ m_Directions = directions; } typename DirectionContainerType::Pointer GetNewDirections(){ return m_NewDirections; } protected: RemoveDwiChannelFilter(); ~RemoveDwiChannelFilter() {} void PrintSelf(std::ostream& os, Indent indent) const override; void BeforeThreadedGenerateData() override; - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType id ) override; + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread) override; std::vector< unsigned int > m_ChannelIndices; typename DirectionContainerType::ConstPointer m_Directions; typename DirectionContainerType::Pointer m_NewDirections; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkRemoveDwiChannelFilter.txx" #endif #endif //__itkRemoveDwiChannelFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/itkRemoveDwiChannelFilter.txx b/Modules/DiffusionCore/Algorithms/itkRemoveDwiChannelFilter.txx index 3280ac0..a24e8ce 100644 --- a/Modules/DiffusionCore/Algorithms/itkRemoveDwiChannelFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkRemoveDwiChannelFilter.txx @@ -1,135 +1,135 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkRemoveDwiChannelFilter_txx #define __itkRemoveDwiChannelFilter_txx #include #include #include #define _USE_MATH_DEFINES #include #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" namespace itk { template< class TInPixelType > RemoveDwiChannelFilter< TInPixelType>::RemoveDwiChannelFilter() { this->SetNumberOfRequiredInputs( 1 ); - this->DynamicMultiThreadingOff(); + } template< class TInPixelType > void RemoveDwiChannelFilter< TInPixelType>::BeforeThreadedGenerateData() { typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); if ( inputImagePointer->GetVectorLength()-m_ChannelIndices.size()<=0 ) itkExceptionMacro("No channels remaining!"); typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); outputImage->SetSpacing( inputImagePointer->GetSpacing() ); outputImage->SetOrigin( inputImagePointer->GetOrigin() ); outputImage->SetDirection( inputImagePointer->GetDirection() ); outputImage->SetLargestPossibleRegion( inputImagePointer->GetLargestPossibleRegion() ); outputImage->SetBufferedRegion( inputImagePointer->GetLargestPossibleRegion() ); outputImage->SetRequestedRegion( inputImagePointer->GetLargestPossibleRegion() ); outputImage->Allocate(); outputImage->SetVectorLength( inputImagePointer->GetVectorLength()-m_ChannelIndices.size() ); typename OutputImageType::PixelType nullPix; nullPix.SetSize(outputImage->GetVectorLength()); nullPix.Fill(0); outputImage->FillBuffer(nullPix); this->SetNthOutput(0, outputImage); m_NewDirections = DirectionContainerType::New(); int chIdx = 0; for (unsigned int i=0; iGetVectorLength(); i++) { bool use = true; for (unsigned int j=0; jInsertElement(chIdx, m_Directions->GetElement(i)); ++chIdx; MITK_INFO << "Using channel " << i; } } } template< class TInPixelType > -void RemoveDwiChannelFilter< TInPixelType>::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) +void RemoveDwiChannelFilter< TInPixelType>::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread ) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); InputIteratorType git( inputImagePointer, outputRegionForThread ); git.GoToBegin(); while( !git.IsAtEnd() ) { int chIdx = 0; typename OutputImageType::PixelType pix = oit.Get(); for (unsigned int i=0; iGetVectorLength(); i++) { bool use = true; for (unsigned int j=0; j void RemoveDwiChannelFilter< TInPixelType> ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); } } #endif // __itkRemoveDwiChannelFilter_txx diff --git a/Modules/DiffusionCore/Algorithms/itkShToOdfImageFilter.cpp b/Modules/DiffusionCore/Algorithms/itkShToOdfImageFilter.cpp index ed864ef..bb14e4f 100644 --- a/Modules/DiffusionCore/Algorithms/itkShToOdfImageFilter.cpp +++ b/Modules/DiffusionCore/Algorithms/itkShToOdfImageFilter.cpp @@ -1,81 +1,81 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkShToOdfImageFilter_cpp #define __itkShToOdfImageFilter_cpp #include #include #include #include "itkShToOdfImageFilter.h" #include #include namespace itk { template< class PixelType, int ShOrder > ShToOdfImageFilter< PixelType, ShOrder >::ShToOdfImageFilter() : m_Toolkit(mitk::ShImage::SH_CONVENTION::MRTRIX) { - this->DynamicMultiThreadingOff(); + } template< class PixelType, int ShOrder > void ShToOdfImageFilter< PixelType, ShOrder >::BeforeThreadedGenerateData() { CalcShBasis(); } template< class PixelType, int ShOrder > -void ShToOdfImageFilter< PixelType, ShOrder >::ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType) +void ShToOdfImageFilter< PixelType, ShOrder >::DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); typedef ImageRegionConstIterator< InputImageType > InputIteratorType; InputIteratorType it(inputImage, outputRegionForThread); typedef ImageRegionIterator< OutputImageType > OutputIteratorType; OutputIteratorType oit(outputImage, outputRegionForThread); while(!it.IsAtEnd()) { auto pix = it.Get(); vnl_vector coeffs = pix.GetVnlVector(); OutputPixelType odf = (m_ShBasis * coeffs).data_block(); oit.Set(odf); ++it; ++oit; } } // generate spherical harmonic values of the desired order for each input direction template< class PixelType, int ShOrder > void ShToOdfImageFilter< PixelType, ShOrder >::CalcShBasis() { vnl_matrix_fixed* U = itk::PointShell >::DistributePointShell(); if (m_Toolkit==mitk::ShImage::SH_CONVENTION::MRTRIX) m_ShBasis = mitk::sh::CalcShBasisForDirections(ShOrder, U->as_matrix()); else m_ShBasis = mitk::sh::CalcShBasisForDirections(ShOrder, U->as_matrix(), false); } } #endif // __itkShToOdfImageFilter_cpp diff --git a/Modules/DiffusionCore/Algorithms/itkShToOdfImageFilter.h b/Modules/DiffusionCore/Algorithms/itkShToOdfImageFilter.h index 1b820f6..078e601 100644 --- a/Modules/DiffusionCore/Algorithms/itkShToOdfImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkShToOdfImageFilter.h @@ -1,82 +1,82 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkShToOdfImageFilter_h_ #define __itkShToOdfImageFilter_h_ #include #include #include namespace itk{ /** \class ShToOdfImageFilter */ template< class PixelType, int ShOrder > class ShToOdfImageFilter : public ImageToImageFilter< itk::Image< itk::Vector< PixelType, (ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder >, 3 >, itk::Image< itk::Vector,3> > { public: typedef itk::Vector< PixelType, (ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder > InputPixelType; typedef itk::Image InputImageType; typedef typename InputImageType::RegionType InputImageRegionType; typedef itk::Vector OutputPixelType; typedef itk::Image OutputImageType; typedef typename OutputImageType::RegionType OutputImageRegionType; typedef ShToOdfImageFilter Self; typedef itk::ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(ShToOdfImageFilter, ImageToImageFilter) itkSetMacro( Toolkit, mitk::ShImage::SH_CONVENTION) ///< define SH coefficient convention (depends on toolkit) itkGetMacro( Toolkit, mitk::ShImage::SH_CONVENTION) ///< SH coefficient convention (depends on toolkit) void BeforeThreadedGenerateData(); - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType); + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread); protected: ShToOdfImageFilter(); ~ShToOdfImageFilter(){} void CalcShBasis(); vnl_matrix m_ShBasis; mitk::ShImage::SH_CONVENTION m_Toolkit; private: }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkShToOdfImageFilter.cpp" #endif #endif //__itkShToOdfImageFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/itkShToRgbImageFilter.h b/Modules/DiffusionCore/Algorithms/itkShToRgbImageFilter.h index 9cb9ce5..c048ec3 100644 --- a/Modules/DiffusionCore/Algorithms/itkShToRgbImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkShToRgbImageFilter.h @@ -1,163 +1,163 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkShToRgbImageFilter_h #define __itkShToRgbImageFilter_h #include "itkUnaryFunctorImageFilter.h" #include "itkOrientationDistributionFunction.h" #include "itkRGBAPixel.h" #include "itkImageRegionConstIterator.h" #include "itkImageRegionIterator.h" #include #include #include namespace itk { #define __IMG_DAT_ITEM__CEIL_ZERO_ONE__(val) (val) = \ ( (val) < 0 ) ? ( 0 ) : ( ( (val)>1 ) ? ( 1 ) : ( (val) ) ); /** \class ShToRgbImageFilter * */ template ,3> > class ShToRgbImageFilter : public ImageToImageFilter { public: /** Standard class typedefs. */ typedef ShToRgbImageFilter Self; typedef ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename OutputImageType::PixelType OutputPixelType; typedef typename TInputImage::PixelType InputPixelType; typedef typename InputPixelType::ValueType InputValueType; /** Run-time type information (and related methods). */ itkTypeMacro( ShToRgbImageFilter, ImageToImageFilter ) /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Print internal ivars */ void PrintSelf(std::ostream& os, Indent indent) const override { this->Superclass::PrintSelf( os, indent ); } #ifdef ITK_USE_CONCEPT_CHECKING /** Begin concept checking */ itkConceptMacro(InputHasNumericTraitsCheck, (Concept::HasNumericTraits)); /** End concept checking */ #endif itkSetMacro( ShConvention, mitk::ShImage::SH_CONVENTION) ///< define SH coefficient convention itkGetMacro( ShConvention, mitk::ShImage::SH_CONVENTION) ///< SH coefficient convention protected: ShToRgbImageFilter(){ - this->DynamicMultiThreadingOff(); + } ~ShToRgbImageFilter() override{} mitk::ShImage::SH_CONVENTION m_ShConvention = mitk::ShImage::SH_CONVENTION::MRTRIX; - void ThreadedGenerateData( const typename OutputImageType::RegionType &outputRegionForThread, ThreadIdType) override + void DynamicThreadedGenerateData( const typename OutputImageType::RegionType &outputRegionForThread) override { typename InputImageType::Pointer coeff_image = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); outputImage->SetSpacing( coeff_image->GetSpacing() ); // Set the image spacing outputImage->SetOrigin( coeff_image->GetOrigin() ); // Set the image origin outputImage->SetDirection( coeff_image->GetDirection() ); // Set the image direction outputImage->SetRegions( coeff_image->GetLargestPossibleRegion()); outputImage->Allocate(); typedef ImageRegionConstIterator< InputImageType > OdfImageIteratorType; OdfImageIteratorType it(coeff_image, outputRegionForThread); typedef ImageRegionIterator< OutputImageType > OutputImageIteratorType; OutputImageIteratorType oit(outputImage, outputRegionForThread); it.GoToBegin(); oit.GoToBegin(); typedef itk::OrientationDistributionFunction OdfType; vnl_matrix sh2Basis = mitk::sh::CalcShBasisForDirections(ShOrder, itk::PointShell >::DistributePointShell()->as_matrix(), m_ShConvention); while(!it.IsAtEnd() && !oit.IsAtEnd()) { InputPixelType x = it.Get(); Vector< float, ODF_SAMPLING_SIZE > odf_vals; vnl_vector< float > coeffs(x.GetNumberOfComponents()); for(unsigned int i=0; i dir; int pd = odf.GetPrincipalDiffusionDirectionIndex(); if (pd==-1) dir.fill(0); else dir = OdfType::GetDirection(pd); const float fa = odf.GetGeneralizedFractionalAnisotropy(); float r = fabs(dir[0]) * fa; float g = fabs(dir[1]) * fa; float b = fabs(dir[2]) * fa; float a = fa; __IMG_DAT_ITEM__CEIL_ZERO_ONE__(r); __IMG_DAT_ITEM__CEIL_ZERO_ONE__(g); __IMG_DAT_ITEM__CEIL_ZERO_ONE__(b); __IMG_DAT_ITEM__CEIL_ZERO_ONE__(a); OutputPixelType out; out.SetRed( r * 255.0f); out.SetGreen( g * 255.0f); out.SetBlue( b * 255.0f); out.SetAlpha( a * 255.0f); oit.Set(out); ++it; ++oit; } } private: ShToRgbImageFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented }; } // end namespace itk #endif diff --git a/Modules/DiffusionCore/Algorithms/itkTensorImageToDiffusionImageFilter.h b/Modules/DiffusionCore/Algorithms/itkTensorImageToDiffusionImageFilter.h index b990e8e..e236cfc 100644 --- a/Modules/DiffusionCore/Algorithms/itkTensorImageToDiffusionImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkTensorImageToDiffusionImageFilter.h @@ -1,172 +1,172 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*========================================================================= Program: Tensor ToolKit - TTK Module: $URL: svn://scm.gforge.inria.fr/svn/ttk/trunk/Algorithms/itkTensorImageToDiffusionImageFilter.h $ Language: C++ Date: $Date: 2010-06-07 13:39:13 +0200 (Mo, 07 Jun 2010) $ Version: $Revision: 68 $ Copyright (c) INRIA 2010. All rights reserved. See LICENSE.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _itk_TensorImageToDiffusionImageFilter_h_ #define _itk_TensorImageToDiffusionImageFilter_h_ #include "itkImageToImageFilter.h" #include #include namespace itk { template class TensorImageToDiffusionImageFilter : public ImageToImageFilter,3>, itk::VectorImage > { public: typedef TInputScalarType InputScalarType; typedef itk::DiffusionTensor3D InputPixelType; typedef itk::Image InputImageType; typedef typename InputImageType::RegionType InputImageRegionType; typedef TOutputScalarType OutputScalarType; typedef itk::VectorImage OutputImageType; typedef typename OutputImageType::PixelType OutputPixelType; typedef typename OutputImageType::RegionType OutputImageRegionType; typedef OutputScalarType BaselineScalarType; typedef BaselineScalarType BaselinePixelType; typedef typename itk::Image BaselineImageType; typedef typename BaselineImageType::RegionType BaselineImageRegionType; typedef itk::Image< short, 3> MaskImageType; typedef MaskImageType::RegionType MaskImageRegionType; typedef TensorImageToDiffusionImageFilter Self; typedef ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; itkTypeMacro (TensorImageToDiffusionImageFilter, ImageToImageFilter); itkStaticConstMacro (ImageDimension, unsigned int, OutputImageType::ImageDimension); itkFactorylessNewMacro(Self) itkCloneMacro(Self) typedef vnl_vector_fixed GradientType; typedef VectorContainer GradientListType; typedef GradientListType::ConstPointer GradientListPointerType; /** Manually Set/Get a list of gradients */ void SetGradientList(const GradientListPointerType list) { m_GradientList = list; this->Modified(); } GradientListPointerType GetGradientList(void) const {return m_GradientList;} void SetBValue( const double& bval) { m_BValue = bval; } void SetMaskImage( MaskImageType::Pointer maskimage ) { m_MaskImage = maskimage; } /** * @brief Set an external baseline image for signal generation (optional) * * An option to enforce a specific baseline image. If none provided (default) the filter uses * the itk::TensorToL2NormImageFilter to generate the modelled baseline image. */ void SetExternalBaselineImage( typename BaselineImageType::Pointer bimage) { m_BaselineImage = bimage; } itkSetMacro(Min, OutputScalarType); itkSetMacro(Max, OutputScalarType); protected: TensorImageToDiffusionImageFilter() { m_BValue = 1.0; m_BaselineImage = 0; m_Min = 0.0; m_Max = 10000.0; - this->DynamicMultiThreadingOff(); + } virtual ~TensorImageToDiffusionImageFilter(){} void PrintSelf (std::ostream& os, Indent indent) const override { Superclass::PrintSelf (os, indent); } virtual void BeforeThreadedGenerateData( void ) override; - virtual void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType) override; + virtual void DynamicThreadedGenerateData(const OutputImageRegionType &outputRegionForThread) override; //void GenerateData(); virtual void UpdateOutputInformation() override; private: TensorImageToDiffusionImageFilter (const Self&); void operator=(const Self&); GradientListType::ConstPointer m_GradientList; double m_BValue; typename BaselineImageType::Pointer m_BaselineImage; OutputScalarType m_Min; OutputScalarType m_Max; MaskImageType::Pointer m_MaskImage; }; } // end of namespace #ifndef ITK_MANUAL_INSTANTIATION #include "itkTensorImageToDiffusionImageFilter.txx" #endif #endif diff --git a/Modules/DiffusionCore/Algorithms/itkTensorImageToDiffusionImageFilter.txx b/Modules/DiffusionCore/Algorithms/itkTensorImageToDiffusionImageFilter.txx index c24f83f..0157bb6 100644 --- a/Modules/DiffusionCore/Algorithms/itkTensorImageToDiffusionImageFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkTensorImageToDiffusionImageFilter.txx @@ -1,244 +1,220 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*========================================================================= 2 3 Program: Tensor ToolKit - TTK 4 Module: $URL: svn://scm.gforge.inria.fr/svn/ttk/trunk/Algorithms/itkTensorImageToDiffusionImageFilter.txx $ 5 Language: C++ 6 Date: $Date: 2010-06-07 13:39:13 +0200 (Mo, 07 Jun 2010) $ 7 Version: $Revision: 68 $ 8 9 Copyright (c) INRIA 2010. All rights reserved. 10 See LICENSE.txt for details. 11 12 This software is distributed WITHOUT ANY WARRANTY; without even 13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 14 PURPOSE. See the above copyright notices for more information. 15 16 =========================================================================*/ #ifndef _itk_TensorImageToDiffusionImageFilter_txx_ #define _itk_TensorImageToDiffusionImageFilter_txx_ #endif #include "itkTensorImageToDiffusionImageFilter.h" #include "itkTensorToL2NormImageFilter.h" #include "itkRescaleIntensityImageFilter.h" #include #include namespace itk { template void TensorImageToDiffusionImageFilter ::BeforeThreadedGenerateData() { if( m_GradientList->Size()==0 ) { throw itk::ExceptionObject (__FILE__,__LINE__,"Error: gradient list is empty, cannot generate DWI."); } if( m_BaselineImage.IsNull() ) { // create a B0 image by taking the norm of the tensor field * scale: typedef itk::TensorToL2NormImageFilter > TensorToL2NormFilterType; typename TensorToL2NormFilterType::Pointer myFilter1 = TensorToL2NormFilterType::New(); myFilter1->SetInput (this->GetInput()); try { myFilter1->Update(); } catch (itk::ExceptionObject &e) { std::cerr << e; return; } typename itk::RescaleIntensityImageFilter< itk::Image, BaselineImageType>::Pointer rescaler= itk::RescaleIntensityImageFilter, BaselineImageType>::New(); rescaler->SetOutputMinimum ( m_Min ); rescaler->SetOutputMaximum ( m_Max ); rescaler->SetInput ( myFilter1->GetOutput() ); try { rescaler->Update(); } catch (itk::ExceptionObject &e) { std::cerr << e; return; } m_BaselineImage = rescaler->GetOutput(); } typename OutputImageType::Pointer outImage = OutputImageType::New(); outImage->SetSpacing( this->GetInput()->GetSpacing() ); // Set the image spacing outImage->SetOrigin( this->GetInput()->GetOrigin() ); // Set the image origin outImage->SetDirection( this->GetInput()->GetDirection() ); // Set the image direction outImage->SetLargestPossibleRegion( this->GetInput()->GetLargestPossibleRegion()); outImage->SetBufferedRegion( this->GetInput()->GetLargestPossibleRegion() ); outImage->SetRequestedRegion( this->GetInput()->GetLargestPossibleRegion() ); outImage->SetVectorLength(m_GradientList->Size()); outImage->Allocate(); this->SetNumberOfRequiredOutputs (1); this->SetNthOutput (0, outImage); } template void TensorImageToDiffusionImageFilter -::ThreadedGenerateData (const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId ) +::DynamicThreadedGenerateData (const OutputImageRegionType &outputRegionForThread) { typedef ImageRegionIterator IteratorOutputType; typedef ImageRegionConstIterator IteratorInputType; typedef ImageRegionConstIterator IteratorBaselineType; - unsigned long numPixels = outputRegionForThread.GetNumberOfPixels(); - unsigned long step = numPixels/100; - unsigned long progress = 0; - IteratorOutputType itOut (this->GetOutput(), outputRegionForThread); IteratorInputType itIn (this->GetInput(), outputRegionForThread); IteratorBaselineType itB0 (m_BaselineImage, outputRegionForThread); typedef ImageRegionConstIterator< MaskImageType > IteratorMaskImageType; IteratorMaskImageType itMask; if( m_MaskImage.IsNotNull() ) { itMask = IteratorMaskImageType( m_MaskImage, outputRegionForThread); itMask.GoToBegin(); } - if( threadId==0 ) - { - this->UpdateProgress (0.0); - } - while(!itIn.IsAtEnd()) { if( this->GetAbortGenerateData() ) { throw itk::ProcessAborted(__FILE__,__LINE__); } InputPixelType T = itIn.Get(); BaselinePixelType b0 = itB0.Get(); OutputPixelType out; out.SetSize(m_GradientList->Size()); out.Fill(0); short maskvalue = 1; if( m_MaskImage.IsNotNull() ) { maskvalue = itMask.Get(); ++itMask; } std::vector b0_indices; if( b0 > 0) { for( unsigned int i=0; iSize(); i++) { GradientType g = m_GradientList->at(i); // normalize vector so the following computations work const double twonorm = g.two_norm(); if( twonorm < vnl_math::eps ) { b0_indices.push_back(i); continue; } GradientType gn = g.normalize(); InputPixelType S; S[0] = gn[0]*gn[0]; S[1] = gn[1]*gn[0]; S[2] = gn[2]*gn[0]; S[3] = gn[1]*gn[1]; S[4] = gn[2]*gn[1]; S[5] = gn[2]*gn[2]; const double res = - T[0]*S[0] + + T[0]*S[0] + 2 * T[1]*S[1] + T[3]*S[3] + 2 * T[2]*S[2] + 2 * T[4]*S[4] + T[5]*S[5]; // check for corrupted tensor if (res>=0) { // estimate the bvalue from the base value and the norm of the gradient // - because of this estimation the vector have to be normalized beforehand // otherwise the modelled signal is wrong ( i.e. not scaled properly ) const double bval = m_BValue * twonorm * twonorm; out[i] = static_cast( maskvalue * 1.0 * b0 * exp ( -1.0 * bval * res ) ); } } } for(unsigned int idx = 0; idx < b0_indices.size(); idx++ ) { out[b0_indices.at(idx)] = b0; } itOut.Set(out); - if( threadId==0 && step>0) - { - if( (progress%step)==0 ) - { - this->UpdateProgress ( double(progress)/double(numPixels) ); - } - } - - ++progress; ++itB0; ++itIn; ++itOut; - - } - - if( threadId==0 ) - { - this->UpdateProgress (1.0); } } template void TensorImageToDiffusionImageFilter ::UpdateOutputInformation() { // Calls to superclass updateoutputinformation Superclass::UpdateOutputInformation(); this->GetOutput()->SetVectorLength( m_GradientList->size() ); } } // end of namespace diff --git a/Modules/DiffusionCore/Algorithms/itkTensorImageToOdfImageFilter.h b/Modules/DiffusionCore/Algorithms/itkTensorImageToOdfImageFilter.h index a31f7ce..9aa8f7e 100644 --- a/Modules/DiffusionCore/Algorithms/itkTensorImageToOdfImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkTensorImageToOdfImageFilter.h @@ -1,110 +1,110 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*========================================================================= Program: Tensor ToolKit - TTK Module: $URL: svn://scm.gforge.inria.fr/svn/ttk/trunk/Algorithms/itkTensorImageToOdfImageFilter.h $ Language: C++ Date: $Date: 2010-06-07 13:39:13 +0200 (Mo, 07 Jun 2010) $ Version: $Revision: 68 $ Copyright (c) INRIA 2010. All rights reserved. See LICENSE.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _itk_TensorImageToOdfImageFilter_h_ #define _itk_TensorImageToOdfImageFilter_h_ #include "itkImageToImageFilter.h" #include #include namespace itk { template class TensorImageToOdfImageFilter : public ImageToImageFilter,3>, itk::Image,3> > { public: typedef TInputScalarType InputScalarType; typedef itk::DiffusionTensor3D InputPixelType; typedef itk::Image InputImageType; typedef typename InputImageType::RegionType InputImageRegionType; typedef TOutputScalarType OutputScalarType; typedef itk::Vector OutputPixelType; typedef itk::Image OutputImageType; typedef typename OutputImageType::RegionType OutputImageRegionType; typedef TensorImageToOdfImageFilter Self; typedef ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; itkTypeMacro (TensorImageToOdfImageFilter, ImageToImageFilter); itkStaticConstMacro (ImageDimension, unsigned int, OutputImageType::ImageDimension); itkFactorylessNewMacro(Self) itkCloneMacro(Self) protected: TensorImageToOdfImageFilter(){ - this->DynamicMultiThreadingOff(); + }; ~TensorImageToOdfImageFilter() override{}; void PrintSelf (std::ostream& os, Indent indent) const override { Superclass::PrintSelf (os, indent); } void BeforeThreadedGenerateData( void ) override; - void ThreadedGenerateData( const - OutputImageRegionType &outputRegionForThread, ThreadIdType) override; + void DynamicThreadedGenerateData( const + OutputImageRegionType &outputRegionForThread) override; //void GenerateData(); private: TensorImageToOdfImageFilter (const Self&); void operator=(const Self&); typename InputImageType::Pointer m_ItkTensorImage; typename OutputImageType::Pointer m_ItkOdfImage; }; } // end of namespace #ifndef ITK_MANUAL_INSTANTIATION #include "itkTensorImageToOdfImageFilter.txx" #endif #endif diff --git a/Modules/DiffusionCore/Algorithms/itkTensorImageToOdfImageFilter.txx b/Modules/DiffusionCore/Algorithms/itkTensorImageToOdfImageFilter.txx index 4f2109f..54bbf15 100644 --- a/Modules/DiffusionCore/Algorithms/itkTensorImageToOdfImageFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkTensorImageToOdfImageFilter.txx @@ -1,131 +1,109 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*========================================================================= Program: Tensor ToolKit - TTK Module: $URL: svn://scm.gforge.inria.fr/svn/ttk/trunk/Algorithms/itkTensorImageToOdfImageFilter.txx $ Language: C++ Date: $Date: 2010-06-07 13:39:13 +0200 (Mo, 07 Jun 2010) $ Version: $Revision: 68 $ Copyright (c) INRIA 2010. All rights reserved. See LICENSE.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _itk_TensorImageToOdfImageFilter_txx_ #define _itk_TensorImageToOdfImageFilter_txx_ #endif #include "itkTensorImageToOdfImageFilter.h" #include #include #include namespace itk { - template - void - TensorImageToOdfImageFilter - ::BeforeThreadedGenerateData() - { - typename OutputImageType::Pointer outImage = OutputImageType::New(); - outImage->SetSpacing( this->GetInput()->GetSpacing() ); // Set the image spacing - outImage->SetOrigin( this->GetInput()->GetOrigin() ); // Set the image origin - outImage->SetDirection( this->GetInput()->GetDirection() ); // Set the image direction - outImage->SetLargestPossibleRegion( this->GetInput()->GetLargestPossibleRegion()); - outImage->SetBufferedRegion( this->GetInput()->GetLargestPossibleRegion() ); - outImage->SetRequestedRegion( this->GetInput()->GetLargestPossibleRegion() ); - outImage->Allocate(); - outImage->FillBuffer(0.0); - - this->SetNumberOfRequiredOutputs (1); - this->SetNthOutput (0, outImage); - } +template +void +TensorImageToOdfImageFilter +::BeforeThreadedGenerateData() +{ + typename OutputImageType::Pointer outImage = OutputImageType::New(); + outImage->SetSpacing( this->GetInput()->GetSpacing() ); // Set the image spacing + outImage->SetOrigin( this->GetInput()->GetOrigin() ); // Set the image origin + outImage->SetDirection( this->GetInput()->GetDirection() ); // Set the image direction + outImage->SetLargestPossibleRegion( this->GetInput()->GetLargestPossibleRegion()); + outImage->SetBufferedRegion( this->GetInput()->GetLargestPossibleRegion() ); + outImage->SetRequestedRegion( this->GetInput()->GetLargestPossibleRegion() ); + outImage->Allocate(); + outImage->FillBuffer(0.0); + + this->SetNumberOfRequiredOutputs (1); + this->SetNthOutput (0, outImage); +} + +template +void +TensorImageToOdfImageFilter +::DynamicThreadedGenerateData (const OutputImageRegionType &outputRegionForThread) +{ + + typedef ImageRegionIterator IteratorOutputType; + typedef ImageRegionConstIterator IteratorInputType; + + IteratorOutputType itOut (this->GetOutput(), outputRegionForThread); + IteratorInputType itIn (this->GetInput(), outputRegionForThread); - template - void - TensorImageToOdfImageFilter - ::ThreadedGenerateData (const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId ) + while(!itIn.IsAtEnd()) { + if( this->GetAbortGenerateData() ) + { + throw itk::ProcessAborted(__FILE__,__LINE__); + } - typedef ImageRegionIterator IteratorOutputType; - typedef ImageRegionConstIterator IteratorInputType; + InputPixelType T = itIn.Get(); - unsigned long numPixels = outputRegionForThread.GetNumberOfPixels(); - unsigned long step = numPixels/100; - unsigned long progress = 0; + OutputPixelType out; - IteratorOutputType itOut (this->GetOutput(), outputRegionForThread); - IteratorInputType itIn (this->GetInput(), outputRegionForThread); + float tensorelems[6] = { + (float)T[0], + (float)T[1], + (float)T[2], + (float)T[3], + (float)T[4], + (float)T[5], + }; + itk::DiffusionTensor3D tensor(tensorelems); - if( threadId==0 ) - this->UpdateProgress (0.0); + itk::OrientationDistributionFunction odf; + odf.InitFromTensor(tensor); + odf.Normalize(); + for( unsigned int i=0; iGetAbortGenerateData() ) - { - throw itk::ProcessAborted(__FILE__,__LINE__); - } - - InputPixelType T = itIn.Get(); - - OutputPixelType out; - - float tensorelems[6] = { - (float)T[0], - (float)T[1], - (float)T[2], - (float)T[3], - (float)T[4], - (float)T[5], - }; - itk::DiffusionTensor3D tensor(tensorelems); - - itk::OrientationDistributionFunction odf; - odf.InitFromTensor(tensor); - odf.Normalize(); - - for( unsigned int i=0; i0) - { - if( (progress%step)==0 ) - { - this->UpdateProgress ( double(progress)/double(numPixels) ); - } - } - - ++progress; - ++itIn; - ++itOut; - } + itOut.Set(out); - if( threadId==0 ) - { - this->UpdateProgress (1.0); - } - MITK_INFO << "one thread finished ODF estimation"; + ++itIn; + ++itOut; } + MITK_INFO << "one thread finished ODF estimation"; +} } // end of namespace diff --git a/Modules/DiffusionCore/Algorithms/itkTensorToL2NormImageFilter.h b/Modules/DiffusionCore/Algorithms/itkTensorToL2NormImageFilter.h index 40a2a0c..40b2587 100644 --- a/Modules/DiffusionCore/Algorithms/itkTensorToL2NormImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkTensorToL2NormImageFilter.h @@ -1,81 +1,81 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _itk_TensorToL2NormImageFilter_h_ #define _itk_TensorToL2NormImageFilter_h_ #include "itkImageToImageFilter.h" namespace itk { template class ITK_EXPORT TensorToL2NormImageFilter : public ImageToImageFilter { public: typedef TensorToL2NormImageFilter Self; typedef ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; itkTypeMacro (TensorToL2NormImageFilter, ImageToImageFilter); itkStaticConstMacro (ImageDimension, unsigned int, TOutputImage::ImageDimension); itkFactorylessNewMacro(Self) itkCloneMacro(Self) typedef TInputImage InputImageType; typedef typename InputImageType::PixelType InputPixelType; typedef TOutputImage OutputImageType; typedef typename OutputImageType::PixelType OutputPixelType; typedef typename OutputImageType::RegionType OutputImageRegionType; protected: TensorToL2NormImageFilter(){ - this->DynamicMultiThreadingOff(); + }; ~TensorToL2NormImageFilter(){}; void PrintSelf (std::ostream& os, Indent indent) const override { Superclass::PrintSelf (os, indent); } - void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId) override; + void DynamicThreadedGenerateData(const OutputImageRegionType &outputRegionForThread) override; private: TensorToL2NormImageFilter (const Self&); void operator=(const Self&); }; } // end of namespace #ifndef ITK_MANUAL_INSTANTIATION #include "itkTensorToL2NormImageFilter.txx" #endif #endif diff --git a/Modules/DiffusionCore/Algorithms/itkTensorToL2NormImageFilter.txx b/Modules/DiffusionCore/Algorithms/itkTensorToL2NormImageFilter.txx index bc120c3..168b5d6 100644 --- a/Modules/DiffusionCore/Algorithms/itkTensorToL2NormImageFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkTensorToL2NormImageFilter.txx @@ -1,97 +1,78 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*========================================================================= Program: Tensor ToolKit - TTK Module: $URL: svn://scm.gforge.inria.fr/svn/ttk/trunk/Algorithms/itkTensorToL2NormImageFilter.txx $ Language: C++ Date: $Date: 2010-06-07 13:39:13 +0200 (Mo, 07 Jun 2010) $ Version: $Revision: 68 $ Copyright (c) INRIA 2010. All rights reserved. See LICENSE.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _itk_TensorToL2NormImageFilter_txx_ #define _itk_TensorToL2NormImageFilter_txx_ #endif #include "itkTensorToL2NormImageFilter.h" #include #include namespace itk { - template - void TensorToL2NormImageFilter::ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId ) - { - typedef ImageRegionIterator IteratorOutputType; - typedef ImageRegionConstIterator IteratorInputType; - - unsigned long numPixels = outputRegionForThread.GetNumberOfPixels(); - unsigned long step = numPixels/100; - unsigned long progress = 0; - - IteratorOutputType itOut(this->GetOutput(), outputRegionForThread); - IteratorInputType itIn(this->GetInput(), outputRegionForThread); +template +void TensorToL2NormImageFilter::DynamicThreadedGenerateData(const OutputImageRegionType &outputRegionForThread) +{ + typedef ImageRegionIterator IteratorOutputType; + typedef ImageRegionConstIterator IteratorInputType; - if( threadId==0 ) - this->UpdateProgress (0.0); + IteratorOutputType itOut(this->GetOutput(), outputRegionForThread); + IteratorInputType itIn(this->GetInput(), outputRegionForThread); - while(!itOut.IsAtEnd()) - { - if( this->GetAbortGenerateData() ) - throw itk::ProcessAborted(__FILE__,__LINE__); + while(!itOut.IsAtEnd()) + { + if( this->GetAbortGenerateData() ) + throw itk::ProcessAborted(__FILE__,__LINE__); - OutputPixelType out = static_cast( 0.0 ); // be careful, overload in MedINRIA + OutputPixelType out = static_cast( 0.0 ); // be careful, overload in MedINRIA - InputPixelType T = itIn.Get(); + InputPixelType T = itIn.Get(); - if ( !(T[0]==0 && T[1]==0 && T[2]==0 && T[3]==0 && T[4]==0 && T[5]==0) ) - { - double sum = T[0]*T[0] + T[3]*T[3] + T[5]*T[5] + if ( !(T[0]==0 && T[1]==0 && T[2]==0 && T[3]==0 && T[4]==0 && T[5]==0) ) + { + double sum = T[0]*T[0] + T[3]*T[3] + T[5]*T[5] + T[1]*T[2]*2.0 + T[2]*T[4]*2.0 + T[1]*T[4]*2.0; - out = static_cast( std::sqrt( sum )); - } - - if( threadId==0 && step>0) - { - if( (progress%step)==0 ) - this->UpdateProgress ( double(progress)/double(numPixels) ); - } - - - itOut.Set (out); - ++progress; - ++itOut; - ++itIn; - + out = static_cast( std::sqrt( sum )); } - if( threadId==0 ) - this->UpdateProgress (1.0); + itOut.Set (out); + ++itOut; + ++itIn; } +} } // end of namespace diff --git a/Modules/DiffusionCore/Algorithms/itkVectorImageToImageFilter.txx b/Modules/DiffusionCore/Algorithms/itkVectorImageToImageFilter.txx index 781357d..ee54a2b 100644 --- a/Modules/DiffusionCore/Algorithms/itkVectorImageToImageFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkVectorImageToImageFilter.txx @@ -1,81 +1,81 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkVectorImageToImageFilter_txx #define __itkVectorImageToImageFilter_txx #include #include #include #define _USE_MATH_DEFINES #include #include "itkImageRegionIterator.h" namespace itk { template< class TPixelType > VectorImageToImageFilter< TPixelType > ::VectorImageToImageFilter() : m_Index(0) { this->SetNumberOfRequiredInputs( 1 ); - this->DynamicMultiThreadingOff(); + } template< class TPixelType > void VectorImageToImageFilter< TPixelType > ::GenerateData() { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); outputImage->SetSpacing(this->GetInput()->GetSpacing()); outputImage->SetOrigin(this->GetInput()->GetOrigin()); outputImage->SetRegions(this->GetInput()->GetLargestPossibleRegion()); outputImage->Allocate(); ImageRegionIterator< OutputImageType > oit(outputImage, outputImage->GetLargestPossibleRegion()); oit.GoToBegin(); // InputIteratorType; typename InputImageType::Pointer inputImagePointer = nullptr; inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); ImageRegionIterator git( inputImagePointer, inputImagePointer->GetLargestPossibleRegion() ); git.GoToBegin(); while( !git.IsAtEnd() ) { oit.Set(git.Get()[m_Index]); ++oit; ++git; } } template< class TPixelType > void VectorImageToImageFilter< TPixelType >::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); } } #endif // __itkVectorImageToImageFilter_txx diff --git a/Modules/FiberTracking/Algorithms/itkStochasticTractographyFilter.h b/Modules/FiberTracking/Algorithms/itkStochasticTractographyFilter.h index cda1ae4..d3c53c5 100644 --- a/Modules/FiberTracking/Algorithms/itkStochasticTractographyFilter.h +++ b/Modules/FiberTracking/Algorithms/itkStochasticTractographyFilter.h @@ -1,316 +1,316 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkStochasticTractographyFilter_h__ #define __itkStochasticTractographyFilter_h__ #include "itkImageToImageFilter.h" #include "vnl/vnl_random.h" #include "vnl/vnl_vector_fixed.h" #include "vnl/vnl_matrix.h" #include "itkArray.h" #include "itkVectorContainer.h" #include "vnl/algo/vnl_qr.h" #include "itkVariableLengthVector.h" #include "StochasticTracking/itkSlowPolyLineParametricPath.h" #include "itkSimpleFastMutexLock.h" #include "itkRealTimeClock.h" #include "itkDiffusionTensor3D.h" #include namespace itk{ /** * \brief Performs probabilistic streamline tracking on the input dwi. */ /**Types for Probability Distribution **/ typedef Image< Array< double >, 3 > ProbabilityDistributionImageType; template< class TInputDWIImage, class TInputWhiteMatterProbabilityImage, class TOutputConnectivityImage > class ITK_EXPORT StochasticTractographyFilter : public ImageToImageFilter< TInputDWIImage, TOutputConnectivityImage >{ public: typedef StochasticTractographyFilter Self; typedef ImageToImageFilter< TInputDWIImage, TOutputConnectivityImage > Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro( StochasticTractographyFilter, ImageToImageFilter ) /** Types for the DWI Input Image **/ typedef TInputDWIImage InputDWIImageType; /** Types for the Connectivity Output Image**/ typedef TOutputConnectivityImage OutputConnectivityImageType; /** Types for the Mask Image **/ typedef TInputWhiteMatterProbabilityImage InputWhiteMatterProbabilityImageType; /** Tract Types **/ typedef SlowPolyLineParametricPath< 3 > TractType; /** Types for the TractContainer **/ typedef VectorContainer< unsigned int, typename TractType::Pointer > TractContainerType; /** Types for Tensor Output Image **/ typedef Image< DiffusionTensor3D< double >, 3 > OutputTensorImageType; /** Types for the Image-wide Magnetic Field Gradient Directions **/ typedef VectorContainer< unsigned int, vnl_vector_fixed< double, 3 > > GradientDirectionContainerType; /** Types for the Image-wide bValues **/ typedef double bValueType; typedef VectorContainer< unsigned int, bValueType > bValueContainerType; /** Types for the Measurement Frame of the Gradients **/ typedef vnl_matrix_fixed< double, 3, 3 > MeasurementFrameType; /** Type for the sample directions **/ typedef VectorContainer< unsigned int, vnl_vector_fixed< double, 3 > > TractOrientationContainerType; /** the number of Tracts to generate **/ itkSetMacro( TotalTracts, unsigned int) itkGetMacro( TotalTracts, unsigned int) /** the maximum length of Tract **/ itkSetMacro( MaxTractLength, unsigned int ) itkGetMacro( MaxTractLength, unsigned int ) /** Set/Get bvalues **/ itkSetConstObjectMacro( bValues, bValueContainerType ) itkGetConstObjectMacro( bValues, bValueContainerType ) /** Set/Get of gradient directions **/ itkSetConstObjectMacro( Gradients, GradientDirectionContainerType ) itkGetConstObjectMacro( Gradients, GradientDirectionContainerType ) /** Set/Get the White Matter Probability Input image **/ /* At each voxel specifies the probability of a mylinated fiber existing at that location. This probability is interpreted to be the probability that a fiber tract passes through that region. */ itkSetInputMacro(WhiteMatterProbabilityImage, InputWhiteMatterProbabilityImageType) itkGetInputMacro(WhiteMatterProbabilityImage, InputWhiteMatterProbabilityImageType) //overide the built in set input function //we need to create a new cache everytime we change the input image //but we need to preserve it when the input image is the same void SetPrimaryInput(DataObject *input) { typename InputDWIImageType::Pointer dwiimagePtr; try { dwiimagePtr = dynamic_cast( input ); } catch(itk::ExceptionObject &e) { MITK_INFO << "wrong image type: " << e.what(); throw; } Superclass::SetPrimaryInput( input ); //update the likelihood cache this->m_LikelihoodCachePtr = ProbabilityDistributionImageType::New(); this->m_LikelihoodCachePtr->CopyInformation( this->GetInput() ); this->m_LikelihoodCachePtr->SetBufferedRegion( this->GetInput()->GetBufferedRegion() ); this->m_LikelihoodCachePtr->SetRequestedRegion( this->GetInput()->GetRequestedRegion() ); this->m_LikelihoodCachePtr->Allocate(); this->m_CurrentLikelihoodCacheElements = 0; //update the likelihoodcache mutex image this->m_LikelihoodCacheMutexImagePtr = LikelihoodCacheMutexImageType::New(); this->m_LikelihoodCacheMutexImagePtr->CopyInformation( this->GetInput() ); this->m_LikelihoodCacheMutexImagePtr->SetBufferedRegion( this->GetInput()->GetBufferedRegion() ); this->m_LikelihoodCacheMutexImagePtr->SetRequestedRegion( this->GetInput()->GetRequestedRegion() ); this->m_LikelihoodCacheMutexImagePtr->Allocate(); } /** Set/Get the seed index **/ itkSetMacro( SeedIndex, typename InputDWIImageType::IndexType ) itkGetMacro( SeedIndex, typename InputDWIImageType::IndexType ) /** Set/Get the list of directions to sample **/ itkSetConstObjectMacro( SampleDirections, TractOrientationContainerType ) itkGetConstObjectMacro( SampleDirections, TractOrientationContainerType ) /** Set/Get the Measurement Frame **/ itkSetMacro( MeasurementFrame, MeasurementFrameType ) itkGetMacro( MeasurementFrame, MeasurementFrameType ) /** Set/Get the Maximum Likelihood Cache Size, the max num. of cached voxels **/ itkSetMacro( MaxLikelihoodCacheSize, unsigned int ) itkGetMacro( MaxLikelihoodCacheSize, unsigned int ) /** Get the Tracts that are generated **/ itkGetObjectMacro( OutputTractContainer, TractContainerType ) /** Get TensorImage **/ itkGetObjectMacro( OutputTensorImage, OutputTensorImageType ) void GenerateData(); void GenerateTractContainerOutput( void ); void GenerateTensorImageOutput( void ); protected: /** Convenience Types used only inside the filter **/ /**Types for the parameters of the Tensor Model **/ typedef vnl_vector_fixed< double, 7 > TensorModelParamType; /**Types for the parameters of the Constrained Model **/ typedef vnl_vector_fixed< double, 6 > ConstrainedModelParamType; /**Type to hold generated DWI values**/ typedef Image< VariableLengthVector< double >, 3 > DWIVectorImageType; /**Types for Probability Distribution **/ typedef Image< Array< double >, 3 > ProbabilityDistributionImageType; /** Types for the Image of Mutexes of the Likelihood distribution **/ typedef Image< SimpleFastMutexLock, 3 > LikelihoodCacheMutexImageType; StochasticTractographyFilter(); virtual ~StochasticTractographyFilter(); /** Load the default Sample Directions**/ void LoadDefaultSampleDirections( void ); /** Randomly chose a neighboring pixel weighted on distance **/ void ProbabilisticallyInterpolate( vnl_random& randomgenerator, const TractType::ContinuousIndexType& cindex, typename InputDWIImageType::IndexType& index); /** Functions and data related to fitting the tensor model at each pixel **/ void UpdateGradientDirections(void); void UpdateTensorModelFittingMatrices( void ); void CalculateTensorModelParameters( const DWIVectorImageType::PixelType& dwivalues, vnl_diag_matrix& W, TensorModelParamType& tensormodelparams); void CalculateConstrainedModelParameters( const TensorModelParamType& tensormodelparams, ConstrainedModelParamType& constrainedmodelparams); void CalculateNoiseFreeDWIFromConstrainedModel( const ConstrainedModelParamType& constrainedmodelparams, DWIVectorImageType::PixelType& noisefreedwi); void CalculateResidualVariance( const DWIVectorImageType::PixelType& noisydwi, const DWIVectorImageType::PixelType& noisefreedwi, const vnl_diag_matrix< double >& W, const unsigned int numberofparameters, double& residualvariance); void CalculateLikelihood( const DWIVectorImageType::PixelType &dwipixel, TractOrientationContainerType::ConstPointer orientations, ProbabilityDistributionImageType::PixelType& likelihood); void CalculatePrior( TractOrientationContainerType::Element v_prev, TractOrientationContainerType::ConstPointer orientations, ProbabilityDistributionImageType::PixelType& prior ); void CalculatePosterior( const ProbabilityDistributionImageType::PixelType& likelihood, const ProbabilityDistributionImageType::PixelType& prior, ProbabilityDistributionImageType::PixelType& posterior); void SampleTractOrientation( vnl_random& randomgenerator, const ProbabilityDistributionImageType::PixelType& posterior, TractOrientationContainerType::ConstPointer orientations, TractOrientationContainerType::Element& choosendirection ); void StochasticTractGeneration( typename InputDWIImageType::ConstPointer dwiimagePtr, typename InputWhiteMatterProbabilityImageType::ConstPointer maskimagePtr, typename InputDWIImageType::IndexType seedindex, unsigned long randomseed, TractType::Pointer tract ); /** Callback routine used by the threading library. This routine just calls - the ThreadedGenerateData method after setting the correct region for this + the DynamicThreadedGenerateData method after setting the correct region for this thread. **/ static ITK_THREAD_RETURN_TYPE StochasticTractGenerationCallback( void *arg ); struct StochasticTractGenerationCallbackStruct{ Pointer Filter; }; /** Thread Safe Function to check/update an entry in the likelihood cache **/ ProbabilityDistributionImageType::PixelType& AccessLikelihoodCache( typename InputDWIImageType::IndexType index ); /** Thread Safe Function to delegate a tract and obtain a randomseed to start tracking **/ bool DelegateTract(unsigned long& randomseed); /** Function to write a tract to the connectivity map **/ void TractContainerToConnectivityMap(TractContainerType::Pointer tractcontainer); /** Thread Safe Function to store a tract to a TractContainer **/ void StoreTract(TractType::Pointer tract); /** Randomly samples the existence of a fiber tract in the current voxel **/ bool FiberExistenceTest( vnl_random& randomgenerator, typename InputWhiteMatterProbabilityImageType::ConstPointer wmpimage, typename InputWhiteMatterProbabilityImageType::IndexType index ); MeasurementFrameType m_MeasurementFrame; LikelihoodCacheMutexImageType::Pointer m_LikelihoodCacheMutexImagePtr; unsigned int m_TotalTracts; unsigned int m_MaxTractLength; GradientDirectionContainerType::ConstPointer m_Gradients; GradientDirectionContainerType::Pointer m_TransformedGradients; bValueContainerType::ConstPointer m_bValues; typename InputDWIImageType::IndexType m_SeedIndex; TractOrientationContainerType::ConstPointer m_SampleDirections; //these will be the same for every pixel in the image so //go ahead and do a QR decomposition to optimize the //LS fitting process for estimating the weighing matrix W //in this case we solve instead: //R*Beta = Q'logPhi vnl_matrix< double >* m_A; vnl_qr< double >* m_Aqr; ProbabilityDistributionImageType::Pointer m_LikelihoodCachePtr; unsigned long m_MaxLikelihoodCacheSize; //in Megabytes unsigned long m_MaxLikelihoodCacheElements; //in Elements (Voxels) unsigned long m_CurrentLikelihoodCacheElements; SimpleFastMutexLock m_LikelihoodCacheMutex; RealTimeClock::Pointer m_ClockPtr; unsigned int m_TotalDelegatedTracts; SimpleFastMutexLock m_TotalDelegatedTractsMutex; //unsigned long m_RandomSeed; SimpleFastMutexLock m_OutputImageMutex; TractContainerType::Pointer m_OutputTractContainer; SimpleFastMutexLock m_OutputTractContainerMutex; OutputTensorImageType::Pointer m_OutputTensorImage; vnl_random m_RandomGenerator; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkStochasticTractographyFilter.txx" #include "StochasticTracking/itkStochasticTractographyFilter_SD.txx" #endif #endif diff --git a/Modules/FiberTracking/Algorithms/itkTdiToVolumeFractionFilter.cpp b/Modules/FiberTracking/Algorithms/itkTdiToVolumeFractionFilter.cpp index a3fd503..e80cc9a 100644 --- a/Modules/FiberTracking/Algorithms/itkTdiToVolumeFractionFilter.cpp +++ b/Modules/FiberTracking/Algorithms/itkTdiToVolumeFractionFilter.cpp @@ -1,158 +1,158 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkTdiToVolumeFractionFilter_txx #define __itkTdiToVolumeFractionFilter_txx #include "itkTdiToVolumeFractionFilter.h" #include #include #include #include namespace itk { template< class TPixelType > TdiToVolumeFractionFilter< TPixelType >::TdiToVolumeFractionFilter() : m_TdiThreshold(0.3) , m_Sqrt(1.0) { this->SetNumberOfRequiredInputs(5); this->SetNumberOfRequiredOutputs(4); - this->DynamicMultiThreadingOff(); + } template< class TPixelType > void TdiToVolumeFractionFilter< TPixelType >::BeforeThreadedGenerateData() { typename InputImageType::Pointer input_tdi = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); for (int i=0; i<4; ++i) { typename OutputImageType::Pointer outputImage = OutputImageType::New(); outputImage->SetOrigin( input_tdi->GetOrigin() ); outputImage->SetRegions( input_tdi->GetLargestPossibleRegion() ); outputImage->SetSpacing( input_tdi->GetSpacing() ); outputImage->SetDirection( input_tdi->GetDirection() ); outputImage->Allocate(); outputImage->FillBuffer(0.0); this->SetNthOutput(i, outputImage); } } template< class TPixelType > -void TdiToVolumeFractionFilter< TPixelType >::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType) +void TdiToVolumeFractionFilter< TPixelType >::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread) { typename OutputImageType::Pointer o_intra_ax = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); typename OutputImageType::Pointer o_inter_ax = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(1)); typename OutputImageType::Pointer o_gray_matter = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(2)); typename OutputImageType::Pointer o_csf = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(3)); ImageRegionIterator< OutputImageType > oit0(o_intra_ax, outputRegionForThread); ImageRegionIterator< OutputImageType > oit1(o_inter_ax, outputRegionForThread); ImageRegionIterator< OutputImageType > oit2(o_gray_matter, outputRegionForThread); ImageRegionIterator< OutputImageType > oit3(o_csf, outputRegionForThread); typename InputImageType::Pointer i_wm = static_cast< InputImageType * >(this->ProcessObject::GetInput(1)); typename InputImageType::Pointer i_gm = static_cast< InputImageType * >(this->ProcessObject::GetInput(2)); typename InputImageType::Pointer i_dgm = static_cast< InputImageType * >(this->ProcessObject::GetInput(3)); typename InputImageType::Pointer i_csf = static_cast< InputImageType * >(this->ProcessObject::GetInput(4)); ImageRegionIterator< OutputImageType > iit0(i_wm, outputRegionForThread); ImageRegionIterator< OutputImageType > iit1(i_gm, outputRegionForThread); ImageRegionIterator< OutputImageType > iit2(i_dgm, outputRegionForThread); ImageRegionIterator< OutputImageType > iit3(i_csf, outputRegionForThread); typename InputImageType::Pointer input_tdi = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); ImageRegionConstIterator< InputImageType > tdi_it(input_tdi, outputRegionForThread); while( !tdi_it.IsAtEnd() ) { TPixelType intra_ax_val = tdi_it.Get(); intra_ax_val = std::pow(intra_ax_val, 1.0/m_Sqrt); if (intra_ax_val>m_TdiThreshold) intra_ax_val = m_TdiThreshold; intra_ax_val /= m_TdiThreshold; if (intra_ax_val<0) intra_ax_val = 0; TPixelType inter_ax_val = 0.0; TPixelType wm_val = iit0.Get(); TPixelType gm_val = iit1.Get(); TPixelType dgm_val = iit2.Get(); TPixelType csf_val = iit3.Get(); if (dgm_val>0) { TPixelType ex = 1.0 - intra_ax_val; gm_val += dgm_val * ex; } if (intra_ax_val < 0.0001 && wm_val > 0.0001) { if (csf_val+gm_val == 0 ) gm_val += wm_val; else { if (csf_val>gm_val) csf_val += wm_val; else gm_val += wm_val; } } else if ( intra_ax_val>0.0001 ) { auto comp_sum = csf_val+gm_val+intra_ax_val; if (comp_sum<1.0) inter_ax_val = 1.0 - comp_sum; else if (comp_sum>1) intra_ax_val = 1.0 - (csf_val+gm_val); if (intra_ax_val<-0.01) MITK_INFO << "Corrupted volume fraction. intra_ax_val=" << intra_ax_val; if (intra_ax_val<0) intra_ax_val = 0; } auto comp_sum = csf_val+gm_val+intra_ax_val+inter_ax_val; if (std::fabs(comp_sum-1.0)>0.00001 && comp_sum > 0.0001) { csf_val /= comp_sum; gm_val /= comp_sum; intra_ax_val /= comp_sum; inter_ax_val /= comp_sum; } oit0.Set(intra_ax_val); oit1.Set(inter_ax_val); oit2.Set(gm_val); oit3.Set(csf_val); ++tdi_it; ++iit0; ++iit1; ++iit2; ++iit3; ++oit0; ++oit1; ++oit2; ++oit3; } } } #endif diff --git a/Modules/FiberTracking/Algorithms/itkTdiToVolumeFractionFilter.h b/Modules/FiberTracking/Algorithms/itkTdiToVolumeFractionFilter.h index cef9aca..153e208 100644 --- a/Modules/FiberTracking/Algorithms/itkTdiToVolumeFractionFilter.h +++ b/Modules/FiberTracking/Algorithms/itkTdiToVolumeFractionFilter.h @@ -1,78 +1,78 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkTdiToVolumeFractionFilter_h_ #define __itkTdiToVolumeFractionFilter_h_ #include #include namespace itk{ /** * \brief */ template< class TPixelType > class TdiToVolumeFractionFilter : public ImageToImageFilter< Image< TPixelType, 3 >, Image< TPixelType, 3 > > { public: typedef TdiToVolumeFractionFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< TPixelType, 3 >, Image< TPixelType, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(TdiToVolumeFractionFilter, ImageToImageFilter) typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; itkSetMacro( TdiThreshold, TPixelType ) itkSetMacro( Sqrt, TPixelType ) protected: TdiToVolumeFractionFilter(); ~TdiToVolumeFractionFilter() override {} void BeforeThreadedGenerateData() override; - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId) override; + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread threadId) override; private: TPixelType m_TdiThreshold; TPixelType m_Sqrt; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkTdiToVolumeFractionFilter.cpp" #endif #endif //__itkTdiToVolumeFractionFilter_h_ diff --git a/Modules/MriSimulation/Algorithms/itkDftImageFilter.cpp b/Modules/MriSimulation/Algorithms/itkDftImageFilter.cpp index f0904dd..cbf86b3 100644 --- a/Modules/MriSimulation/Algorithms/itkDftImageFilter.cpp +++ b/Modules/MriSimulation/Algorithms/itkDftImageFilter.cpp @@ -1,96 +1,96 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkDftImageFilter_txx #define __itkDftImageFilter_txx #include #include #include #include "itkDftImageFilter.h" #include #include #include namespace itk { template< class TPixelType > DftImageFilter< TPixelType > ::DftImageFilter() { this->SetNumberOfRequiredInputs( 1 ); - this->DynamicMultiThreadingOff(); + } template< class TPixelType > void DftImageFilter< TPixelType > ::BeforeThreadedGenerateData() { } template< class TPixelType > void DftImageFilter< TPixelType > -::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType) +::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); float szx = outputImage->GetLargestPossibleRegion().GetSize(0); float szy = outputImage->GetLargestPossibleRegion().GetSize(1); float x_shift = 0; float y_shift = 0; if (static_cast(szx)%2==1) x_shift = (szx-1)/2; else x_shift = szx/2; if (static_cast(szy)%2==1) y_shift = (szy-1)/2; else y_shift = szy/2; while( !oit.IsAtEnd() ) { float kx = oit.GetIndex()[0] - x_shift; float ky = oit.GetIndex()[1] - y_shift; kx /= szx; ky /= szy; std::complex s(0,0); InputIteratorType it(inputImage, inputImage->GetLargestPossibleRegion() ); while( !it.IsAtEnd() ) { float x = it.GetIndex()[0] - x_shift; float y = it.GetIndex()[1] - y_shift; s += it.Get() * exp( std::complex(0, -itk::Math::twopi * (kx*x + ky*y) ) ); ++it; } oit.Set(s); ++oit; } } } #endif diff --git a/Modules/MriSimulation/Algorithms/itkDftImageFilter.h b/Modules/MriSimulation/Algorithms/itkDftImageFilter.h index faefbba..db91ad4 100644 --- a/Modules/MriSimulation/Algorithms/itkDftImageFilter.h +++ b/Modules/MriSimulation/Algorithms/itkDftImageFilter.h @@ -1,78 +1,78 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkDftImageFilter_h_ #define __itkDftImageFilter_h_ #include #include #include namespace itk{ /** * \brief 2D Discrete Fourier Transform Filter (complex to real). Special issue for Fiberfox -> rearranges slice. */ template< class TPixelType > class DftImageFilter : public ImageToImageFilter< Image< std::complex< TPixelType > >, Image< std::complex< TPixelType > > > { public: typedef DftImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< std::complex< TPixelType > >, Image< std::complex< TPixelType > > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DftImageFilter, ImageToImageFilter) typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; void SetParameters( FiberfoxParameters& param ){ m_Parameters = param; } protected: DftImageFilter(); ~DftImageFilter() override {} void BeforeThreadedGenerateData() override; - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId) override; + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread) override; private: FiberfoxParameters m_Parameters; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkDftImageFilter.cpp" #endif #endif //__itkDftImageFilter_h_ diff --git a/Modules/MriSimulation/Algorithms/itkFieldmapGeneratorFilter.cpp b/Modules/MriSimulation/Algorithms/itkFieldmapGeneratorFilter.cpp index acf807f..7883397 100644 --- a/Modules/MriSimulation/Algorithms/itkFieldmapGeneratorFilter.cpp +++ b/Modules/MriSimulation/Algorithms/itkFieldmapGeneratorFilter.cpp @@ -1,81 +1,81 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Coindex[1]right (c) German Cancer Research Center, All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "itkFieldmapGeneratorFilter.h" #include #include #include namespace itk{ template< class OutputImageType > FieldmapGeneratorFilter< OutputImageType >::FieldmapGeneratorFilter() { m_Gradient.fill(0.0); m_Offset.fill(0.0); - this->DynamicMultiThreadingOff(); + } template< class OutputImageType > FieldmapGeneratorFilter< OutputImageType >::~FieldmapGeneratorFilter() { } template< class OutputImageType > void FieldmapGeneratorFilter< OutputImageType >::BeforeThreadedGenerateData() { typename OutputImageType::Pointer outImage = OutputImageType::New(); outImage->SetSpacing( m_Spacing ); outImage->SetOrigin( m_Origin ); outImage->SetDirection( m_DirectionMatrix ); outImage->SetLargestPossibleRegion( m_ImageRegion ); outImage->SetBufferedRegion( m_ImageRegion ); outImage->SetRequestedRegion( m_ImageRegion ); outImage->Allocate(); outImage->FillBuffer(0); this->SetNthOutput(0, outImage); } template< class OutputImageType > -void FieldmapGeneratorFilter< OutputImageType >::ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId) +void FieldmapGeneratorFilter< OutputImageType >::DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread) { typename OutputImageType::Pointer outImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outImage, outputRegionForThread); while( !oit.IsAtEnd() ) { double value = 0; IndexType idx = oit.GetIndex(); for (int i=0; i<3; i++) value += idx[i]*m_Gradient[i] + m_Offset[i]; for (unsigned int i=0; i vertex; outImage->TransformIndexToPhysicalPoint(idx, vertex); double dist = c.EuclideanDistanceTo(vertex); value += m_Heights.at(i)*exp(-dist*dist/(2*m_Variances.at(i))); } oit.Set(value); ++oit; } - MITK_INFO << "Thread " << threadId << "finished processing"; + MITK_INFO << "One thread finished processing"; } } diff --git a/Modules/MriSimulation/Algorithms/itkFieldmapGeneratorFilter.h b/Modules/MriSimulation/Algorithms/itkFieldmapGeneratorFilter.h index 9f5dc11..22890e2 100644 --- a/Modules/MriSimulation/Algorithms/itkFieldmapGeneratorFilter.h +++ b/Modules/MriSimulation/Algorithms/itkFieldmapGeneratorFilter.h @@ -1,93 +1,93 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkFieldmapGeneratorFilter_h__ #define __itkFieldmapGeneratorFilter_h__ #include #include #include #include #include #include #include namespace itk{ /** * \brief Generate float image with artificial frequency maps used by Fiberfox. Simulates additional frequencies at (possibly multiple) positions based on 3D gaussians with the specified variance and amplitude and/or as a linear gradient in the image. * See "Fiberfox: Facilitating the creation of realistic white matter software phantoms" (DOI: 10.1002/mrm.25045) for details. */ template< class OutputImageType > class FieldmapGeneratorFilter : public ImageSource< OutputImageType > { public: typedef FieldmapGeneratorFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef typename OutputImageType::PixelType PixelType; typedef typename OutputImageType::IndexType IndexType; typedef itk::ImageRegion<3> OutputImageRegionType; typedef itk::Matrix MatrixType; itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro( FieldmapGeneratorFilter, ImageSource ) /** Output image parameters. */ itkSetMacro( Spacing, itk::Vector ) itkSetMacro( Origin, mitk::Point3D ) itkSetMacro( DirectionMatrix, MatrixType ) itkSetMacro( ImageRegion, OutputImageRegionType ) /** Gradient direction and offset. */ void SetGradient( vnl_vector_fixed< double, 3 > gradient ) { m_Gradient=gradient; } void SetOffset( vnl_vector_fixed< double, 3 > offset ) { m_Offset=offset; } /** Parameters of gaussian frequency sources. */ void SetVariances( std::vector< double > variances ) { m_Variances=variances; } void SetHeights( std::vector< double > heights ) { m_Heights=heights; } void SetWorldPositions( std::vector< mitk::Point3D > worldPositions ) { m_WorldPositions=worldPositions; } protected: void BeforeThreadedGenerateData(); - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId); + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread); FieldmapGeneratorFilter(); virtual ~FieldmapGeneratorFilter(); itk::Vector m_Spacing; ///< output image spacing mitk::Point3D m_Origin; ///< output image origin MatrixType m_DirectionMatrix; ///< output image rotation OutputImageRegionType m_ImageRegion; ///< output image size std::vector< double > m_Variances; std::vector< double > m_Heights; std::vector< mitk::Point3D > m_WorldPositions; vnl_vector_fixed< double, 3 > m_Gradient; vnl_vector_fixed< double, 3 > m_Offset; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkFieldmapGeneratorFilter.cpp" #endif #endif // __itkFieldmapGeneratorFilter_h__ diff --git a/Modules/MriSimulation/Algorithms/itkKspaceImageFilter.cpp b/Modules/MriSimulation/Algorithms/itkKspaceImageFilter.cpp index 3ed6e50..680fe0d 100644 --- a/Modules/MriSimulation/Algorithms/itkKspaceImageFilter.cpp +++ b/Modules/MriSimulation/Algorithms/itkKspaceImageFilter.cpp @@ -1,514 +1,514 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkKspaceImageFilter_txx #define __itkKspaceImageFilter_txx //#endif #include #include #include #include #include "itkKspaceImageFilter.h" #include #include #include #include #include #include #include #include namespace itk { template< class ScalarType > KspaceImageFilter< ScalarType >::KspaceImageFilter() : m_Z(0) , m_RandSeed(-1) , m_SpikesPerSlice(0) , m_IsBaseline(true) , m_StoreTimings(false) { m_DiffusionGradientDirection.Fill(0.0); m_CoilPosition.Fill(0.0); - this->DynamicMultiThreadingOff(); + } template< class ScalarType > void KspaceImageFilter< ScalarType > ::BeforeThreadedGenerateData() { m_Spike = std::complex(0,0); m_SpikeLog = ""; m_TransX = -m_Translation[0]; m_TransY = -m_Translation[1]; m_TransZ = -m_Translation[2]; kxMax = m_Parameters->m_SignalGen.m_CroppedRegion.GetSize(0); kyMax = m_Parameters->m_SignalGen.m_CroppedRegion.GetSize(1); xMax = m_CompartmentImages.at(0)->GetLargestPossibleRegion().GetSize(0); // scanner coverage in x-direction yMax = m_CompartmentImages.at(0)->GetLargestPossibleRegion().GetSize(1); // scanner coverage in y-direction yMaxFov = yMax; if (m_Parameters->m_Misc.m_DoAddAliasing) { // actual FOV in y-direction (in x-direction FOV=xMax) yMaxFov = static_cast(yMaxFov * m_Parameters->m_SignalGen.m_CroppingFactor); } yMaxFov_half = (yMaxFov-1)/2; numPix = kxMax*kyMax; float ringing_factor = static_cast(m_Parameters->m_SignalGen.m_ZeroRinging)/100.0; ringing_lines_x = static_cast(ceil(kxMax/2 * ringing_factor)); ringing_lines_y = static_cast(ceil(kyMax/2 * ringing_factor)); // Adjust noise variance since it is the intended variance in physical space and not in k-space: float noiseVar = m_Parameters->m_SignalGen.m_PartialFourier*m_Parameters->m_SignalGen.m_NoiseVariance/(kyMax*kxMax); m_RandGen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); if (m_RandSeed>=0) // always generate the same random numbers? m_RandGen->SetSeed(m_RandSeed); else m_RandGen->SetSeed(); typename OutputImageType::Pointer outputImage = OutputImageType::New(); itk::ImageRegion<2> region; region.SetSize(0, m_Parameters->m_SignalGen.m_CroppedRegion.GetSize(0)); region.SetSize(1, m_Parameters->m_SignalGen.m_CroppedRegion.GetSize(1)); outputImage->SetLargestPossibleRegion( region ); outputImage->SetBufferedRegion( region ); outputImage->SetRequestedRegion( region ); outputImage->Allocate(); std::complex zero = std::complex(0, 0); outputImage->FillBuffer(zero); if (m_Parameters->m_SignalGen.m_NoiseVariance>0 && m_Parameters->m_Misc.m_DoAddNoise) { ImageRegionIterator< OutputImageType > oit(outputImage, outputImage->GetLargestPossibleRegion()); while( !oit.IsAtEnd() ) { oit.Set(std::complex(m_RandGen->GetNormalVariate(0, noiseVar), m_RandGen->GetNormalVariate(0, noiseVar))); ++oit; } } m_KSpaceImage = InputImageType::New(); m_KSpaceImage->SetLargestPossibleRegion( region ); m_KSpaceImage->SetBufferedRegion( region ); m_KSpaceImage->SetRequestedRegion( region ); m_KSpaceImage->Allocate(); m_KSpaceImage->FillBuffer(0.0); if (m_StoreTimings) { m_TickImage = InputImageType::New(); m_TickImage->SetLargestPossibleRegion( region ); m_TickImage->SetBufferedRegion( region ); m_TickImage->SetRequestedRegion( region ); m_TickImage->Allocate(); m_TickImage->FillBuffer(-1.0); m_RfImage = InputImageType::New(); m_RfImage->SetLargestPossibleRegion( region ); m_RfImage->SetBufferedRegion( region ); m_RfImage->SetRequestedRegion( region ); m_RfImage->Allocate(); m_RfImage->FillBuffer(-1.0); } else { m_TickImage = nullptr; m_RfImage = nullptr; } m_Gamma = 42576000*itk::Math::twopi; // Gyromagnetic ratio in Hz/T if ( m_Parameters->m_SignalGen.m_EddyStrength>0 && m_DiffusionGradientDirection.GetNorm()>0.001) { m_DiffusionGradientDirection = m_DiffusionGradientDirection * m_Parameters->m_SignalGen.m_EddyStrength/1000 * m_Gamma; m_IsBaseline = false; } else { m_IsBaseline = true; } this->SetNthOutput(0, outputImage); for (int i=0; i<3; i++) for (int j=0; j<3; j++) m_Transform[i][j] = m_Parameters->m_SignalGen.m_ImageDirection[i][j] * m_Parameters->m_SignalGen.m_ImageSpacing[j]/1000; float a = m_Parameters->m_SignalGen.m_ImageRegion.GetSize(0)*m_Parameters->m_SignalGen.m_ImageSpacing[0]; float b = m_Parameters->m_SignalGen.m_ImageRegion.GetSize(1)*m_Parameters->m_SignalGen.m_ImageSpacing[1]; float diagonal = sqrt(a*a+b*b)/1000; // image diagonal in m switch (m_Parameters->m_SignalGen.m_CoilSensitivityProfile) { case SignalGenerationParameters::COIL_CONSTANT: { m_CoilSensitivityFactor = 1; // same signal everywhere break; } case SignalGenerationParameters::COIL_LINEAR: { m_CoilSensitivityFactor = -1/diagonal; // about 50% of the signal in the image center remaining break; } case SignalGenerationParameters::COIL_EXPONENTIAL: { m_CoilSensitivityFactor = -log(0.1)/diagonal; // about 32% of the signal in the image center remaining break; } } switch (m_Parameters->m_SignalGen.m_AcquisitionType) { case SignalGenerationParameters::SingleShotEpi: m_ReadoutScheme = new mitk::SingleShotEpi(m_Parameters); break; case SignalGenerationParameters::ConventionalSpinEcho: m_ReadoutScheme = new mitk::ConventionalSpinEcho(m_Parameters); break; case SignalGenerationParameters::FastSpinEcho: m_ReadoutScheme = new mitk::FastSpinEcho(m_Parameters); break; default: m_ReadoutScheme = new mitk::SingleShotEpi(m_Parameters); } m_ReadoutScheme->AdjustEchoTime(); m_MovedFmap = nullptr; if (m_Parameters->m_Misc.m_DoAddDistortions && m_Parameters->m_SignalGen.m_FrequencyMap.IsNotNull() && m_Parameters->m_SignalGen.m_DoAddMotion) { // we have to account for the head motion since this also moves our frequency map itk::LinearInterpolateImageFunction< itk::Image< float, 3 >, float >::Pointer fmapInterpolator; fmapInterpolator = itk::LinearInterpolateImageFunction< itk::Image< float, 3 >, float >::New(); fmapInterpolator->SetInputImage(m_Parameters->m_SignalGen.m_FrequencyMap); m_MovedFmap = itk::Image< ScalarType, 2 >::New(); m_MovedFmap->SetLargestPossibleRegion( m_CompartmentImages.at(0)->GetLargestPossibleRegion() ); m_MovedFmap->SetBufferedRegion( m_CompartmentImages.at(0)->GetLargestPossibleRegion() ); m_MovedFmap->SetRequestedRegion( m_CompartmentImages.at(0)->GetLargestPossibleRegion() ); m_MovedFmap->Allocate(); m_MovedFmap->FillBuffer(0); ImageRegionIterator< InputImageType > it(m_MovedFmap, m_MovedFmap->GetLargestPossibleRegion() ); while( !it.IsAtEnd() ) { itk::Image::IndexType index; index[0] = it.GetIndex()[0]; index[1] = it.GetIndex()[1]; index[2] = m_Zidx; itk::Point point3D; m_Parameters->m_SignalGen.m_FrequencyMap->TransformIndexToPhysicalPoint(index, point3D); m_FiberBundle->TransformPoint( point3D, m_RotationMatrix, m_TransX, m_TransY, m_TransZ ); it.Set(mitk::imv::GetImageValue(point3D, true, fmapInterpolator)); ++it; } } // calculate T1 relaxation (independent of actual readout) m_T1Relax.clear(); if ( m_Parameters->m_SignalGen.m_DoSimulateRelaxation) for (unsigned int i=0; im_SignalGen.m_tRep/m_T1[i])); // account for inversion pulse and TI if (m_Parameters->m_SignalGen.m_tInv > 0) relaxation *= (1.0-std::exp(std::log(2) - m_Parameters->m_SignalGen.m_tInv/m_T1[i])); m_T1Relax.push_back(relaxation); } } template< class ScalarType > float KspaceImageFilter< ScalarType >::CoilSensitivity(VectorType& pos) { // ************************************************************************* // Coil ring is moving with excited slice (FIX THIS SOMETIME) m_CoilPosition[2] = pos[2]; // ************************************************************************* switch (m_Parameters->m_SignalGen.m_CoilSensitivityProfile) { case SignalGenerationParameters::COIL_CONSTANT: return 1; case SignalGenerationParameters::COIL_LINEAR: { VectorType diff = pos-m_CoilPosition; float sens = diff.GetNorm()*m_CoilSensitivityFactor + 1; if (sens<0) sens = 0; return sens; } case SignalGenerationParameters::COIL_EXPONENTIAL: { VectorType diff = pos-m_CoilPosition; float dist = static_cast(diff.GetNorm()); return std::exp(-dist*m_CoilSensitivityFactor); } default: return 1; } } template< class ScalarType > void KspaceImageFilter< ScalarType > - ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) + ::DynamicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread ) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); typedef ImageRegionConstIterator< InputImageType > InputIteratorType; // precalculate shifts for DFT float x_shift = 0; float y_shift = 0; if (static_cast(xMax)%2==1) x_shift = (xMax-1)/2; else x_shift = xMax/2; if (static_cast(yMax)%2==1) y_shift = (yMax-1)/2; else y_shift = yMax/2; float kx_shift = 0; float ky_shift = 0; if (static_cast(kxMax)%2==1) kx_shift = (kxMax-1)/2; else kx_shift = kxMax/2; if (static_cast(kyMax)%2==1) ky_shift = (kyMax-1)/2; else ky_shift = kyMax/2; std::complex zero = std::complex(0, 0); while( !oit.IsAtEnd() ) { int tick = oit.GetIndex()[1] * kxMax + oit.GetIndex()[0]; // get current k-space index (depends on the chosen k-space readout scheme) itk::Index< 2 > kIdx = m_ReadoutScheme->GetActualKspaceIndex(tick); // we have to adjust the ticks to obtain correct times since the DFT is not completely symmetric in the even number of lines case if (static_cast(kyMax)%2 == 0 && !m_Parameters->m_SignalGen.m_ReversePhase) { tick += kxMax; tick %= static_cast(numPix); } // partial fourier // two cases because we always want to skip the "later" parts of k-space // in "normal" phase direction, the higher k-space indices are acquired first // in reversed phase direction, the higher k-space indices are acquired later // if the image has an even number of lines, never skip line zero since it is missing on the other side (DFT not completely syymetric in even case) if ((m_Parameters->m_SignalGen.m_ReversePhase && kIdx[1]>std::ceil(kyMax*m_Parameters->m_SignalGen.m_PartialFourier)) || (!m_Parameters->m_SignalGen.m_ReversePhase && kIdx[1]m_SignalGen.m_PartialFourier)) && (kIdx[1]>0 || static_cast(kyMax)%2 == 1))) { outputImage->SetPixel(kIdx, zero); ++oit; continue; } if (m_StoreTimings) m_TickImage->SetPixel(kIdx, tick); // gibbs ringing by setting high frequencies to zero (alternative to using smaller k-space than input image space) if (m_Parameters->m_SignalGen.m_DoAddGibbsRinging && m_Parameters->m_SignalGen.m_ZeroRinging>0) { if (kIdx[0] < ringing_lines_x || kIdx[1] < ringing_lines_y || kIdx[0] >= kxMax - ringing_lines_x || kIdx[1] >= kyMax - ringing_lines_y) { outputImage->SetPixel(kIdx, zero); ++oit; continue; } } // time from maximum echo float t = m_ReadoutScheme->GetTimeFromMaxEcho(tick); // calculate eddy current decay factor float eddyDecay = 0; if ( m_Parameters->m_Misc.m_DoAddEddyCurrents && m_Parameters->m_SignalGen.m_EddyStrength>0 && !m_IsBaseline) { // time passed since k-space readout started float tRead = m_ReadoutScheme->GetTimeFromLastDiffusionGradient(tick); eddyDecay = std::exp(-tRead/m_Parameters->m_SignalGen.m_Tau ) * t/1000; // time in seconds here } // calcualte signal relaxation factors std::vector< float > relaxFactor; if ( m_Parameters->m_SignalGen.m_DoSimulateRelaxation) { // time passes since application of the RF pulse float tRf = m_ReadoutScheme->GetTimeFromRf(tick); if (m_StoreTimings) m_RfImage->SetPixel(kIdx, tRf); for (unsigned int i=0; im_SignalGen.m_tInhom)); } } // shift k for DFT: (0 -- N) --> (-N/2 -- N/2) float kx = kIdx[0] - kx_shift; float ky = kIdx[1] - ky_shift; // add ghosting by adding gradient delay induced offset if (m_Parameters->m_Misc.m_DoAddGhosts) { if (kIdx[1]%2 == 1) kx -= m_Parameters->m_SignalGen.m_KspaceLineOffset; else kx += m_Parameters->m_SignalGen.m_KspaceLineOffset; } // pull stuff out of inner loop t /= 1000; // time in seconds kx /= xMax; ky /= yMaxFov; // calculate signal s at k-space position (kx, ky) std::complex s(0,0); InputIteratorType it(m_CompartmentImages[0], m_CompartmentImages[0]->GetLargestPossibleRegion() ); while( !it.IsAtEnd() ) { typename InputImageType::IndexType input_idx = it.GetIndex(); // shift x,y for DFT: (0 -- N) --> (-N/2 -- N/2) float x = input_idx[0] - x_shift; float y = input_idx[1] - y_shift; // sum compartment signals and simulate relaxation ScalarType f_real = 0; for (unsigned int i=0; im_SignalGen.m_DoSimulateRelaxation) f_real += m_CompartmentImages[i]->GetPixel(input_idx) * relaxFactor[i]; else f_real += m_CompartmentImages[i]->GetPixel(input_idx); // vector from image center to current position (in meter) // only necessary for eddy currents and non-constant coil sensitivity VectorType pos; if ((m_Parameters->m_Misc.m_DoAddEddyCurrents && m_Parameters->m_SignalGen.m_EddyStrength>0 && !m_IsBaseline) || m_Parameters->m_SignalGen.m_CoilSensitivityProfile!=SignalGenerationParameters::COIL_CONSTANT) { pos[0] = x; pos[1] = y; pos[2] = m_Z; pos = m_Transform*pos; } if (m_Parameters->m_SignalGen.m_CoilSensitivityProfile!=SignalGenerationParameters::COIL_CONSTANT) f_real *= CoilSensitivity(pos); // simulate eddy currents and other distortions float phi = 0; // phase shift if ( m_Parameters->m_Misc.m_DoAddEddyCurrents && m_Parameters->m_SignalGen.m_EddyStrength>0 && !m_IsBaseline) { // duration (tRead) already included in "eddyDecay" phi += (m_DiffusionGradientDirection[0]*pos[0]+m_DiffusionGradientDirection[1]*pos[1]+m_DiffusionGradientDirection[2]*pos[2]) * eddyDecay; } // simulate distortions if (m_Parameters->m_Misc.m_DoAddDistortions) { if (m_MovedFmap.IsNotNull()) // if we have headmotion, use moved map phi += m_MovedFmap->GetPixel(input_idx) * t; else if (m_Parameters->m_SignalGen.m_FrequencyMap.IsNotNull()) { itk::Image::IndexType index; index[0] = input_idx[0]; index[1] = input_idx[1]; index[2] = m_Zidx; phi += m_Parameters->m_SignalGen.m_FrequencyMap->GetPixel(index) * t; } } // if signal comes from outside FOV, mirror it back (wrap-around artifact - aliasing if (m_Parameters->m_Misc.m_DoAddAliasing) { if (y<-yMaxFov_half) y += yMaxFov; else if (y>yMaxFov_half) y -= yMaxFov; } // actual DFT term std::complex f(f_real * m_Parameters->m_SignalGen.m_SignalScale, 0); s += f * std::exp( std::complex(0, itk::Math::twopi * (kx*x + ky*y + phi )) ); ++it; } s /= numPix; if (m_SpikesPerSlice>0 && sqrt(s.imag()*s.imag()+s.real()*s.real()) > sqrt(m_Spike.imag()*m_Spike.imag()+m_Spike.real()*m_Spike.real()) ) m_Spike = s; s += outputImage->GetPixel(kIdx); // add precalculated noise outputImage->SetPixel(kIdx, s); m_KSpaceImage->SetPixel(kIdx, sqrt(s.imag()*s.imag()+s.real()*s.real()) ); ++oit; } } template< class ScalarType > void KspaceImageFilter< ScalarType > ::AfterThreadedGenerateData() { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); int kxMax = outputImage->GetLargestPossibleRegion().GetSize(0); // k-space size in x-direction int kyMax = outputImage->GetLargestPossibleRegion().GetSize(1); // k-space size in y-direction ImageRegionIterator< OutputImageType > oit(outputImage, outputImage->GetLargestPossibleRegion()); while( !oit.IsAtEnd() ) // use hermitian k-space symmetry to fill empty k-space parts resulting from partial fourier acquisition { int tick = oit.GetIndex()[1] * kxMax + oit.GetIndex()[0]; auto kIdx = m_ReadoutScheme->GetActualKspaceIndex(tick); if ((m_Parameters->m_SignalGen.m_ReversePhase && kIdx[1]>std::ceil(kyMax*m_Parameters->m_SignalGen.m_PartialFourier)) || (!m_Parameters->m_SignalGen.m_ReversePhase && kIdx[1]m_SignalGen.m_PartialFourier)) && (kIdx[1]>0 || static_cast(kyMax)%2 == 1))) { // calculate symmetric index auto sym = m_ReadoutScheme->GetSymmetricIndex(kIdx); // use complex conjugate of symmetric index value at current index std::complex s = outputImage->GetPixel(sym); s = std::complex(s.real(), -s.imag()); outputImage->SetPixel(kIdx, s); m_KSpaceImage->SetPixel(kIdx, sqrt(s.imag()*s.imag()+s.real()*s.real()) ); } ++oit; } m_Spike *= m_Parameters->m_SignalGen.m_SpikeAmplitude; itk::Index< 2 > spikeIdx; for (unsigned int i=0; iGetIntegerVariate()%kxMax; spikeIdx[1] = m_RandGen->GetIntegerVariate()%kyMax; outputImage->SetPixel(spikeIdx, m_Spike); m_SpikeLog += "[" + boost::lexical_cast(spikeIdx[0]) + "," + boost::lexical_cast(spikeIdx[1]) + "," + boost::lexical_cast(m_Zidx) + "] Magnitude: " + boost::lexical_cast(m_Spike.real()) + "+" + boost::lexical_cast(m_Spike.imag()) + "i\n"; } delete m_ReadoutScheme; } } #endif diff --git a/Modules/MriSimulation/Algorithms/itkKspaceImageFilter.h b/Modules/MriSimulation/Algorithms/itkKspaceImageFilter.h index 9ab858e..9fc5f35 100644 --- a/Modules/MriSimulation/Algorithms/itkKspaceImageFilter.h +++ b/Modules/MriSimulation/Algorithms/itkKspaceImageFilter.h @@ -1,159 +1,159 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkKspaceImageFilter_h_ #define __itkKspaceImageFilter_h_ #include #include #include #include #include #include namespace itk{ /** * \brief Simulates k-space acquisition of one slice with a single shot EPI sequence. Enables the simulation of various effects occuring during real MR acquisitions: * - T2 signal relaxation * - Spikes * - N/2 Ghosts * - Aliasing (wrap around) * - Image distortions (off-frequency effects) * - Gibbs ringing * - Eddy current effects * Based on a discrete fourier transformation. * See "Fiberfox: Facilitating the creation of realistic white matter software phantoms" (DOI: 10.1002/mrm.25045) for details. */ template< class ScalarType > class KspaceImageFilter : public ImageSource< Image< std::complex< ScalarType >, 2 > > { public: typedef KspaceImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageSource< Image< std::complex< ScalarType >, 2 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(KspaceImageFilter, ImageToImageFilter) typedef typename itk::Image< ScalarType, 2 > InputImageType; typedef typename InputImageType::Pointer InputImagePointerType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef itk::Matrix MatrixType; typedef itk::Point Point2D; typedef itk::Vector< float,3> VectorType; itkSetMacro( SpikesPerSlice, unsigned int ) ///< Number of spikes per slice. Corresponding parameter in fiberfox parameter object specifies the number of spikes for the whole image and can thus not be used here. itkSetMacro( Z, double ) ///< Slice position, necessary for eddy current simulation. itkSetMacro( RandSeed, int ) ///< Use constant seed for random generator for reproducible results. itkSetMacro( Translation, VectorType ) itkSetMacro( RotationMatrix, MatrixType ) itkSetMacro( Zidx, int ) itkSetMacro( StoreTimings, bool ) itkSetMacro( FiberBundle, FiberBundle::Pointer ) itkSetMacro( CoilPosition, VectorType ) itkGetMacro( KSpaceImage, typename InputImageType::Pointer ) ///< k-space magnitude image itkGetMacro( TickImage, typename InputImageType::Pointer ) ///< k-space readout ordering encoded in the voxels itkGetMacro( RfImage, typename InputImageType::Pointer ) ///< time passed since last RF pulse encoded per voxel itkGetMacro( SpikeLog, std::string ) void SetParameters( FiberfoxParameters* param ){ m_Parameters = param; } void SetCompartmentImages( std::vector< InputImagePointerType > cImgs ) { m_CompartmentImages=cImgs; } ///< One signal image per compartment. void SetT2( std::vector< float > t2Vector ) { m_T2=t2Vector; } ///< One T2 relaxation constant per compartment image. void SetT1( std::vector< float > t1Vector ) { m_T1=t1Vector; } ///< One T1 relaxation constant per compartment image. void SetDiffusionGradientDirection(itk::Vector g) { m_DiffusionGradientDirection=g; } ///< Gradient direction is needed for eddy current simulation. protected: KspaceImageFilter(); ~KspaceImageFilter() override {} float CoilSensitivity(VectorType& pos); void BeforeThreadedGenerateData() override; - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadID) override; + void DynamicThreadedGenerateData( const OutputImageRegionType &outputRegionForThread) override; void AfterThreadedGenerateData() override; VectorType m_CoilPosition; FiberfoxParameters* m_Parameters; std::vector< float > m_T2; std::vector< float > m_T1; std::vector< float > m_T1Relax; std::vector< InputImagePointerType > m_CompartmentImages; itk::Vector m_DiffusionGradientDirection; float m_Z; int m_Zidx; int m_RandSeed; itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer m_RandGen; unsigned int m_SpikesPerSlice; FiberBundle::Pointer m_FiberBundle; float m_Gamma; VectorType m_Translation; ///< used to find correct point in frequency map (head motion) MatrixType m_RotationMatrix; float m_TransX; float m_TransY; float m_TransZ; bool m_IsBaseline; std::complex m_Spike; MatrixType m_Transform; std::string m_SpikeLog; float m_CoilSensitivityFactor; typename InputImageType::Pointer m_KSpaceImage; typename InputImageType::Pointer m_TickImage; typename InputImageType::Pointer m_RfImage; AcquisitionType* m_ReadoutScheme; typename itk::Image< ScalarType, 2 >::Pointer m_MovedFmap; int ringing_lines_x; int ringing_lines_y; float kxMax; float kyMax; float xMax; float yMax; float yMaxFov; float yMaxFov_half; float numPix; bool m_StoreTimings; private: }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkKspaceImageFilter.cpp" #endif #endif //__itkKspaceImageFilter_h_