16 #ifndef __itkAnalyticalDiffusionQballReconstructionImageFilter_cpp
17 #define __itkAnalyticalDiffusionQballReconstructionImageFilter_cpp
20 #include <itkImageRegionConstIterator.h>
21 #include <itkImageRegionConstIteratorWithIndex.h>
22 #include <itkImageRegionIterator.h>
24 #include <vnl/vnl_vector.h>
26 #include <boost/version.hpp>
31 #define _USE_MATH_DEFINES
34 #include <boost/math/special_functions.hpp>
42 #define QBALL_ANAL_RECON_PI M_PI
44 template<
class T,
class TG,
class TO,
int L,
int NODF>
45 AnalyticalDiffusionQballReconstructionImageFilter<T,TG,TO,L,NODF>
46 ::AnalyticalDiffusionQballReconstructionImageFilter() :
47 m_GradientDirectionContainer(NULL),
48 m_NumberOfGradientDirections(0),
49 m_NumberOfBaselineImages(1),
53 m_DirectionsDuplicated(false),
56 m_UseMrtrixBasis(false)
60 this->SetNumberOfRequiredInputs( 1 );
65 class TReferenceImagePixelType,
66 class TGradientImagePixelType,
71 TReferenceImagePixelType,TGradientImagePixelType,TOdfPixelType,
72 NOrderL,NrOdfDirections>::OdfPixelType
74 <TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType,
75 NOrderL, NrOdfDirections>
77 typename NumericTraits<ReferencePixelType>::AccumulateType b0 )
79 switch( m_NormalizationMethod )
83 TOdfPixelType sum = 0;
85 for(
int i=0; i<NrOdfDirections; i++)
95 case QBAR_B_ZERO_B_VALUE:
97 for(
int i=0; i<NrOdfDirections; i++)
99 odf[i] = ((TOdfPixelType)log((TOdfPixelType)b0)-odf[i])/m_BValue;
117 for(
int i=0; i<NrOdfDirections; i++)
119 odf[i] = ((TOdfPixelType)log((TOdfPixelType)b0)-odf[i])/m_BValue;
124 case QBAR_RAW_SIGNAL:
129 case QBAR_SOLID_ANGLE:
131 for(
int i=0; i<NrOdfDirections; i++)
136 case QBAR_NONNEG_SOLID_ANGLE:
147 class TReferenceImagePixelType,
148 class TGradientImagePixelType,
152 vnl_vector<TOdfPixelType>
154 <TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType,
155 NOrderL, NrOdfDirections>
156 ::PreNormalize( vnl_vector<TOdfPixelType> vec,
157 typename NumericTraits<ReferencePixelType>::AccumulateType b0 )
159 switch( m_NormalizationMethod )
164 double b0f = (double)b0;
165 for(
int i=0; i<n; i++)
172 case QBAR_B_ZERO_B_VALUE:
175 for(
int i=0; i<n; i++)
180 vec[i] = log(vec[i]);
198 for(
int i=0; i<n; i++)
203 vec[i] = log(vec[i]);
208 case QBAR_RAW_SIGNAL:
213 case QBAR_SOLID_ANGLE:
214 case QBAR_NONNEG_SOLID_ANGLE:
217 double b0f = (double)b0;
218 for(
int i=0; i<n; i++)
224 else if (vec[i]<m_Delta1)
225 vec[i] = m_Delta1/2 + vec[i]*vec[i]/(2*m_Delta1);
227 vec[i] = 1-m_Delta2/2;
228 else if (vec[i]>=1-m_Delta2)
229 vec[i] = 1-m_Delta2/2-(1-vec[i])*(1-vec[i])/(2*m_Delta2);
231 vec[i] = log(-log(vec[i]));
241 template<
class T,
class TG,
class TO,
int L,
int NODF>
252 if( m_NumberOfGradientDirections < (L*L + L + 2)/2 + L )
254 itkExceptionMacro( <<
"Not enough gradient directions supplied (" << m_NumberOfGradientDirections <<
"). At least " << (L*L + L + 2)/2 + L <<
" needed for SH-order " << L);
258 std::string gradientImageClassName(
259 this->ProcessObject::GetInput(0)->GetNameOfClass());
260 if ( strcmp(gradientImageClassName.c_str(),
"VectorImage") != 0 )
262 itkExceptionMacro( <<
263 "There is only one Gradient image. I expect that to be a VectorImage. "
264 <<
"But its of type: " << gradientImageClassName );
267 this->ComputeReconstructionMatrix();
270 this->ProcessObject::GetInput(0) );
273 m_BZeroImage->SetSpacing( img->GetSpacing() );
274 m_BZeroImage->SetOrigin( img->GetOrigin() );
275 m_BZeroImage->SetDirection( img->GetDirection() );
276 m_BZeroImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion());
277 m_BZeroImage->SetBufferedRegion( img->GetLargestPossibleRegion() );
278 m_BZeroImage->Allocate();
281 m_ODFSumImage->SetSpacing( img->GetSpacing() );
282 m_ODFSumImage->SetOrigin( img->GetOrigin() );
283 m_ODFSumImage->SetDirection( img->GetDirection() );
284 m_ODFSumImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion());
285 m_ODFSumImage->SetBufferedRegion( img->GetLargestPossibleRegion() );
286 m_ODFSumImage->Allocate();
289 m_CoefficientImage->SetSpacing( img->GetSpacing() );
290 m_CoefficientImage->SetOrigin( img->GetOrigin() );
291 m_CoefficientImage->SetDirection( img->GetDirection() );
292 m_CoefficientImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion());
293 m_CoefficientImage->SetBufferedRegion( img->GetLargestPossibleRegion() );
294 m_CoefficientImage->Allocate();
296 if(m_NormalizationMethod == QBAR_SOLID_ANGLE || m_NormalizationMethod == QBAR_NONNEG_SOLID_ANGLE)
300 template<
class T,
class TG,
class TO,
int L,
int NODF>
306 static_cast< OutputImageType *
>(this->ProcessObject::GetPrimaryOutput());
308 ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread);
311 ImageRegionIterator< BZeroImageType > oit2(m_BZeroImage, outputRegionForThread);
314 ImageRegionIterator< FloatImageType > oit3(m_ODFSumImage, outputRegionForThread);
317 ImageRegionIterator< CoefficientImageType > oit4(m_CoefficientImage, outputRegionForThread);
320 typedef ImageRegionConstIterator< GradientImagesType > GradientIteratorType;
327 this->ProcessObject::GetInput(0) );
329 GradientIteratorType git(gradientImagePointer, outputRegionForThread );
333 std::vector<unsigned int> baselineind;
335 std::vector<unsigned int> gradientind;
338 for(GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin();
339 gdcit != this->m_GradientDirectionContainer->End(); ++gdcit)
341 if(gdcit.Value().one_norm() <= 0.0)
342 baselineind.push_back(gdcit.Index());
344 gradientind.push_back(gdcit.Index());
347 if( m_DirectionsDuplicated )
349 int gradIndSize = gradientind.size();
350 for(
int i=0; i<gradIndSize; i++)
351 gradientind.push_back(gradientind[i]);
354 while( !git.IsAtEnd() )
356 GradientVectorType b = git.Get();
358 typename NumericTraits<ReferencePixelType>::AccumulateType b0 = NumericTraits<ReferencePixelType>::Zero;
361 for(
unsigned int i = 0; i < baselineind.size(); ++i)
363 b0 += b[baselineind[i]];
365 b0 /= this->m_NumberOfBaselineImages;
369 vnl_vector<TO> B(m_NumberOfGradientDirections);
371 if( (b0 != 0) && (b0 >= m_Threshold) )
373 for(
unsigned int i = 0; i< m_NumberOfGradientDirections; i++ )
375 B[i] =
static_cast<TO
>(b[gradientind[i]]);
378 B = PreNormalize(B, b0);
379 if(m_NormalizationMethod == QBAR_SOLID_ANGLE)
381 vnl_vector<TO> coeffs(m_NumberCoefficients);
382 coeffs = ( (*m_CoeffReconstructionMatrix) * B );
384 odf = ( (*m_SphericalHarmonicBasisMatrix) * coeffs ).data_block();
385 coeffPixel = coeffs.data_block();
387 else if(m_NormalizationMethod == QBAR_NONNEG_SOLID_ANGLE)
396 itkExceptionMacro( <<
"Nonnegative Solid Angle not yet implemented");
400 vnl_vector<TO> coeffs(m_NumberCoefficients);
401 coeffs = ( (*m_CoeffReconstructionMatrix) * B );
403 coeffPixel = coeffs.data_block();
404 odf = ( (*m_ReconstructionMatrix) * B ).data_block();
413 for (
unsigned int k=0; k<odf.Size(); k++)
414 sum += (
float) odf[k];
416 oit4.Set(coeffPixel);
424 std::cout <<
"One Thread finished reconstruction" << std::endl;
427 template<
class T,
class TG,
class TO,
int L,
int NODF>
431 vnl_matrix<double> A = (*pA);
432 std::ofstream myfile;
434 std::locale originalLocale = myfile.getloc();
437 myfile.open (fname.c_str());
439 for(
unsigned int i=0; i<A.rows(); i++)
441 for(
unsigned int j=0; j<A.columns(); j++)
443 myfile << A(i,j) <<
" ";
444 if(j==A.columns()-1 && i!=A.rows()-1)
451 myfile.imbue( originalLocale );
454 template<
class T,
class TG,
class TO,
int L,
int NODF>
458 double phi, theta, r;
459 r = sqrt(x*x+y*y+z*z);
472 spherical[1] = theta;
476 template<
class T,
class TG,
class TO,
int L,
int NODF>
478 ::Yj(
int m,
int l,
double theta,
double phi,
bool useMRtrixBasis)
483 return sqrt(2.0)*spherical_harmonic_r(l, -m, theta, phi);
485 return spherical_harmonic_r(l, m, theta, phi);
487 return pow(-1.0,m)*sqrt(2.0)*spherical_harmonic_i(l, m, theta, phi);
491 double plm = legendre_p<double>(l,abs(m),-cos(theta));
492 double mag = sqrt((
double)(2*l+1)/(4.0*
M_PI)*factorial<double>(l-abs(m))/factorial<double>(l+abs(m)))*plm;
494 return mag*cos(m*phi);
498 return mag*sin(-m*phi);
504 template<
class T,
class TG,
class TO,
int L,
int NODF>
515 for(
int i=1;i<l;i+=2) prod1 *= i;
517 for(
int i=2;i<=l;i+=2) prod2 *= i;
518 return pow(-1.0,l/2.0)*(prod1/prod2);
522 template<
class T,
class TG,
class TO,
int L,
int NODF>
530 if( m_NumberOfGradientDirections < (L*L + L + 2)/2 + L )
532 itkExceptionMacro( <<
"Not enough gradient directions supplied (" << m_NumberOfGradientDirections <<
"). At least " << (L*L + L + 2)/2 + L <<
" needed for SH-order " << L);
537 bool warning =
false;
538 for(GradientDirectionContainerType::ConstIterator gdcit1 = this->m_GradientDirectionContainer->Begin();
539 gdcit1 != this->m_GradientDirectionContainer->End(); ++gdcit1)
541 for(GradientDirectionContainerType::ConstIterator gdcit2 = this->m_GradientDirectionContainer->Begin();
542 gdcit2 != this->m_GradientDirectionContainer->End(); ++gdcit2)
544 if(gdcit1.Value() == gdcit2.Value() && gdcit1.Index() != gdcit2.Index())
546 itkWarningMacro( <<
"Some of the Diffusion Gradients equal each other. Corresponding image data should be averaged before calling this filter." );
557 vnl_vector<double> centerMass(3);
558 centerMass.fill(0.0);
560 for(GradientDirectionContainerType::ConstIterator gdcit1 = this->m_GradientDirectionContainer->Begin();
561 gdcit1 != this->m_GradientDirectionContainer->End(); ++gdcit1)
563 if(gdcit1.Value().one_norm() > 0.0)
565 centerMass += gdcit1.Value();
570 if(centerMass.two_norm() > 0.1)
572 m_DirectionsDuplicated =
true;
573 m_NumberOfGradientDirections *= 2;
577 vnl_matrix<double> *Q =
new vnl_matrix<double>(3, m_NumberOfGradientDirections);
581 for(GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin();
582 gdcit != this->m_GradientDirectionContainer->End(); ++gdcit)
584 if(gdcit.Value().one_norm() > 0.0)
586 double x = gdcit.Value().get(0);
587 double y = gdcit.Value().get(1);
588 double z = gdcit.Value().get(2);
590 Cart2Sph(x,y,z,cart);
593 (*Q)(2,i++) = cart[2];
596 if(m_DirectionsDuplicated)
598 for(GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin();
599 gdcit != this->m_GradientDirectionContainer->End(); ++gdcit)
601 if(gdcit.Value().one_norm() > 0.0)
603 double x = gdcit.Value().get(0);
604 double y = gdcit.Value().get(1);
605 double z = gdcit.Value().get(2);
607 Cart2Sph(x,y,z,cart);
610 (*Q)(2,i++) = cart[2];
617 m_NumberCoefficients = (int)(l*l + l + 2.0)/2.0 + l;
618 vnl_matrix<double>* B =
new vnl_matrix<double>(m_NumberOfGradientDirections,m_NumberCoefficients);
619 vnl_matrix<double>* _L =
new vnl_matrix<double>(m_NumberCoefficients,m_NumberCoefficients);
621 vnl_matrix<double>* LL =
new vnl_matrix<double>(m_NumberCoefficients,m_NumberCoefficients);
623 vnl_matrix<double>* P =
new vnl_matrix<double>(m_NumberCoefficients,m_NumberCoefficients);
625 vnl_matrix<double>* Inv =
new vnl_matrix<double>(m_NumberCoefficients,m_NumberCoefficients);
627 vnl_vector<int>* lj =
new vnl_vector<int>(m_NumberCoefficients);
628 m_LP =
new vnl_vector<double>(m_NumberCoefficients);
630 for(
unsigned int i=0; i<m_NumberOfGradientDirections; i++)
632 for(
int k=0; k<=l; k+=2)
634 for(
int m=-k; m<=k; m++)
636 int j = (k*k + k + 2)/2 + m - 1;
637 (*_L)(j,j) = -k*(k+1);
638 (*m_LP)(j) = -k*(k+1);
640 double phi = (*Q)(0,i);
641 double th = (*Q)(1,i);
642 (*B)(i,j) = Yj(m,k,th,phi, m_UseMrtrixBasis);
652 for(
int i=0; i<m_NumberCoefficients; i++)
658 if(m_NormalizationMethod == QBAR_SOLID_ANGLE || m_NormalizationMethod == QBAR_NONNEG_SOLID_ANGLE)
661 (*m_LP)(i) *= (*P)(i,i);
665 (*P)(i,i) = Legendre0((*lj)[i]);
668 m_B_t =
new vnl_matrix<double>(B->transpose());
670 vnl_matrix<double> B_t_B = (*m_B_t) * (*B);
672 vnl_matrix<double> lambdaLL(m_NumberCoefficients,m_NumberCoefficients);
673 lambdaLL.update((*LL));
674 lambdaLL *= m_Lambda;
677 vnl_matrix<double> tmp( B_t_B + lambdaLL);
678 vnl_matrix_inverse<double> *pseudoInverse
679 =
new vnl_matrix_inverse<double>( tmp );
681 (*Inv) = pseudoInverse->pinverse();
683 vnl_matrix<double> temp((*Inv) * (*m_B_t));
685 switch(m_NormalizationMethod)
688 case QBAR_RAW_SIGNAL:
691 case QBAR_B_ZERO_B_VALUE:
696 case QBAR_SOLID_ANGLE:
697 temp = fac1 * (*P) * (*_L) * temp;
699 case QBAR_NONNEG_SOLID_ANGLE:
705 m_CoeffReconstructionMatrix =
new vnl_matrix<TO>(m_NumberCoefficients,m_NumberOfGradientDirections);
706 for(
int i=0; i<m_NumberCoefficients; i++)
708 for(
unsigned int j=0; j<m_NumberOfGradientDirections; j++)
710 (*m_CoeffReconstructionMatrix)(i,j) = (
float) temp(i,j);
716 int NOdfDirections = NODF;
717 vnl_matrix_fixed<double, 3, NODF>* U =
720 m_SphericalHarmonicBasisMatrix =
new vnl_matrix<TO>(NOdfDirections,m_NumberCoefficients);
721 vnl_matrix<double>* sphericalHarmonicBasisMatrix2
722 =
new vnl_matrix<double>(NOdfDirections,m_NumberCoefficients);
723 for(
int i=0; i<NOdfDirections; i++)
725 double x = (*U)(0,i);
726 double y = (*U)(1,i);
727 double z = (*U)(2,i);
729 Cart2Sph(x,y,z,cart);
735 for(
int i=0; i<NOdfDirections; i++)
737 for(
int k=0; k<=l; k+=2)
739 for(
int m=-k; m<=k; m++)
741 int j = (k*k + k + 2)/2 + m - 1;
742 double phi = (*U)(0,i);
743 double th = (*U)(1,i);
744 (*m_SphericalHarmonicBasisMatrix)(i,j) = Yj(m,k,th,phi,m_UseMrtrixBasis);
745 (*sphericalHarmonicBasisMatrix2)(i,j) = (*m_SphericalHarmonicBasisMatrix)(i,j);
750 m_ReconstructionMatrix =
new vnl_matrix<TO>(NOdfDirections,m_NumberOfGradientDirections);
751 *m_ReconstructionMatrix = (*m_SphericalHarmonicBasisMatrix) * (*m_CoeffReconstructionMatrix);
755 template<
class T,
class TG,
class TO,
int L,
int NODF>
762 for(GradientDirectionContainerType::ConstIterator it = gradientDirection->Begin();
763 it != gradientDirection->End(); it++)
765 this->m_GradientDirectionContainer->push_back(it.Value());
769 unsigned int numImages = gradientDirection->Size();
770 this->m_NumberOfBaselineImages = 0;
771 for(GradientDirectionContainerType::Iterator it = this->m_GradientDirectionContainer->Begin();
772 it != this->m_GradientDirectionContainer->End(); it++)
774 if(it.Value().one_norm() <= 0.0)
776 this->m_NumberOfBaselineImages++;
780 it.Value() = it.Value() / it.Value().two_norm();
784 this->m_NumberOfGradientDirections = numImages - this->m_NumberOfBaselineImages;
788 if( gradientImage->GetVectorLength() != this->m_NumberOfBaselineImages + m_NumberOfGradientDirections )
790 itkExceptionMacro( << m_NumberOfGradientDirections <<
" gradients + " << this->m_NumberOfBaselineImages
791 <<
"baselines = " << m_NumberOfGradientDirections + this->m_NumberOfBaselineImages
792 <<
" directions specified but image has " << gradientImage->GetVectorLength()
796 this->ProcessObject::SetNthInput( 0, const_cast< GradientImagesType* >(gradientImage) );
799 template<
class T,
class TG,
class TO,
int L,
int NODF>
804 std::locale originalLocale = os.getloc();
807 Superclass::PrintSelf(os,indent);
809 os << indent <<
"OdfReconstructionMatrix: " << m_ReconstructionMatrix << std::endl;
810 if ( m_GradientDirectionContainer )
811 os << indent <<
"GradientDirectionContainer: " << m_GradientDirectionContainer << std::endl;
813 os << indent <<
"GradientDirectionContainer: (Gradient directions not set)" << std::endl;
815 os << indent <<
"NumberOfGradientDirections: " << m_NumberOfGradientDirections << std::endl;
816 os << indent <<
"NumberOfBaselineImages: " << m_NumberOfBaselineImages << std::endl;
817 os << indent <<
"Threshold for reference B0 image: " << m_Threshold << std::endl;
818 os << indent <<
"BValue: " << m_BValue << std::endl;
819 os.imbue( originalLocale );
824 #endif // __itkAnalyticalDiffusionQballReconstructionImageFilter_cpp
static void tofile2(vnl_matrix< double > *A, std::string fname)
itk::SmartPointer< Self > Pointer
VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType
Vector< TOdfPixelType, NrOdfDirections > OdfPixelType
static double Yj(int m, int k, double theta, double phi, bool useMRtrixBasis=false)
void SetGradientImage(const GradientDirectionContainerType *, const GradientImagesType *image)
#define QBALL_ANAL_RECON_PI
void PrintSelf(std::ostream &os, Indent indent) const
void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType)
This class takes as input one or more reference image (acquired in the absence of diffusion sensitizi...
TReferenceImagePixelType ReferencePixelType
void BeforeThreadedGenerateData()
void ComputeReconstructionMatrix()
static void Cart2Sph(double x, double y, double z, double *cart)
Superclass::OutputImageRegionType OutputImageRegionType
void Normalize(itk::Image< TPixel, VImageDimension > *itkImage, mitk::Image::Pointer im2, mitk::Image::Pointer mask1, std::string output)
MITKCORE_EXPORT const ScalarType eps
VectorImage< GradientPixelType, 3 > GradientImagesType
OdfImageType OutputImageType
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.