16 #ifndef __itkDiffusionMultiShellQballReconstructionImageFilter_cpp
17 #define __itkDiffusionMultiShellQballReconstructionImageFilter_cpp
21 #include <itkTimeProbe.h>
27 template<
class T,
class TG,
class TO,
int L,
int NODF>
30 m_ReconstructionType(Mode_Standard1Shell),
31 m_Interpolation_Flag(false),
32 m_Interpolation_SHT1_inv(NULL),
33 m_Interpolation_SHT2_inv(NULL),
34 m_Interpolation_SHT3_inv(NULL),
35 m_TARGET_SH_shell1(NULL),
36 m_TARGET_SH_shell2(NULL),
37 m_TARGET_SH_shell3(NULL),
39 m_CoeffReconstructionMatrix(NULL),
40 m_ODFSphericalHarmonicBasisMatrix(NULL),
41 m_GradientDirectionContainer(NULL),
42 m_NumberOfGradientDirections(0),
43 m_NumberOfBaselineImages(0),
46 m_CoefficientImage(NULL),
49 m_IsHemisphericalArrangementOfGradientDirections(false),
50 m_IsArithmeticProgession(false)
54 this->SetNumberOfRequiredInputs( 1 );
58 template<
class T,
class TG,
class TO,
int L,
int NODF>
65 m_NumberOfBaselineImages = 0;
68 for(GradientDirectionContainerType::ConstIterator it = gradientDirection->Begin();
69 it != gradientDirection->End(); it++)
71 this->m_GradientDirectionContainer->push_back(it.Value());
75 if(m_BValueMap.size() == 0){
76 itkWarningMacro(<<
"DiffusionMultiShellQballReconstructionImageFilter.cpp : no GradientIndexMapAvalible");
78 GradientDirectionContainerType::ConstIterator gdcit;
79 for( gdcit = m_GradientDirectionContainer->Begin(); gdcit != m_GradientDirectionContainer->End(); ++gdcit)
81 double bValueKey = int(((m_BValue * gdcit.Value().two_norm() * gdcit.Value().two_norm())+7.5)/10)*10;
82 m_BValueMap[bValueKey].push_back(gdcit.Index());
86 if(m_BValueMap.find(0) == m_BValueMap.end())
88 itkExceptionMacro(<<
"DiffusionMultiShellQballReconstructionImageFilter.cpp : GradientIndxMap with no b-Zero indecies found: check input BValueMap");
92 m_NumberOfBaselineImages = m_BValueMap[0].size();
93 m_NumberOfGradientDirections = gradientDirection->Size() - m_NumberOfBaselineImages;
96 if( gradientImage->GetVectorLength() != m_NumberOfBaselineImages + m_NumberOfGradientDirections )
98 itkExceptionMacro( << m_NumberOfGradientDirections <<
" gradients + " << m_NumberOfBaselineImages
99 <<
"baselines = " << m_NumberOfGradientDirections + m_NumberOfBaselineImages
100 <<
" directions specified but image has " << gradientImage->GetVectorLength()
105 ProcessObject::SetNthInput( 0, const_cast< GradientImagesType* >(gradientImage) );
107 std::string gradientImageClassName(ProcessObject::GetInput(0)->GetNameOfClass());
108 if ( strcmp(gradientImageClassName.c_str(),
"VectorImage") != 0 )
109 itkExceptionMacro( <<
"There is only one Gradient image. I expect that to be a VectorImage. But its of type: " << gradientImageClassName );
114 m_BZeroImage->SetSpacing( img->GetSpacing() );
115 m_BZeroImage->SetOrigin( img->GetOrigin() );
116 m_BZeroImage->SetDirection( img->GetDirection() );
117 m_BZeroImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion());
118 m_BZeroImage->SetBufferedRegion( img->GetLargestPossibleRegion() );
119 m_BZeroImage->Allocate();
122 m_CoefficientImage->SetSpacing( img->GetSpacing() );
123 m_CoefficientImage->SetOrigin( img->GetOrigin() );
124 m_CoefficientImage->SetDirection( img->GetDirection() );
125 m_CoefficientImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion());
126 m_CoefficientImage->SetBufferedRegion( img->GetLargestPossibleRegion() );
127 m_CoefficientImage->Allocate();
131 template<
class TReferenceImagePixelType,
class TGradientImagePixelType,
class TOdfPixelType,
int NOrderL,
int NrOdfDirections>
135 for(
int i=0; i<NrOdfDirections; i++)
137 out[i] = out[i] < 0 ? 0 : out[i];
138 out[i] *=
M_PI * 4 / NrOdfDirections;
142 template<
class TReferenceImagePixelType,
class TGradientImagePixelType,
class TOdfPixelType,
int NOrderL,
int NrOdfDirections>
143 void DiffusionMultiShellQballReconstructionImageFilter<TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType,NOrderL, NrOdfDirections>
144 ::Projection1(vnl_vector<double> & vec,
double delta)
147 for (
unsigned int i=0; i<vec.size(); i++)
148 vec[i]=(vec[i]>=0 && vec[i]<=1)*vec[i]+(vec[i]>1);
151 for (
unsigned int i=0; i< vec.size(); i++)
152 vec[i]=CalculateThreashold(vec[i], delta);
156 template<
class TReferenceImagePixelType,
class TGradientImagePixelType,
class TOdfPixelType,
int NOrderL,
int NrOdfDirections>
157 double DiffusionMultiShellQballReconstructionImageFilter<TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType,NOrderL, NrOdfDirections>
158 ::CalculateThreashold(
const double value,
const double delta)
160 return (value<0)*(0.5*delta) + (value>=0 && value<delta)*(0.5*delta+0.5*(value*value)/delta)
161 + (value>=delta && value<1-delta)*value+(value>=1-delta && value<1)*(1-0.5*delta-0.5*((1-value)*(1-value))/delta)
162 + (value>=1)*(1-0.5*delta);
165 template<
class TReferenceImagePixelType,
class TGradientImagePixelType,
class TOdfPixelType,
int NOrderL,
int NrOdfDirections>
166 void DiffusionMultiShellQballReconstructionImageFilter<TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType,NOrderL, NrOdfDirections>
167 ::Projection2( vnl_vector<double> & E1,vnl_vector<double> & E2, vnl_vector<double> & E3,
double delta )
170 const double sF = sqrt(5.0);
172 vnl_vector<double> vOnes(m_MaxDirections);
175 vnl_matrix<double> T0(m_MaxDirections, 3);
176 vnl_matrix<unsigned char> C(m_MaxDirections, 7);
177 vnl_matrix<double> A(m_MaxDirections, 7);
178 vnl_matrix<double> B(m_MaxDirections, 7);
180 vnl_vector<double> s0(m_MaxDirections);
181 vnl_vector<double> a0(m_MaxDirections);
182 vnl_vector<double> b0(m_MaxDirections);
183 vnl_vector<double> ta(m_MaxDirections);
184 vnl_vector<double> tb(m_MaxDirections);
185 vnl_vector<double> e(m_MaxDirections);
186 vnl_vector<double> m(m_MaxDirections);
187 vnl_vector<double> a(m_MaxDirections);
188 vnl_vector<double> b(m_MaxDirections);
192 for(
unsigned int i = 0 ; i < m_MaxDirections; i++)
194 T0(i,0) = -log(E1(i));
195 T0(i,1) = -log(E2(i));
196 T0(i,2) = -log(E3(i));
203 for(
unsigned int i = 0 ; i < m_MaxDirections; i++)
205 s0[i] = T0(i,0) + T0(i,1) + T0(i,2);
208 for(
unsigned int i = 0; i < m_MaxDirections; i ++)
211 a0[i] = T0(i,0) / s0[i];
213 b0[i] = T0(i,1) / s0[i];
219 m = (tb * 2.0 ) + ta;
221 for(
unsigned int i = 0; i <m_MaxDirections; i++)
223 C(i,0) = (tb[i] < 1+3*delta && 0.5+1.5*(sF+1)*delta < ta[i] && ta[i] < 1-3* (sF+2) *delta);
224 C(i,1) = (e[i] <= -1+3*(2*sF+5)*delta) && (ta[i]>=1-3*(sF+2)*delta);
225 C(i,2) = (m[i] > 3-3*sF*delta) && (-1+3*(2*sF+5)*delta<e[i]) && (e[i]<-3*sF*delta);
226 C(i,3) = (m[i] >= 3-3*sF*delta && e[i] >= -3 *sF * delta);
227 C(i,4) = (2.5 + 1.5*(5+sF)*delta < m[i] && m[i] < 3-3*sF*delta && e[i] > -3*sF*delta);
228 C(i,5) = (ta[i] <= 0.5+1.5 *(sF+1)*delta && m[i] <= 2.5 + 1.5 *(5+sF) * delta);
229 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) );
231 A(i,0)=(bool)C(i,0) * a0(i);
232 A(i,1)=(bool)C(i,1) * (1.0/3.0-(sF+2)*delta);
233 A(i,2)=(bool)C(i,2) * (0.2+0.8*a0(i)-0.4*b0(i)-delta/sF);
234 A(i,3)=(bool)C(i,3) * (0.2+delta/sF);
235 A(i,4)=(bool)C(i,4) * (0.2*a0(i)+0.4*b0(i)+2*delta/sF);
236 A(i,5)=(bool)C(i,5) * (1.0/6.0+0.5*(sF+1)*delta);
237 A(i,6)=(bool)C(i,6) * a0(i);
239 B(i,0)=(bool)C(i,0) * (1.0/3.0+delta);
240 B(i,1)=(bool)C(i,1) * (1.0/3.0+delta);
241 B(i,2)=(bool)C(i,2) * (0.4-0.4*a0(i)+0.2*b0(i)-2*delta/sF);
242 B(i,3)=(bool)C(i,3) * (0.4-3*delta/sF);
243 B(i,4)=(bool)C(i,4) * (0.4*a0(i)+0.8*b0(i)-delta/sF);
244 B(i,5)=(bool)C(i,5) * (1.0/3.0+delta);
245 B(i,6)=(bool)C(i,6) * b0(i);
248 for(
unsigned int i = 0 ; i < m_MaxDirections; i++)
252 for(
int j = 0 ; j < 7; j++)
261 for(
unsigned int i = 0; i < m_MaxDirections; i++)
263 E1(i) = exp(-(a[i]*s0[i]));
264 E2(i) = exp(-(b[i]*s0[i]));
265 E3(i) = exp(-((1-a[i]-b[i])*s0[i]));
270 template<
class TReferenceImagePixelType,
class TGradientImagePixelType,
class TOdfPixelType,
int NOrderL,
int NrOdfDirections>
271 void DiffusionMultiShellQballReconstructionImageFilter<TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType,NOrderL, NrOdfDirections>
272 ::Projection3( vnl_vector<double> & A, vnl_vector<double> & a, vnl_vector<double> & b,
double delta0)
275 const double s6 = sqrt(6.0);
276 const double s15 = s6/2.0;
278 vnl_vector<double> delta(a.size());
281 vnl_matrix<double> AM(a.size(), 15);
282 vnl_matrix<double> aM(a.size(), 15);
283 vnl_matrix<double> bM(a.size(), 15);
284 vnl_matrix<unsigned char> B(a.size(), 15);
289 AM.set_column(3, delta);
290 AM.set_column(4, (A+a-b - (delta*s6))/3.0);
291 AM.set_column(5, delta);
292 AM.set_column(6, delta);
293 AM.set_column(7, delta);
295 AM.set_column(9, 0.2*(a*2+A-2*(s6+1)*delta));
296 AM.set_column(10,0.2*(b*(-2)+A+2-2*(s6+1)*delta));
297 AM.set_column(11, delta);
298 AM.set_column(12, delta);
299 AM.set_column(13, delta);
300 AM.set_column(14, 0.5-(1+s15)*delta);
305 aM.set_column(2, -delta + 1);
307 aM.set_column(4, (A*2+a*5+b+s6*delta)/6.0);
309 aM.set_column(6, -delta + 1);
310 aM.set_column(7, 0.5*(a+b)+(1+s15)*delta);
311 aM.set_column(8, -delta + 1);
312 aM.set_column(9, 0.2*(a*4+A*2+(s6+1)*delta));
313 aM.set_column(10, -delta + 1);
314 aM.set_column(11, (s6+3)*delta);
315 aM.set_column(12, -delta + 1);
316 aM.set_column(13, -delta + 1);
317 aM.set_column(14, -delta + 1);
320 bM.set_column(1, delta);
323 bM.set_column(4, (A*(-2)+a+b*5-s6*delta)/6.0);
324 bM.set_column(5, delta);
326 bM.set_column(7, 0.5*(a+b)-(1+s15)*delta);
327 bM.set_column(8, delta);
328 bM.set_column(9, delta);
329 bM.set_column(10, 0.2*(b*4-A*2+1-(s6+1)*delta));
330 bM.set_column(11, delta);
331 bM.set_column(12, delta);
332 bM.set_column(13, -delta*(s6+3) + 1);
333 bM.set_column(14, delta);
337 vnl_matrix<double> R2(a.size(), 15);
338 std::vector<unsigned int> I(a.size());
340 for (
unsigned int i=0; i<AM.rows(); i++){
341 for (
unsigned int j=0; j<AM.cols(); j++){
342 if (delta0 < AM(i,j) && 2*(AM(i,j)+delta0*s15)<aM(i,j)-bM(i,j) && bM(i,j)>delta0 && aM(i,j)<1-delta0)
343 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));
347 unsigned int index = 0;
348 double minvalue = 999;
349 for(
int j = 0 ; j < 15 ; j++)
351 if(R2(i,j) < minvalue){
359 for (
unsigned int i=0; i < A.size(); i++){
360 A(i) = AM(i,(
int)I[i]);
361 a(i) = aM(i,(
int)I[i]);
362 b(i) = bM(i,(
int)I[i]);
367 template<
class TReferenceImagePixelType,
class TGradientImagePixelType,
class TOdfPixelType,
int NOrderL,
int NrOdfDirections>
368 void DiffusionMultiShellQballReconstructionImageFilter<TReferenceImagePixelType, TGradientImagePixelType, TOdfPixelType,NOrderL, NrOdfDirections>
369 ::S_S0Normalization( vnl_vector<double> & vec,
double S0 )
371 for(
unsigned int i = 0; i < vec.size(); i++)
380 template<
class T,
class TG,
class TO,
int L,
int NODF>
381 void DiffusionMultiShellQballReconstructionImageFilter<T,TG,TO,L,NODF>
382 ::DoubleLogarithm(vnl_vector<double> & vec)
384 for(
unsigned int i = 0; i < vec.size(); i++)
386 vec[i] = log(-log(vec[i]));
392 template<
class T,
class TG,
class TO,
int L,
int NODF>
396 m_ReconstructionType = Mode_Standard1Shell;
398 if(m_BValueMap.size() == 4 ){
402 const unsigned int bValue_shell1 = it->first;
403 const unsigned int size_shell1 = it->second.size();
406 const unsigned int bValue_shell2 = it->first;
407 const unsigned int size_shell2 = it->second.size();
410 const unsigned int bValue_shell3 = it->first;
411 const unsigned int size_shell3 = it->second.size();
415 if(bValue_shell2 - bValue_shell1 == bValue_shell1 && bValue_shell3 - bValue_shell2 == bValue_shell1 )
419 m_Interpolation_Flag =
false;
420 if(size_shell1 != size_shell2 || size_shell2 != size_shell3 || size_shell1 != size_shell3)
422 m_Interpolation_Flag =
true;
423 MITK_INFO <<
"Shell interpolation: shells with different numbers of directions";
428 m_Interpolation_Flag = CheckForDifferingShellDirections();
429 if(m_Interpolation_Flag)
MITK_INFO <<
"Shell interpolation: gradient direction differ more than one 1 degree";
432 m_ReconstructionType = Mode_Analytical3Shells;
434 if(m_Interpolation_Flag)
436 unsigned int interp_SHOrder_shell1 = 12;
437 while( ((interp_SHOrder_shell1+1)*(interp_SHOrder_shell1+2)/2) > size_shell1 && interp_SHOrder_shell1 > L )
438 interp_SHOrder_shell1 -= 2 ;
440 const int number_coeffs_shell1 = (int)(interp_SHOrder_shell1*interp_SHOrder_shell1 + interp_SHOrder_shell1 + 2.0)/2.0 + interp_SHOrder_shell1;
442 unsigned int interp_SHOrder_shell2 = 12;
443 while( ((interp_SHOrder_shell2+1)*(interp_SHOrder_shell2+2)/2) > size_shell2 && interp_SHOrder_shell2 > L )
444 interp_SHOrder_shell2 -= 2 ;
446 const int number_coeffs_shell2 = (int)(interp_SHOrder_shell2*interp_SHOrder_shell2 + interp_SHOrder_shell2 + 2.0)/2.0 + interp_SHOrder_shell2;
448 unsigned int interp_SHOrder_shell3 = 12;
449 while( ((interp_SHOrder_shell3+1)*(interp_SHOrder_shell3+2)/2) > size_shell3 && interp_SHOrder_shell3 > L )
450 interp_SHOrder_shell3 -= 2 ;
452 const int number_coeffs_shell3 = (int)(interp_SHOrder_shell3*interp_SHOrder_shell3 + interp_SHOrder_shell3 + 2.0)/2.0 + interp_SHOrder_shell3;
456 m_MaxDirections = all_directions_container.size();
460 vnl_matrix<double> * Q =
new vnl_matrix<double>(3, m_MaxDirections);
461 ComputeSphericalFromCartesian(Q, all_directions_container);
463 m_TARGET_SH_shell1 =
new vnl_matrix<double>(m_MaxDirections, number_coeffs_shell1);
464 ComputeSphericalHarmonicsBasis(Q, m_TARGET_SH_shell1, interp_SHOrder_shell1);
467 Q =
new vnl_matrix<double>(3, m_MaxDirections);
468 ComputeSphericalFromCartesian(Q, all_directions_container);
469 m_TARGET_SH_shell2 =
new vnl_matrix<double>(m_MaxDirections, number_coeffs_shell2);
470 ComputeSphericalHarmonicsBasis(Q, m_TARGET_SH_shell2, interp_SHOrder_shell2);
473 Q =
new vnl_matrix<double>(3, m_MaxDirections);
474 ComputeSphericalFromCartesian(Q, all_directions_container);
475 m_TARGET_SH_shell3 =
new vnl_matrix<double>(m_MaxDirections, number_coeffs_shell3);
476 ComputeSphericalHarmonicsBasis(Q, m_TARGET_SH_shell3, interp_SHOrder_shell3);
483 vnl_matrix<double> * tempSHBasis;
484 vnl_matrix_inverse<double> * temp;
487 Q =
new vnl_matrix<double>(3, shell1.size());
488 ComputeSphericalFromCartesian(Q, shell1);
490 tempSHBasis =
new vnl_matrix<double>(shell1.size(), number_coeffs_shell1);
491 ComputeSphericalHarmonicsBasis(Q, tempSHBasis, interp_SHOrder_shell1);
497 temp =
new vnl_matrix_inverse<double>((*tempSHBasis));
498 m_Interpolation_SHT1_inv =
new vnl_matrix<double>(temp->inverse());
505 Q =
new vnl_matrix<double>(3, shell2.size());
506 ComputeSphericalFromCartesian(Q, shell2);
508 tempSHBasis =
new vnl_matrix<double>(shell2.size(), number_coeffs_shell2);
509 ComputeSphericalHarmonicsBasis(Q, tempSHBasis, interp_SHOrder_shell2);
511 temp =
new vnl_matrix_inverse<double>((*tempSHBasis));
513 m_Interpolation_SHT2_inv =
new vnl_matrix<double>(temp->inverse());
520 Q =
new vnl_matrix<double>(3, shell3.size());
521 ComputeSphericalFromCartesian(Q, shell3);
523 tempSHBasis =
new vnl_matrix<double>(shell3.size(), number_coeffs_shell3);
524 ComputeSphericalHarmonicsBasis(Q, tempSHBasis, interp_SHOrder_shell3);
526 temp =
new vnl_matrix_inverse<double>((*tempSHBasis));
528 m_Interpolation_SHT3_inv =
new vnl_matrix<double>(temp->inverse());
534 ComputeReconstructionMatrix(all_directions_container);
536 MITK_INFO <<
"Reconstruction information: Multishell Reconstruction filter - Interpolation";
538 MITK_INFO <<
" SHOrder: " << interp_SHOrder_shell1;
539 MITK_INFO <<
" Number of Coeffs: " << number_coeffs_shell1;
540 MITK_INFO <<
" Number of Gradientdirections: " << size_shell1;
544 MITK_INFO <<
" SHOrder: " << interp_SHOrder_shell2;
545 MITK_INFO <<
" Number of Coeffs: " << number_coeffs_shell2;
546 MITK_INFO <<
" Number of Gradientdirections: " << size_shell2;
550 MITK_INFO <<
" SHOrder: " << interp_SHOrder_shell3;
551 MITK_INFO <<
" Number of Coeffs: " << number_coeffs_shell3;
552 MITK_INFO <<
" Number of Gradientdirections: " << size_shell3;
557 MITK_INFO <<
" Number of Coeffs: " << (L+1)*(L+2)*0.5;
558 MITK_INFO <<
" Number of Gradientdirections: " << m_MaxDirections;
563 ComputeReconstructionMatrix(shell1);
568 if(m_BValueMap.size() > 2 && m_ReconstructionType != Mode_Analytical3Shells)
570 m_ReconstructionType = Mode_NumericalNShells;
572 if(m_BValueMap.size() == 2){
576 ComputeReconstructionMatrix(shell);
582 template<
class T,
class TG,
class TO,
int L,
int NODF>
587 itk::TimeProbe clock;
589 switch(m_ReconstructionType)
591 case Mode_Standard1Shell:
592 StandardOneShellReconstruction(outputRegionForThread);
594 case Mode_Analytical3Shells:
595 AnalyticalThreeShellReconstruction(outputRegionForThread);
597 case Mode_NumericalNShells:
601 MITK_INFO <<
"Reconstruction in : " << clock.GetTotal() <<
" s";
605 template<
class T,
class TG,
class TO,
int L,
int NODF>
610 typename OdfImageType::Pointer outputImage =
static_cast< OdfImageType *
>(ProcessObject::GetPrimaryOutput());
615 ImageRegionIterator< OdfImageType > oit(outputImage, outputRegionForThread);
619 ImageRegionIterator< BZeroImageType > bzeroIterator(m_BZeroImage, outputRegionForThread);
620 bzeroIterator.GoToBegin();
623 typedef ImageRegionConstIterator< GradientImagesType > GradientIteratorType;
624 GradientIteratorType git(gradientImagePointer, outputRegionForThread );
627 BValueMapIteraotr it = m_BValueMap.begin();
629 IndiciesVector SignalIndicies = it->second;
630 IndiciesVector BZeroIndicies = m_BValueMap[0];
632 unsigned int NumbersOfGradientIndicies = SignalIndicies.size();
637 while( ! git.IsAtEnd() )
639 GradientVectorType b = git.Get();
641 OdfPixelType odf(0.0);
643 double b0average = 0;
644 const unsigned int b0size = BZeroIndicies.size();
645 for(
unsigned int i = 0; i < b0size ; ++i)
647 b0average += b[BZeroIndicies[i]];
650 bzeroIterator.Set(b0average);
654 vnl_vector<double> SignalVector(NumbersOfGradientIndicies);
655 if( (b0average != 0) && (b0average >= m_Threshold) )
658 for(
unsigned int i = 0; i< SignalIndicies.size(); i++ )
660 SignalVector[i] =
static_cast<double>(b[SignalIndicies[i]]);
665 S_S0Normalization(SignalVector, b0average);
666 Projection1(SignalVector);
668 DoubleLogarithm(SignalVector);
671 vnl_vector<double> coeffs = ( (*m_CoeffReconstructionMatrix) * SignalVector );
672 coeffs[0] = 1.0/(2.0*sqrt(
M_PI));
674 odf = element_cast<double, TO>(( (*m_ODFSphericalHarmonicBasisMatrix) * coeffs )).data_block();
675 odf *= (
M_PI*4/NODF);
684 MITK_INFO <<
"One Thread finished reconstruction";
689 template<
class T,
class TG,
class TO,
int L,
int NODF>
690 void DiffusionMultiShellQballReconstructionImageFilter<T,TG,TO,L,NODF>
691 ::NumericalNShellReconstruction(
const OutputImageRegionType& outputRegionForThread)
714 template<
class T,
class TG,
class TO,
int L,
int NODF>
715 void DiffusionMultiShellQballReconstructionImageFilter<T,TG,TO,L,NODF>
716 ::AnalyticalThreeShellReconstruction(
const OutputImageRegionType& outputRegionForThread)
720 typename OdfImageType::Pointer outputImage =
static_cast< OdfImageType *
>(ProcessObject::GetPrimaryOutput());
724 ImageRegionIterator< OdfImageType > odfOutputImageIterator(outputImage, outputRegionForThread);
725 ImageRegionConstIterator< GradientImagesType > gradientInputImageIterator(gradientImagePointer, outputRegionForThread );
726 ImageRegionIterator< BZeroImageType > bzeroIterator(m_BZeroImage, outputRegionForThread);
727 ImageRegionIterator< CoefficientImageType > coefficientImageIterator(m_CoefficientImage, outputRegionForThread);
730 coefficientImageIterator.GoToBegin();
731 bzeroIterator.GoToBegin();
732 odfOutputImageIterator.GoToBegin();
733 gradientInputImageIterator.GoToBegin();
737 BValueMapIteraotr it = m_BValueMap.begin();
740 IndiciesVector Shell1Indiecies = it->second;
743 IndiciesVector Shell2Indiecies = it->second;
746 IndiciesVector Shell3Indiecies = it->second;
747 IndiciesVector BZeroIndicies = m_BValueMap[0];
749 if(!m_Interpolation_Flag)
751 m_MaxDirections = Shell1Indiecies.size();
755 vnl_vector< double > E1(m_MaxDirections);
756 vnl_vector< double > E2(m_MaxDirections);
757 vnl_vector< double > E3(m_MaxDirections);
759 vnl_vector<double> AlphaValues(m_MaxDirections);
760 vnl_vector<double> BetaValues(m_MaxDirections);
761 vnl_vector<double> LAValues(m_MaxDirections);
762 vnl_vector<double> PValues(m_MaxDirections);
764 vnl_vector<double> DataShell1(Shell1Indiecies.size());
765 vnl_vector<double> DataShell2(Shell2Indiecies.size());
766 vnl_vector<double> DataShell3(Shell3Indiecies.size());
768 vnl_matrix<double> tempInterpolationMatrixShell1,tempInterpolationMatrixShell2,tempInterpolationMatrixShell3;
770 if(m_Interpolation_Flag)
772 tempInterpolationMatrixShell1 = (*m_TARGET_SH_shell1) * (*m_Interpolation_SHT1_inv);
773 tempInterpolationMatrixShell2 = (*m_TARGET_SH_shell2) * (*m_Interpolation_SHT2_inv);
774 tempInterpolationMatrixShell3 = (*m_TARGET_SH_shell3) * (*m_Interpolation_SHT3_inv);
777 OdfPixelType odf(0.0);
780 double P2,A,B2,B,P,alpha,beta,lambda, ER1, ER2;
785 while( ! gradientInputImageIterator.IsAtEnd() )
791 GradientVectorType b = gradientInputImageIterator.Get();
794 double shell1b0Norm =0;
795 double shell2b0Norm =0;
796 double shell3b0Norm =0;
797 double b0average = 0;
798 const unsigned int b0size = BZeroIndicies.size();
802 shell1b0Norm = b[BZeroIndicies[0]];
803 shell2b0Norm = b[BZeroIndicies[0]];
804 shell3b0Norm = b[BZeroIndicies[0]];
805 b0average = b[BZeroIndicies[0]];
806 }
else if(b0size % 3 ==0)
808 for(
unsigned int i = 0; i < b0size ; ++i)
810 if(i < b0size / 3) shell1b0Norm += b[BZeroIndicies[i]];
811 if(i >= b0size / 3 && i < (b0size / 3)*2) shell2b0Norm += b[BZeroIndicies[i]];
812 if(i >= (b0size / 3) * 2) shell3b0Norm += b[BZeroIndicies[i]];
814 shell1b0Norm /= (b0size/3);
815 shell2b0Norm /= (b0size/3);
816 shell3b0Norm /= (b0size/3);
817 b0average = (shell1b0Norm + shell2b0Norm+ shell3b0Norm)/3;
820 for(
unsigned int i = 0; i <b0size ; ++i)
822 shell1b0Norm += b[BZeroIndicies[i]];
824 shell1b0Norm /= b0size;
825 shell2b0Norm = shell1b0Norm;
826 shell3b0Norm = shell1b0Norm;
827 b0average = shell1b0Norm;
830 bzeroIterator.Set(b0average);
833 if( (b0average != 0) && ( b0average >= m_Threshold) )
852 for(
unsigned int i = 0 ; i < Shell1Indiecies.size(); i++)
853 DataShell1[i] = static_cast<double>(b[Shell1Indiecies[i]]);
854 for(
unsigned int i = 0 ; i < Shell2Indiecies.size(); i++)
855 DataShell2[i] = static_cast<double>(b[Shell2Indiecies[i]]);
856 for(
unsigned int i = 0 ; i < Shell3Indiecies.size(); i++)
857 DataShell3[i] = static_cast<double>(b[Shell3Indiecies[i]]);
862 S_S0Normalization(DataShell1, shell1b0Norm);
863 S_S0Normalization(DataShell2, shell2b0Norm);
864 S_S0Normalization(DataShell3, shell3b0Norm);
867 if(m_Interpolation_Flag)
869 E1 = tempInterpolationMatrixShell1 * DataShell1;
870 E2 = tempInterpolationMatrixShell2 * DataShell2;
871 E3 = tempInterpolationMatrixShell3 * DataShell3;
884 Projection2(E1,E2,E3);
886 for(
unsigned int i = 0; i< m_MaxDirections; i++ )
888 double e1 = E1.get(i);
889 double e2 = E2.get(i);
890 double e3 = E3.get(i);
893 A = (e3 -e1*e2) / ( 2* P2);
894 B2 = A * A -(e1 * e3 - e2 * e2) /P2;
896 if(B2 > 0) B = sqrt(B2);
898 if(P2 > 0) P = sqrt(P2);
904 AlphaValues.put(i, alpha);
905 BetaValues.put(i, beta);
909 Projection3(PValues, AlphaValues, BetaValues);
911 for(
unsigned int i = 0 ; i < m_MaxDirections; i++)
913 const double fac = (PValues[i] * 2 ) / (AlphaValues[i] - BetaValues[i]);
914 lambda = 0.5 + 0.5 * std::sqrt(1 - fac * fac);;
915 ER1 = std::fabs(lambda * (AlphaValues[i] - BetaValues[i]) + (BetaValues[i] - E1.get(i) ))
916 + std::fabs(lambda * (AlphaValues[i] * AlphaValues[i] - BetaValues[i] * BetaValues[i]) + (BetaValues[i] * BetaValues[i] - E2.get(i) ))
917 + std::fabs(lambda * (AlphaValues[i] * AlphaValues[i] * AlphaValues[i] - BetaValues[i] * BetaValues[i] * BetaValues[i]) + (BetaValues[i] * BetaValues[i] * BetaValues[i] - E3.get(i) ));
918 ER2 = std::fabs((1-lambda) * (AlphaValues[i] - BetaValues[i]) + (BetaValues[i] - E1.get(i) ))
919 + std::fabs((1-lambda) * (AlphaValues[i] * AlphaValues[i] - BetaValues[i] * BetaValues[i]) + (BetaValues[i] * BetaValues[i] - E2.get(i) ))
920 + 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)));
922 LAValues.put(i, lambda);
924 LAValues.put(i, 1-lambda);
928 DoubleLogarithm(AlphaValues);
929 DoubleLogarithm(BetaValues);
931 vnl_vector<double> SignalVector(element_product((LAValues) , (AlphaValues)-(BetaValues)) + (BetaValues));
933 vnl_vector<double> coeffs((*m_CoeffReconstructionMatrix) *SignalVector );
936 coeffs[0] = 1.0/(2.0*sqrt(
M_PI));
937 coeffPixel = element_cast<double, TO>(coeffs).data_block();
940 odf = element_cast<double, TO>( (*m_ODFSphericalHarmonicBasisMatrix) * coeffs ).data_block();
941 odf *= ((
M_PI*4)/NODF);
945 coefficientImageIterator.Set(coeffPixel);
946 odfOutputImageIterator.Set( odf );
947 ++odfOutputImageIterator;
948 ++coefficientImageIterator;
949 ++gradientInputImageIterator;
956 template<
class T,
class TG,
class TO,
int L,
int NODF>
957 void DiffusionMultiShellQballReconstructionImageFilter<T, TG, TO, L, NODF>::
958 ComputeSphericalHarmonicsBasis(vnl_matrix<double> * QBallReference, vnl_matrix<double> *SHBasisOutput,
int LOrder , vnl_matrix<double>* LaplaciaBaltramiOutput, vnl_vector<int>* SHOrderAssociation, vnl_matrix<double>* SHEigenvalues)
963 for(
unsigned int i=0; i< (*SHBasisOutput).rows(); i++)
965 for(
int k = 0; k <= LOrder; k += 2)
967 for(
int m =- k; m <= k; m++)
969 int j = ( k * k + k + 2 ) / 2 + m - 1;
973 double phi = (*QBallReference)(0,i);
974 double th = (*QBallReference)(1,i);
979 if(LaplaciaBaltramiOutput)
980 (*LaplaciaBaltramiOutput)(j,j) = k*k*(k + 1)*(k+1);
984 (*SHEigenvalues)(j,j) = -k* (k+1);
987 if(SHOrderAssociation)
988 (*SHOrderAssociation)[j] = k;
995 template<
class T,
class TG,
class TO,
int L,
int NOdfDirections>
996 void DiffusionMultiShellQballReconstructionImageFilter<T,TG,TO,L,NOdfDirections>
997 ::ComputeReconstructionMatrix(IndiciesVector
const & refVector)
1000 typedef std::unique_ptr< vnl_matrix< double> > MatrixDoublePtr;
1001 typedef std::unique_ptr< vnl_vector< int > > VectorIntPtr;
1002 typedef std::unique_ptr< vnl_matrix_inverse< double > > InverseMatrixDoublePtr;
1004 int numberOfGradientDirections = refVector.size();
1006 if( numberOfGradientDirections <= (((L+1)*(L+2))/2) || numberOfGradientDirections < 6 )
1008 itkExceptionMacro( <<
"At least (L+1)(L+2)/2 gradient directions for each shell are required; current : " << numberOfGradientDirections );
1011 CheckDuplicateDiffusionGradients();
1013 const int LOrder = L;
1014 int NumberOfCoeffs = (int)(LOrder*LOrder + LOrder + 2.0)/2.0 + LOrder;
1015 MatrixDoublePtr SHBasisMatrix(
new vnl_matrix<double>(numberOfGradientDirections,NumberOfCoeffs));
1016 SHBasisMatrix->fill(0.0);
1017 VectorIntPtr SHOrderAssociation(
new vnl_vector<int>(NumberOfCoeffs));
1018 SHOrderAssociation->fill(0.0);
1019 MatrixDoublePtr LaplacianBaltrami(
new vnl_matrix<double>(NumberOfCoeffs,NumberOfCoeffs));
1020 LaplacianBaltrami->fill(0.0);
1021 MatrixDoublePtr FRTMatrix(
new vnl_matrix<double>(NumberOfCoeffs,NumberOfCoeffs));
1022 FRTMatrix->fill(0.0);
1023 MatrixDoublePtr SHEigenvalues(
new vnl_matrix<double>(NumberOfCoeffs,NumberOfCoeffs));
1024 SHEigenvalues->fill(0.0);
1026 MatrixDoublePtr Q(
new vnl_matrix<double>(3, numberOfGradientDirections));
1029 ComputeSphericalFromCartesian(Q.get(), refVector);
1032 ComputeSphericalHarmonicsBasis(Q.get() ,SHBasisMatrix.get() , LOrder , LaplacianBaltrami.get(), SHOrderAssociation.get(), SHEigenvalues.get());
1035 for(
int i=0; i<NumberOfCoeffs; i++)
1040 MatrixDoublePtr temp(
new vnl_matrix<double>(((SHBasisMatrix->transpose()) * (*SHBasisMatrix)) + (m_Lambda * (*LaplacianBaltrami))));
1042 InverseMatrixDoublePtr pseudo_inv(
new vnl_matrix_inverse<double>((*temp)));
1043 MatrixDoublePtr inverse(
new vnl_matrix<double>(NumberOfCoeffs,NumberOfCoeffs));
1044 (*inverse) = pseudo_inv->inverse();
1046 const double factor = (1.0/(16.0*
M_PI*
M_PI));
1047 MatrixDoublePtr SignalReonstructionMatrix (
new vnl_matrix<double>((*inverse) * (SHBasisMatrix->transpose())));
1048 m_CoeffReconstructionMatrix =
new vnl_matrix<double>(( factor * ((*FRTMatrix) * ((*SHEigenvalues) * (*SignalReonstructionMatrix))) ));
1052 vnl_matrix_fixed<double, 3, NOdfDirections>* U = PointShell<NOdfDirections, vnl_matrix_fixed<double, 3, NOdfDirections> >::DistributePointShell();
1053 for(
int i=0; i<NOdfDirections; i++)
1055 double x = (*U)(0,i);
1056 double y = (*U)(1,i);
1057 double z = (*U)(2,i);
1060 (*U)(0,i) = cart[0];
1061 (*U)(1,i) = cart[1];
1062 (*U)(2,i) = cart[2];
1065 MatrixDoublePtr tempPtr (
new vnl_matrix<double>( U->as_matrix() ));
1066 m_ODFSphericalHarmonicBasisMatrix =
new vnl_matrix<double>(NOdfDirections,NumberOfCoeffs);
1067 ComputeSphericalHarmonicsBasis(tempPtr.get(), m_ODFSphericalHarmonicBasisMatrix, LOrder);
1070 template<
class T,
class TG,
class TO,
int L,
int NOdfDirections>
1071 void DiffusionMultiShellQballReconstructionImageFilter<T,TG,TO,L,NOdfDirections>
1072 ::ComputeSphericalFromCartesian(vnl_matrix<double> * Q, IndiciesVector
const & refShell)
1074 for(
unsigned int i = 0; i < refShell.size(); i++)
1076 double x = m_GradientDirectionContainer->ElementAt(refShell[i]).normalize().get(0);
1077 double y = m_GradientDirectionContainer->ElementAt(refShell[i]).normalize().get(1);
1078 double z = m_GradientDirectionContainer->ElementAt(refShell[i]).normalize().get(2);
1081 (*Q)(0,i) = cart[0];
1082 (*Q)(1,i) = cart[1];
1083 (*Q)(2,i) = cart[2];
1088 template<
class T,
class TG,
class TO,
int L,
int NODF>
1089 bool DiffusionMultiShellQballReconstructionImageFilter<T,TG,TO,L,NODF>
1090 ::CheckDuplicateDiffusionGradients()
1094 BValueMapIteraotr mapIterator = m_BValueMap.begin();
1096 while(mapIterator != m_BValueMap.end())
1098 std::vector<unsigned int>::const_iterator it1 = mapIterator->second.begin();
1099 std::vector<unsigned int>::const_iterator it2 = mapIterator->second.begin();
1101 for(; it1 != mapIterator->second.end(); ++it1)
1103 for(; it2 != mapIterator->second.end(); ++it2)
1105 if(m_GradientDirectionContainer->ElementAt(*it1) == m_GradientDirectionContainer->ElementAt(*it2) && it1 != it2)
1107 itkWarningMacro( <<
"Some of the Diffusion Gradients equal each other. Corresponding image data should be averaged before calling this filter." );
1117 template<
class T,
class TG,
class TO,
int L,
int NODF>
1118 std::vector<unsigned int> DiffusionMultiShellQballReconstructionImageFilter<T,TG,TO,L,NODF>
1119 ::GetAllDirections()
1121 IndiciesVector directioncontainer;
1123 BValueMapIteraotr mapIterator = m_BValueMap.begin();
1125 IndiciesVector shell1 = mapIterator->second;
1127 IndiciesVector shell2 = mapIterator->second;
1129 IndiciesVector shell3 = mapIterator->second;
1131 while(shell1.size()>0)
1133 unsigned int wntIndex = shell1.back();
1136 IndiciesVector::iterator containerIt = directioncontainer.begin();
1137 bool directionExist =
false;
1138 while(containerIt != directioncontainer.end())
1140 if (fabs(dot(m_GradientDirectionContainer->ElementAt(*containerIt), m_GradientDirectionContainer->ElementAt(wntIndex))) > 0.9998)
1142 directionExist =
true;
1149 directioncontainer.push_back(wntIndex);
1153 while(shell2.size()>0)
1155 unsigned int wntIndex = shell2.back();
1158 IndiciesVector::iterator containerIt = directioncontainer.begin();
1159 bool directionExist =
false;
1160 while(containerIt != directioncontainer.end())
1162 if (fabs(dot(m_GradientDirectionContainer->ElementAt(*containerIt), m_GradientDirectionContainer->ElementAt(wntIndex))) > 0.9998)
1164 directionExist =
true;
1171 directioncontainer.push_back(wntIndex);
1175 while(shell3.size()>0)
1177 unsigned int wntIndex = shell3.back();
1180 IndiciesVector::iterator containerIt = directioncontainer.begin();
1181 bool directionExist =
false;
1182 while(containerIt != directioncontainer.end())
1184 if (fabs(dot(m_GradientDirectionContainer->ElementAt(*containerIt), m_GradientDirectionContainer->ElementAt(wntIndex))) > 0.9998)
1186 directionExist =
true;
1193 directioncontainer.push_back(wntIndex);
1197 return directioncontainer;
1201 template<
class T,
class TG,
class TO,
int L,
int NODF>
1202 bool DiffusionMultiShellQballReconstructionImageFilter<T,TG,TO,L,NODF>
1203 ::CheckForDifferingShellDirections()
1205 bool interp_flag =
false;
1207 BValueMapIteraotr mapIterator = m_BValueMap.begin();
1209 IndiciesVector shell1 = mapIterator->second;
1211 IndiciesVector shell2 = mapIterator->second;
1213 IndiciesVector shell3 = mapIterator->second;
1215 for (
unsigned int i=0; i< shell1.size(); i++)
1216 if (fabs(dot(m_GradientDirectionContainer->ElementAt(shell1[i]), m_GradientDirectionContainer->ElementAt(shell2[i]))) <= 0.9998) {interp_flag=
true;
break;}
1217 for (
unsigned int i=0; i< shell1.size(); i++)
1218 if (fabs(dot(m_GradientDirectionContainer->ElementAt(shell1[i]), m_GradientDirectionContainer->ElementAt(shell3[i]))) <= 0.9998) {interp_flag=
true;
break;}
1219 for (
unsigned int i=0; i< shell1.size(); i++)
1220 if (fabs(dot(m_GradientDirectionContainer->ElementAt(shell2[i]), m_GradientDirectionContainer->ElementAt(shell3[i]))) <= 0.9998) {interp_flag=
true;
break;}
1225 template<
class T,
class TG,
class TO,
int L,
int NODF>
1230 std::locale originalLocale = os.getloc();
1233 Superclass::PrintSelf(os,indent);
1236 if ( m_GradientDirectionContainer )
1238 os << indent <<
"GradientDirectionContainer: "
1239 << m_GradientDirectionContainer << std::endl;
1244 "GradientDirectionContainer: (Gradient directions not set)" << std::endl;
1246 os << indent <<
"NumberOfGradientDirections: " <<
1247 m_NumberOfGradientDirections << std::endl;
1248 os << indent <<
"NumberOfBaselineImages: " <<
1249 m_NumberOfBaselineImages << std::endl;
1250 os << indent <<
"Threshold for reference B0 image: " << m_Threshold << std::endl;
1251 os << indent <<
"BValue: " << m_BValue << std::endl;
1253 os.imbue( originalLocale );
1261 #endif // __itkDiffusionMultiShellQballReconstructionImageFilter_cpp
itk::SmartPointer< Self > Pointer
static double legendre0(int l)
static double Yj(int m, int k, double theta, double phi)
void BeforeThreadedGenerateData()
static void Cart2Sph(double x, double y, double z, double *cart)
void PrintSelf(std::ostream &os, Indent indent) const
std::vector< unsigned int > IndiciesVector
VectorImage< GradientPixelType, 3 > GradientImagesType
void SetGradientImage(const GradientDirectionContainerType *gradientDirectionContainer, const GradientImagesType *gradientImage, float bvalue)
VectorContainer< unsigned int, vnl_vector_fixed< double, 3 > > GradientDirectionContainerType
Superclass::OutputImageRegionType OutputImageRegionType
void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType NumberOfThreads)
std::map< unsigned int, std::vector< unsigned int > >::iterator BValueMapIteraotr
DiffusionMultiShellQballReconstructionImageFilter()
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.