Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
itkAnalyticalDiffusionQballReconstructionImageFilter.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 #ifndef __itkAnalyticalDiffusionQballReconstructionImageFilter_cpp
17 #define __itkAnalyticalDiffusionQballReconstructionImageFilter_cpp
18 
20 #include <itkImageRegionConstIterator.h>
21 #include <itkImageRegionConstIteratorWithIndex.h>
22 #include <itkImageRegionIterator.h>
23 #include <itkArray.h>
24 #include <vnl/vnl_vector.h>
25 
26 #include <boost/version.hpp>
27 #include <stdio.h>
28 #include <locale>
29 #include <fstream>
30 
31 #define _USE_MATH_DEFINES
32 #include <math.h>
33 
34 #include <boost/math/special_functions.hpp>
35 
36 #include "itkPointShell.h"
37 
38 using namespace boost::math;
39 
40 namespace itk {
41 
42 #define QBALL_ANAL_RECON_PI M_PI
43 
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),
50  m_Threshold(NumericTraits< ReferencePixelType >::NonpositiveMin()),
51  m_BValue(1.0),
52  m_Lambda(0.0),
53  m_DirectionsDuplicated(false),
54  m_Delta1(0.001),
55  m_Delta2(0.001),
56  m_UseMrtrixBasis(false)
57 {
58  // At least 1 inputs is necessary for a vector image.
59  // For images added one at a time we need at least six
60  this->SetNumberOfRequiredInputs( 1 );
61 }
62 
63 
64 template<
65  class TReferenceImagePixelType,
66  class TGradientImagePixelType,
67  class TOdfPixelType,
68  int NOrderL,
69  int NrOdfDirections>
71 TReferenceImagePixelType,TGradientImagePixelType,TOdfPixelType,
72 NOrderL,NrOdfDirections>::OdfPixelType
74 <TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType,
75 NOrderL, NrOdfDirections>
77  typename NumericTraits<ReferencePixelType>::AccumulateType b0 )
78 {
79  switch( m_NormalizationMethod )
80  {
81  case QBAR_STANDARD:
82  {
83  TOdfPixelType sum = 0;
84 
85  for(int i=0; i<NrOdfDirections; i++)
86  {
87  sum += odf[i];
88  }
89  if(sum>0)
90  odf /= sum;
91 
92  return odf;
93  break;
94  }
95  case QBAR_B_ZERO_B_VALUE:
96  {
97  for(int i=0; i<NrOdfDirections; i++)
98  {
99  odf[i] = ((TOdfPixelType)log((TOdfPixelType)b0)-odf[i])/m_BValue;
100  }
101  return odf;
102  break;
103  }
104  case QBAR_B_ZERO:
105  {
106  odf *= 1.0/b0;
107  return odf;
108  break;
109  }
110  case QBAR_NONE:
111  {
112  return odf;
113  break;
114  }
115  case QBAR_ADC_ONLY:
116  {
117  for(int i=0; i<NrOdfDirections; i++)
118  {
119  odf[i] = ((TOdfPixelType)log((TOdfPixelType)b0)-odf[i])/m_BValue;
120  }
121  return odf;
122  break;
123  }
124  case QBAR_RAW_SIGNAL:
125  {
126  return odf;
127  break;
128  }
129  case QBAR_SOLID_ANGLE:
130  {
131  for(int i=0; i<NrOdfDirections; i++)
132  odf[i] *= QBALL_ANAL_RECON_PI*4/NrOdfDirections;
133 
134  break;
135  }
136  case QBAR_NONNEG_SOLID_ANGLE:
137  {
138  break;
139  }
140  }
141 
142  return odf;
143 }
144 
145 
146 template<
147  class TReferenceImagePixelType,
148  class TGradientImagePixelType,
149  class TOdfPixelType,
150  int NOrderL,
151  int NrOdfDirections>
152 vnl_vector<TOdfPixelType>
154 <TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType,
155 NOrderL, NrOdfDirections>
156 ::PreNormalize( vnl_vector<TOdfPixelType> vec,
157  typename NumericTraits<ReferencePixelType>::AccumulateType b0 )
158 {
159  switch( m_NormalizationMethod )
160  {
161  case QBAR_STANDARD:
162  {
163  int n = vec.size();
164  double b0f = (double)b0;
165  for(int i=0; i<n; i++)
166  {
167  vec[i] = vec[i]/b0f;
168  }
169  return vec;
170  break;
171  }
172  case QBAR_B_ZERO_B_VALUE:
173  {
174  int n = vec.size();
175  for(int i=0; i<n; i++)
176  {
177  if (vec[i]<=0)
178  vec[i] = 0.001;
179 
180  vec[i] = log(vec[i]);
181  }
182  return vec;
183  break;
184  }
185  case QBAR_B_ZERO:
186  {
187  return vec;
188  break;
189  }
190  case QBAR_NONE:
191  {
192  return vec;
193  break;
194  }
195  case QBAR_ADC_ONLY:
196  {
197  int n = vec.size();
198  for(int i=0; i<n; i++)
199  {
200  if (vec[i]<=0)
201  vec[i] = 0.001;
202 
203  vec[i] = log(vec[i]);
204  }
205  return vec;
206  break;
207  }
208  case QBAR_RAW_SIGNAL:
209  {
210  return vec;
211  break;
212  }
213  case QBAR_SOLID_ANGLE:
214  case QBAR_NONNEG_SOLID_ANGLE:
215  {
216  int n = vec.size();
217  double b0f = (double)b0;
218  for(int i=0; i<n; i++)
219  {
220  vec[i] = vec[i]/b0f;
221 
222  if (vec[i]<0)
223  vec[i] = m_Delta1;
224  else if (vec[i]<m_Delta1)
225  vec[i] = m_Delta1/2 + vec[i]*vec[i]/(2*m_Delta1);
226  else if (vec[i]>=1)
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);
230 
231  vec[i] = log(-log(vec[i]));
232  }
233  return vec;
234  break;
235  }
236  }
237 
238  return vec;
239 }
240 
241 template< class T, class TG, class TO, int L, int NODF>
244 {
245  // If we have more than 2 inputs, then each input, except the first is a
246  // gradient image. The number of gradient images must match the number of
247  // gradient directions.
248  //const unsigned int numberOfInputs = this->GetNumberOfInputs();
249 
250  // There need to be at least 6 gradient directions to be able to compute the
251  // tensor basis
252  if( m_NumberOfGradientDirections < (L*L + L + 2)/2 + L )
253  {
254  itkExceptionMacro( << "Not enough gradient directions supplied (" << m_NumberOfGradientDirections << "). At least " << (L*L + L + 2)/2 + L << " needed for SH-order " << L);
255  }
256 
257  // Input must be an itk::VectorImage.
258  std::string gradientImageClassName(
259  this->ProcessObject::GetInput(0)->GetNameOfClass());
260  if ( strcmp(gradientImageClassName.c_str(),"VectorImage") != 0 )
261  {
262  itkExceptionMacro( <<
263  "There is only one Gradient image. I expect that to be a VectorImage. "
264  << "But its of type: " << gradientImageClassName );
265  }
266 
267  this->ComputeReconstructionMatrix();
268 
269  typename GradientImagesType::Pointer img = static_cast< GradientImagesType * >(
270  this->ProcessObject::GetInput(0) );
271 
272  m_BZeroImage = BZeroImageType::New();
273  m_BZeroImage->SetSpacing( img->GetSpacing() ); // Set the image spacing
274  m_BZeroImage->SetOrigin( img->GetOrigin() ); // Set the image origin
275  m_BZeroImage->SetDirection( img->GetDirection() ); // Set the image direction
276  m_BZeroImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion());
277  m_BZeroImage->SetBufferedRegion( img->GetLargestPossibleRegion() );
278  m_BZeroImage->Allocate();
279 
280  m_ODFSumImage = BZeroImageType::New();
281  m_ODFSumImage->SetSpacing( img->GetSpacing() ); // Set the image spacing
282  m_ODFSumImage->SetOrigin( img->GetOrigin() ); // Set the image origin
283  m_ODFSumImage->SetDirection( img->GetDirection() ); // Set the image direction
284  m_ODFSumImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion());
285  m_ODFSumImage->SetBufferedRegion( img->GetLargestPossibleRegion() );
286  m_ODFSumImage->Allocate();
287 
288  m_CoefficientImage = CoefficientImageType::New();
289  m_CoefficientImage->SetSpacing( img->GetSpacing() ); // Set the image spacing
290  m_CoefficientImage->SetOrigin( img->GetOrigin() ); // Set the image origin
291  m_CoefficientImage->SetDirection( img->GetDirection() ); // Set the image direction
292  m_CoefficientImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion());
293  m_CoefficientImage->SetBufferedRegion( img->GetLargestPossibleRegion() );
294  m_CoefficientImage->Allocate();
295 
296  if(m_NormalizationMethod == QBAR_SOLID_ANGLE || m_NormalizationMethod == QBAR_NONNEG_SOLID_ANGLE)
297  m_Lambda = 0.0;
298 }
299 
300 template< class T, class TG, class TO, int L, int NODF>
302 ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread,
303  ThreadIdType )
304 {
305  typename OutputImageType::Pointer outputImage =
306  static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput());
307 
308  ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread);
309  oit.GoToBegin();
310 
311  ImageRegionIterator< BZeroImageType > oit2(m_BZeroImage, outputRegionForThread);
312  oit2.GoToBegin();
313 
314  ImageRegionIterator< FloatImageType > oit3(m_ODFSumImage, outputRegionForThread);
315  oit3.GoToBegin();
316 
317  ImageRegionIterator< CoefficientImageType > oit4(m_CoefficientImage, outputRegionForThread);
318  oit4.GoToBegin();
319 
320  typedef ImageRegionConstIterator< GradientImagesType > GradientIteratorType;
321  typedef typename GradientImagesType::PixelType GradientVectorType;
322  typename GradientImagesType::Pointer gradientImagePointer = NULL;
323 
324  // Would have liked a dynamic_cast here, but seems SGI doesn't like it
325  // The enum will ensure that an inappropriate cast is not done
326  gradientImagePointer = static_cast< GradientImagesType * >(
327  this->ProcessObject::GetInput(0) );
328 
329  GradientIteratorType git(gradientImagePointer, outputRegionForThread );
330  git.GoToBegin();
331 
332  // Compute the indicies of the baseline images and gradient images
333  std::vector<unsigned int> baselineind; // contains the indicies of
334  // the baseline images
335  std::vector<unsigned int> gradientind; // contains the indicies of
336  // the gradient images
337 
338  for(GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin();
339  gdcit != this->m_GradientDirectionContainer->End(); ++gdcit)
340  {
341  if(gdcit.Value().one_norm() <= 0.0)
342  baselineind.push_back(gdcit.Index());
343  else
344  gradientind.push_back(gdcit.Index());
345  }
346 
347  if( m_DirectionsDuplicated )
348  {
349  int gradIndSize = gradientind.size();
350  for(int i=0; i<gradIndSize; i++)
351  gradientind.push_back(gradientind[i]);
352  }
353 
354  while( !git.IsAtEnd() )
355  {
356  GradientVectorType b = git.Get();
357 
358  typename NumericTraits<ReferencePixelType>::AccumulateType b0 = NumericTraits<ReferencePixelType>::Zero;
359 
360  // Average the baseline image pixels
361  for(unsigned int i = 0; i < baselineind.size(); ++i)
362  {
363  b0 += b[baselineind[i]];
364  }
365  b0 /= this->m_NumberOfBaselineImages;
366 
367  OdfPixelType odf(0.0);
368  typename CoefficientImageType::PixelType coeffPixel(0.0);
369  vnl_vector<TO> B(m_NumberOfGradientDirections);
370 
371  if( (b0 != 0) && (b0 >= m_Threshold) )
372  {
373  for( unsigned int i = 0; i< m_NumberOfGradientDirections; i++ )
374  {
375  B[i] = static_cast<TO>(b[gradientind[i]]);
376  }
377 
378  B = PreNormalize(B, b0);
379  if(m_NormalizationMethod == QBAR_SOLID_ANGLE)
380  {
381  vnl_vector<TO> coeffs(m_NumberCoefficients);
382  coeffs = ( (*m_CoeffReconstructionMatrix) * B );
383  coeffs[0] += 1.0/(2.0*sqrt(QBALL_ANAL_RECON_PI));
384  odf = ( (*m_SphericalHarmonicBasisMatrix) * coeffs ).data_block();
385  coeffPixel = coeffs.data_block();
386  }
387  else if(m_NormalizationMethod == QBAR_NONNEG_SOLID_ANGLE)
388  {
396  itkExceptionMacro( << "Nonnegative Solid Angle not yet implemented");
397  }
398  else
399  {
400  vnl_vector<TO> coeffs(m_NumberCoefficients);
401  coeffs = ( (*m_CoeffReconstructionMatrix) * B );
402  coeffs[0] += 1.0/(2.0*sqrt(QBALL_ANAL_RECON_PI));
403  coeffPixel = coeffs.data_block();
404  odf = ( (*m_ReconstructionMatrix) * B ).data_block();
405  }
406  odf = Normalize(odf, b0);
407 
408  }
409 
410  oit.Set( odf );
411  oit2.Set( b0 );
412  float sum = 0;
413  for (unsigned int k=0; k<odf.Size(); k++)
414  sum += (float) odf[k];
415  oit3.Set( sum-1 );
416  oit4.Set(coeffPixel);
417  ++oit; // odf image iterator
418  ++oit3; // odf sum image iterator
419  ++oit2; // b0 image iterator
420  ++oit4; // coefficient image iterator
421  ++git; // Gradient image iterator
422  }
423 
424  std::cout << "One Thread finished reconstruction" << std::endl;
425 }
426 
427 template< class T, class TG, class TO, int L, int NODF>
429 ::tofile2(vnl_matrix<double> *pA, std::string fname)
430 {
431  vnl_matrix<double> A = (*pA);
432  std::ofstream myfile;
433  std::locale C("C");
434  std::locale originalLocale = myfile.getloc();
435  myfile.imbue(C);
436 
437  myfile.open (fname.c_str());
438  myfile << "A1=[";
439  for(unsigned int i=0; i<A.rows(); i++)
440  {
441  for(unsigned int j=0; j<A.columns(); j++)
442  {
443  myfile << A(i,j) << " ";
444  if(j==A.columns()-1 && i!=A.rows()-1)
445  myfile << ";";
446  }
447  }
448  myfile << "];";
449  myfile.close();
450 
451  myfile.imbue( originalLocale );
452 }
453 
454 template< class T, class TG, class TO, int L, int NODF>
456 ::Cart2Sph(double x, double y, double z, double *spherical)
457 {
458  double phi, theta, r;
459  r = sqrt(x*x+y*y+z*z);
460 
461  if( r<mitk::eps )
462  {
463  theta = M_PI/2;
464  phi = M_PI/2;
465  }
466  else
467  {
468  theta = acos(z/r);
469  phi = atan2(y, x);
470  }
471  spherical[0] = phi;
472  spherical[1] = theta;
473  spherical[2] = r;
474 }
475 
476 template< class T, class TG, class TO, int L, int NODF>
478 ::Yj(int m, int l, double theta, double phi, bool useMRtrixBasis)
479 {
480  if (!useMRtrixBasis)
481  {
482  if (m<0)
483  return sqrt(2.0)*spherical_harmonic_r(l, -m, theta, phi);
484  else if (m==0)
485  return spherical_harmonic_r(l, m, theta, phi);
486  else
487  return pow(-1.0,m)*sqrt(2.0)*spherical_harmonic_i(l, m, theta, phi);
488  }
489  else
490  {
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;
493  if (m>0)
494  return mag*cos(m*phi);
495  else if (m==0)
496  return mag;
497  else
498  return mag*sin(-m*phi);
499  }
500 
501  return 0;
502 }
503 
504 template< class T, class TG, class TO, int L, int NODF>
507 {
508  if( l%2 != 0 )
509  {
510  return 0;
511  }
512  else
513  {
514  double prod1 = 1.0;
515  for(int i=1;i<l;i+=2) prod1 *= i;
516  double prod2 = 1.0;
517  for(int i=2;i<=l;i+=2) prod2 *= i;
518  return pow(-1.0,l/2.0)*(prod1/prod2);
519  }
520 }
521 
522 template< class T, class TG, class TO, int L, int NODF>
525 {
526 
527  //for(int i=-6;i<7;i++)
528  // std::cout << boost::math::legendre_p<double>(6, i, 0.65657) << std::endl;
529 
530  if( m_NumberOfGradientDirections < (L*L + L + 2)/2 + L )
531  {
532  itkExceptionMacro( << "Not enough gradient directions supplied (" << m_NumberOfGradientDirections << "). At least " << (L*L + L + 2)/2 + L << " needed for SH-order " << L);
533  }
534 
535  {
536  // check for duplicate diffusion gradients
537  bool warning = false;
538  for(GradientDirectionContainerType::ConstIterator gdcit1 = this->m_GradientDirectionContainer->Begin();
539  gdcit1 != this->m_GradientDirectionContainer->End(); ++gdcit1)
540  {
541  for(GradientDirectionContainerType::ConstIterator gdcit2 = this->m_GradientDirectionContainer->Begin();
542  gdcit2 != this->m_GradientDirectionContainer->End(); ++gdcit2)
543  {
544  if(gdcit1.Value() == gdcit2.Value() && gdcit1.Index() != gdcit2.Index())
545  {
546  itkWarningMacro( << "Some of the Diffusion Gradients equal each other. Corresponding image data should be averaged before calling this filter." );
547  warning = true;
548  break;
549  }
550  }
551  if (warning) break;
552  }
553 
554  // handle acquisition schemes where only half of the spherical
555  // shell is sampled by the gradient directions. In this case,
556  // each gradient direction is duplicated in negative direction.
557  vnl_vector<double> centerMass(3);
558  centerMass.fill(0.0);
559  int count = 0;
560  for(GradientDirectionContainerType::ConstIterator gdcit1 = this->m_GradientDirectionContainer->Begin();
561  gdcit1 != this->m_GradientDirectionContainer->End(); ++gdcit1)
562  {
563  if(gdcit1.Value().one_norm() > 0.0)
564  {
565  centerMass += gdcit1.Value();
566  count ++;
567  }
568  }
569  centerMass /= count;
570  if(centerMass.two_norm() > 0.1)
571  {
572  m_DirectionsDuplicated = true;
573  m_NumberOfGradientDirections *= 2;
574  }
575  }
576 
577  vnl_matrix<double> *Q = new vnl_matrix<double>(3, m_NumberOfGradientDirections);
578 
579  {
580  int i = 0;
581  for(GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin();
582  gdcit != this->m_GradientDirectionContainer->End(); ++gdcit)
583  {
584  if(gdcit.Value().one_norm() > 0.0)
585  {
586  double x = gdcit.Value().get(0);
587  double y = gdcit.Value().get(1);
588  double z = gdcit.Value().get(2);
589  double cart[3];
590  Cart2Sph(x,y,z,cart);
591  (*Q)(0,i) = cart[0];
592  (*Q)(1,i) = cart[1];
593  (*Q)(2,i++) = cart[2];
594  }
595  }
596  if(m_DirectionsDuplicated)
597  {
598  for(GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin();
599  gdcit != this->m_GradientDirectionContainer->End(); ++gdcit)
600  {
601  if(gdcit.Value().one_norm() > 0.0)
602  {
603  double x = gdcit.Value().get(0);
604  double y = gdcit.Value().get(1);
605  double z = gdcit.Value().get(2);
606  double cart[3];
607  Cart2Sph(x,y,z,cart);
608  (*Q)(0,i) = cart[0];
609  (*Q)(1,i) = cart[1];
610  (*Q)(2,i++) = cart[2];
611  }
612  }
613  }
614  }
615 
616  int l = L;
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);
620  _L->fill(0.0);
621  vnl_matrix<double>* LL = new vnl_matrix<double>(m_NumberCoefficients,m_NumberCoefficients);
622  LL->fill(0.0);
623  vnl_matrix<double>* P = new vnl_matrix<double>(m_NumberCoefficients,m_NumberCoefficients);
624  P->fill(0.0);
625  vnl_matrix<double>* Inv = new vnl_matrix<double>(m_NumberCoefficients,m_NumberCoefficients);
626  P->fill(0.0);
627  vnl_vector<int>* lj = new vnl_vector<int>(m_NumberCoefficients);
628  m_LP = new vnl_vector<double>(m_NumberCoefficients);
629 
630  for(unsigned int i=0; i<m_NumberOfGradientDirections; i++)
631  {
632  for(int k=0; k<=l; k+=2)
633  {
634  for(int m=-k; m<=k; m++)
635  {
636  int j = (k*k + k + 2)/2 + m - 1;
637  (*_L)(j,j) = -k*(k+1);
638  (*m_LP)(j) = -k*(k+1);
639  (*lj)[j] = k;
640  double phi = (*Q)(0,i);
641  double th = (*Q)(1,i);
642  (*B)(i,j) = Yj(m,k,th,phi, m_UseMrtrixBasis);
643  }
644  }
645  }
646 
647  //vnl_matrix<double> temp((*_L)*(*_L));
648  LL->update(*_L);
649  *LL *= *_L;
650  //tofile2(LL,"LL");
651 
652  for(int i=0; i<m_NumberCoefficients; i++)
653  {
654  // here we leave out the 2*pi multiplication from Descoteaux
655  // this is because we do not want the real integral value
656  // but an average value over the equator.
657 
658  if(m_NormalizationMethod == QBAR_SOLID_ANGLE || m_NormalizationMethod == QBAR_NONNEG_SOLID_ANGLE)
659  {
660  (*P)(i,i) = 2.0*QBALL_ANAL_RECON_PI*Legendre0((*lj)[i]);
661  (*m_LP)(i) *= (*P)(i,i);
662  }
663  else
664  {
665  (*P)(i,i) = Legendre0((*lj)[i]);
666  }
667  }
668  m_B_t = new vnl_matrix<double>(B->transpose());
669  //tofile2(&m_B_t,"m_B_t");
670  vnl_matrix<double> B_t_B = (*m_B_t) * (*B);
671  //tofile2(&B_t_B,"B_t_B");
672  vnl_matrix<double> lambdaLL(m_NumberCoefficients,m_NumberCoefficients);
673  lambdaLL.update((*LL));
674  lambdaLL *= m_Lambda;
675  //tofile2(&lambdaLL,"lLL");
676 
677  vnl_matrix<double> tmp( B_t_B + lambdaLL);
678  vnl_matrix_inverse<double> *pseudoInverse
679  = new vnl_matrix_inverse<double>( tmp );
680 
681  (*Inv) = pseudoInverse->pinverse();
682  //tofile2(Inv,"Inv");
683  vnl_matrix<double> temp((*Inv) * (*m_B_t));
684  double fac1 = (1.0/(16.0*QBALL_ANAL_RECON_PI*QBALL_ANAL_RECON_PI));
685  switch(m_NormalizationMethod)
686  {
687  case QBAR_ADC_ONLY:
688  case QBAR_RAW_SIGNAL:
689  break;
690  case QBAR_STANDARD:
691  case QBAR_B_ZERO_B_VALUE:
692  case QBAR_B_ZERO:
693  case QBAR_NONE:
694  temp = (*P) * temp;
695  break;
696  case QBAR_SOLID_ANGLE:
697  temp = fac1 * (*P) * (*_L) * temp;
698  break;
699  case QBAR_NONNEG_SOLID_ANGLE:
700  break;
701  }
702 
703  //tofile2(&temp,"A");
704 
705  m_CoeffReconstructionMatrix = new vnl_matrix<TO>(m_NumberCoefficients,m_NumberOfGradientDirections);
706  for(int i=0; i<m_NumberCoefficients; i++)
707  {
708  for(unsigned int j=0; j<m_NumberOfGradientDirections; j++)
709  {
710  (*m_CoeffReconstructionMatrix)(i,j) = (float) temp(i,j);
711  }
712  }
713 
714  // this code goes to the image adapter coeffs->odfs later
715 
716  int NOdfDirections = NODF;
717  vnl_matrix_fixed<double, 3, NODF>* U =
719 
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++)
724  {
725  double x = (*U)(0,i);
726  double y = (*U)(1,i);
727  double z = (*U)(2,i);
728  double cart[3];
729  Cart2Sph(x,y,z,cart);
730  (*U)(0,i) = cart[0];
731  (*U)(1,i) = cart[1];
732  (*U)(2,i) = cart[2];
733  }
734 
735  for(int i=0; i<NOdfDirections; i++)
736  {
737  for(int k=0; k<=l; k+=2)
738  {
739  for(int m=-k; m<=k; m++)
740  {
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);
746  }
747  }
748  }
749 
750  m_ReconstructionMatrix = new vnl_matrix<TO>(NOdfDirections,m_NumberOfGradientDirections);
751  *m_ReconstructionMatrix = (*m_SphericalHarmonicBasisMatrix) * (*m_CoeffReconstructionMatrix);
752 
753 }
754 
755 template< class T, class TG, class TO, int L, int NODF>
758  const GradientImagesType *gradientImage )
759 {
760  // Copy Gradient Direction Container
761  this->m_GradientDirectionContainer = GradientDirectionContainerType::New();
762  for(GradientDirectionContainerType::ConstIterator it = gradientDirection->Begin();
763  it != gradientDirection->End(); it++)
764  {
765  this->m_GradientDirectionContainer->push_back(it.Value());
766  }
767 
768 
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++)
773  {
774  if(it.Value().one_norm() <= 0.0)
775  {
776  this->m_NumberOfBaselineImages++;
777  }
778  else // Normalize non-zero gradient directions
779  {
780  it.Value() = it.Value() / it.Value().two_norm();
781  }
782  }
783 
784  this->m_NumberOfGradientDirections = numImages - this->m_NumberOfBaselineImages;
785 
786  // ensure that the gradient image we received has as many components as
787  // the number of gradient directions
788  if( gradientImage->GetVectorLength() != this->m_NumberOfBaselineImages + m_NumberOfGradientDirections )
789  {
790  itkExceptionMacro( << m_NumberOfGradientDirections << " gradients + " << this->m_NumberOfBaselineImages
791  << "baselines = " << m_NumberOfGradientDirections + this->m_NumberOfBaselineImages
792  << " directions specified but image has " << gradientImage->GetVectorLength()
793  << " components.");
794  }
795 
796  this->ProcessObject::SetNthInput( 0, const_cast< GradientImagesType* >(gradientImage) );
797 }
798 
799 template< class T, class TG, class TO, int L, int NODF>
801 ::PrintSelf(std::ostream& os, Indent indent) const
802 {
803  std::locale C("C");
804  std::locale originalLocale = os.getloc();
805  os.imbue(C);
806 
807  Superclass::PrintSelf(os,indent);
808 
809  os << indent << "OdfReconstructionMatrix: " << m_ReconstructionMatrix << std::endl;
810  if ( m_GradientDirectionContainer )
811  os << indent << "GradientDirectionContainer: " << m_GradientDirectionContainer << std::endl;
812  else
813  os << indent << "GradientDirectionContainer: (Gradient directions not set)" << std::endl;
814 
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 );
820 }
821 
822 }
823 
824 #endif // __itkAnalyticalDiffusionQballReconstructionImageFilter_cpp
itk::SmartPointer< Self > Pointer
VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType
static double Yj(int m, int k, double theta, double phi, bool useMRtrixBasis=false)
void SetGradientImage(const GradientDirectionContainerType *, const GradientImagesType *image)
void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType)
This class takes as input one or more reference image (acquired in the absence of diffusion sensitizi...
void Normalize(itk::Image< TPixel, VImageDimension > *itkImage, mitk::Image::Pointer im2, mitk::Image::Pointer mask1, std::string output)
Definition: CLBrainMask.cpp:40
MITKCORE_EXPORT const ScalarType eps
unsigned short PixelType
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.