ANIMA  4.0
animaDTIProbabilisticTractographyImageFilter.cxx
Go to the documentation of this file.
2 #include <cmath>
3 
6 #include <animaVMFDistribution.h>
9 #include <animaBaseTensorTools.h>
10 
11 #include <itkSymmetricEigenAnalysis.h>
12 
13 #include <vtkPointData.h>
14 #include <vtkDoubleArray.h>
15 
16 namespace anima
17 {
18 
21 {
22  m_ThresholdForProlateTensor = 0.25;
23  m_FAThreshold = 0.2;
24 
25  this->SetModelDimension(6);
26 }
27 
29 {
30 }
31 
34  Vector3DType &sampling_direction, double &log_prior,
35  double &log_proposal, std::mt19937 &random_generator,
36  unsigned int threadId)
37 {
38  Vector3DType resVec(0.0);
39 
40  double concentrationParameter;
41  bool is2d = this->GetInputModelImage()->GetLargestPossibleRegion().GetSize()[2] <= 1;
42  double LC = this->GetLinearCoefficient(modelValue);
43 
44  if (LC > m_ThresholdForProlateTensor)
45  {
46 
47  this->GetDTIPrincipalDirection(modelValue, sampling_direction, is2d);
48 
49  if (anima::ComputeScalarProduct(oldDirection, sampling_direction) < 0)
50  sampling_direction *= -1;
51 
52  double FA = this->GetFractionalAnisotropy(modelValue);
53 
54  concentrationParameter = this->GetKappaFromFA(FA);
55  }
56  else
57  {
58  sampling_direction = oldDirection;
59  concentrationParameter = this->GetKappaOfPriorDistribution();
60  }
61 
62 // if (concentrationParameter > 700)
63 // anima::SampleFromVMFDistributionNumericallyStable(concentrationParameter,sampling_direction,resVec,random_generator);
64 // else
65 // anima::SampleFromVMFDistribution(concentrationParameter,sampling_direction,resVec,random_generator);
66 
67  anima::SampleFromWatsonDistribution(concentrationParameter,sampling_direction,resVec,3,random_generator);
68 
69  if (is2d)
70  {
71  resVec[InputModelImageType::ImageDimension - 1] = 0;
72  resVec.Normalize();
73  }
74 
75  if (LC > m_ThresholdForProlateTensor)
76  {
77 // log_prior = anima::safe_log(anima::ComputeVMFPdf(resVec, oldDirection, this->GetKappaOfPriorDistribution()));
78  log_prior = anima::safe_log(anima::EvaluateWatsonPDF(resVec, oldDirection, this->GetKappaOfPriorDistribution()));
79 
80 // log_proposal = anima::safe_log(anima::ComputeVMFPdf(resVec, sampling_direction, concentrationParameter));
81  log_proposal = anima::safe_log(anima::EvaluateWatsonPDF(resVec, sampling_direction, concentrationParameter));
82  }
83 
84  if (anima::ComputeScalarProduct(oldDirection, resVec) < 0)
85  resVec *= -1;
86 
87  return resVec;
88 }
89 
92 InitializeFirstIterationFromModel(Vector3DType &colinearDir, VectorType &modelValue, unsigned int threadId)
93 {
94  Vector3DType resVec, tmpVec;
95  bool is2d = (this->GetInputModelImage()->GetLargestPossibleRegion().GetSize()[2] == 1);
96 
97  itk::SymmetricEigenAnalysis <Matrix3DType,Vector3DType,Matrix3DType> EigenAnalysis(InputModelImageType::ImageDimension);
98  EigenAnalysis.SetOrderEigenValues(true);
99 
100  Matrix3DType dtiTensor, eigVecs;
101  Vector3DType eigVals;
102 
103  unsigned int pos = 0;
104  for (unsigned int i = 0;i < 3;++i)
105  for (unsigned int j = 0;j <= i;++j)
106  {
107  dtiTensor(i,j) = modelValue[pos];
108  if (j != i)
109  dtiTensor(j,i) = dtiTensor(i,j);
110  ++pos;
111  }
112 
113  EigenAnalysis.ComputeEigenValuesAndVectors(dtiTensor,eigVals,eigVecs);
114 
115  switch(this->GetInitialDirectionMode())
116  {
117  case Colinear:
118  {
119  double maxVal = 0;
120  for (unsigned int i = 0;i < 3;++i)
121  {
122  for (unsigned int j = 0;j < 3;++j)
123  tmpVec[j] = eigVecs(i,j);
124 
125  double tmpVal = anima::ComputeScalarProduct(colinearDir,tmpVec);
126 
127  if (tmpVal < 0)
128  {
129  tmpVec *= -1;
130  tmpVal *= -1;
131  }
132 
133  if (maxVal < tmpVal)
134  {
135  maxVal = tmpVal;
136  resVec = tmpVec;
137  }
138  }
139  break;
140  }
141 
142  case Weight:
143  default:
144  {
145  for (unsigned int i = 0;i < 3;++i)
146  resVec[i] = eigVecs(2,i);
147 
148  if (anima::ComputeScalarProduct(colinearDir, resVec) < 0)
149  resVec *= -1;
150 
151  break;
152  }
153  }
154 
155  if (is2d)
156  {
157  resVec[2] = 0;
158  resVec.Normalize();
159  }
160 
161  return resVec;
162 }
163 
164 bool DTIProbabilisticTractographyImageFilter::CheckModelProperties(double estimatedB0Value, double estimatedNoiseValue, VectorType &modelValue, unsigned int threadId)
165 {
166  if (estimatedB0Value < 50.0)
167  return false;
168 
169  bool isTensorNull = true;
170  for (unsigned int j = 0;j < this->GetModelDimension();++j)
171  {
172  if (modelValue[j] != 0)
173  {
174  isTensorNull = false;
175  break;
176  }
177  }
178 
179  if (isTensorNull)
180  return false;
181 
182  double fractionalAnisotropy = this->GetFractionalAnisotropy(modelValue);
183  if (fractionalAnisotropy < m_FAThreshold)
184  return false;
185 
186  return true;
187 }
188 
189 double DTIProbabilisticTractographyImageFilter::ComputeLogWeightUpdate(double b0Value, double noiseValue, Vector3DType &newDirection, VectorType &modelValue, double &log_prior,
190  double &log_proposal, unsigned int threadId)
191 {
192  bool is2d = this->GetInputModelImage()->GetLargestPossibleRegion().GetSize()[2] <= 1;
193 
194  // Computes prior, proposal and log-likelihood values
195  double logLikelihood = 0;
196  double LC = this->GetLinearCoefficient(modelValue);
197 
198  double concentrationParameter = 50.0;
199  if (noiseValue > 0)
200  concentrationParameter = b0Value / std::sqrt(noiseValue);
201 
202  if (LC > m_ThresholdForProlateTensor)
203  {
204  Vector3DType dtiPrincipalDirection(0.0);
205 
206  this->GetDTIPrincipalDirection(modelValue, dtiPrincipalDirection, is2d);
207  logLikelihood = std::log(anima::EvaluateWatsonPDF(dtiPrincipalDirection, newDirection, concentrationParameter));
208  }
209  else
210  {
211  Vector3DType dtiMinorDirection(0.0);
212 
213  this->GetDTIMinorDirection(modelValue, dtiMinorDirection);
214  logLikelihood = std::log(anima::EvaluateWatsonPDF(dtiMinorDirection, newDirection, - concentrationParameter));
215  }
216 
217  double resVal = log_prior + logLikelihood - log_proposal;
218  return resVal;
219 }
220 
222 {
223  m_KappaPolynomialCoefficients.resize(coefs.size());
224  for (unsigned int i = 0;i < coefs.size();++i)
225  m_KappaPolynomialCoefficients[i] = coefs[i];
226 }
227 
229 {
230  double resVal = 0.0;
231  for (unsigned int i = 0;i < m_KappaPolynomialCoefficients.size();++i)
232  resVal += m_KappaPolynomialCoefficients[i] * std::pow(FA, (double)i);
233 
234  return 0.5 * resVal;
235 }
236 
238 {
239  itk::SymmetricEigenAnalysis <Matrix3DType,Vector3DType,Matrix3DType> EigenAnalysis(InputModelImageType::ImageDimension);
240  EigenAnalysis.SetOrderEigenValues(true);
241 
242  Matrix3DType dtiTensor, eigVecs;
243  Vector3DType eigVals;
244 
245  unsigned int pos = 0;
246  for (unsigned int i = 0;i < 3;++i)
247  for (unsigned int j = 0;j <= i;++j)
248  {
249  dtiTensor(i,j) = modelValue[pos];
250  if (j != i)
251  dtiTensor(j,i) = dtiTensor(i,j);
252  ++pos;
253  }
254 
255  EigenAnalysis.ComputeEigenValuesAndVectors(dtiTensor,eigVals,eigVecs);
256 
257  for (unsigned int i = 0;i < 3;++i)
258  resVec[i] = eigVecs(2,i);
259 
260  if (is2d)
261  {
262  resVec[2] = 0;
263  resVec.Normalize();
264  }
265 }
266 
268 {
269  itk::SymmetricEigenAnalysis <Matrix3DType,Vector3DType,Matrix3DType> EigenAnalysis(InputModelImageType::ImageDimension);
270  EigenAnalysis.SetOrderEigenValues(true);
271 
272  Matrix3DType dtiTensor, eigVecs;
273  Vector3DType eigVals;
274 
275  unsigned int pos = 0;
276  for (unsigned int i = 0;i < 3;++i)
277  for (unsigned int j = 0;j <= i;++j)
278  {
279  dtiTensor(i,j) = modelValue[pos];
280  if (j != i)
281  dtiTensor(j,i) = dtiTensor(i,j);
282  ++pos;
283  }
284 
285  EigenAnalysis.ComputeEigenValuesAndVectors(dtiTensor,eigVals,eigVecs);
286 
287  for (unsigned int i = 0;i < 3;++i)
288  resVec[i] = eigVecs(0,i);
289 }
290 
292  VectorType &modelValue)
293 {
294  modelValue.SetSize(this->GetModelDimension());
295  modelValue.Fill(0.0);
296 
297  if (modelInterpolator->IsInsideBuffer(index))
298  modelValue = modelInterpolator->EvaluateAtContinuousIndex(index);
299 
300  using LECalculatorType = anima::LogEuclideanTensorCalculator <double>;
301  using LECalculatorPointer = LECalculatorType::Pointer;
302 
303  LECalculatorPointer leCalculator = LECalculatorType::New();
304 
305  vnl_matrix <double> tmpTensor(3,3);
306  anima::GetTensorFromVectorRepresentation(modelValue,tmpTensor);
307  leCalculator->GetTensorExponential(tmpTensor,tmpTensor);
308  anima::GetVectorRepresentation(tmpTensor,modelValue);
309 }
310 
312 {
313  itk::SymmetricEigenAnalysis <Matrix3DType,Vector3DType,Matrix3DType> EigenAnalysis(InputModelImageType::ImageDimension);
314  EigenAnalysis.SetOrderEigenValues(true);
315 
316  Matrix3DType dtiTensor;
317  Vector3DType eigVals;
318 
319  unsigned int pos = 0;
320  for (unsigned int i = 0;i < 3;++i)
321  for (unsigned int j = 0;j <= i;++j)
322  {
323  dtiTensor(i,j) = modelValue[pos];
324  if (j != i)
325  dtiTensor(j,i) = dtiTensor(i,j);
326  ++pos;
327  }
328 
329  EigenAnalysis.ComputeEigenValues(dtiTensor,eigVals);
330 
331  double denom = 0;
332  for (unsigned int i = 0;i < 3;++i)
333  denom += eigVals[i] * eigVals[i];
334 
335  return (eigVals[2] - eigVals[1]) / sqrt(denom);
336 }
337 
339 {
340  itk::SymmetricEigenAnalysis <Matrix3DType,Vector3DType,Matrix3DType> EigenAnalysis(InputModelImageType::ImageDimension);
341  EigenAnalysis.SetOrderEigenValues(true);
342 
343  Matrix3DType dtiTensor;
344  Vector3DType eigVals;
345 
346  unsigned int pos = 0;
347  for (unsigned int i = 0;i < 3;++i)
348  for (unsigned int j = 0;j <= i;++j)
349  {
350  dtiTensor(i,j) = modelValue[pos];
351  if (j != i)
352  dtiTensor(j,i) = dtiTensor(i,j);
353  ++pos;
354  }
355 
356  EigenAnalysis.ComputeEigenValues(dtiTensor,eigVals);
357 
358  double meanLambda = 0;
359  for (unsigned int i = 0;i < 3;++i)
360  meanLambda += eigVals[i];
361 
362  meanLambda /= 3.0;
363 
364  double num = 0;
365  double denom = 0;
366  for (unsigned int i = 0;i < 3;++i)
367  {
368  num += (eigVals[i] - meanLambda) * (eigVals[i] - meanLambda);
369  denom += eigVals[i] * eigVals[i];
370  }
371 
372  // FA
373  return std::sqrt(3.0 * num / (2.0 * denom));
374 }
375 
376 void DTIProbabilisticTractographyImageFilter::GetEigenValueCombinations(VectorType &modelValue, double &meanLambda, double &perpLambda)
377 {
378  itk::SymmetricEigenAnalysis <Matrix3DType,Vector3DType,Matrix3DType> EigenAnalysis(InputModelImageType::ImageDimension);
379  EigenAnalysis.SetOrderEigenValues(true);
380 
381  Matrix3DType dtiTensor;
382  Vector3DType eigVals;
383 
384  unsigned int pos = 0;
385  for (unsigned int i = 0;i < 3;++i)
386  for (unsigned int j = 0;j <= i;++j)
387  {
388  dtiTensor(i,j) = modelValue[pos];
389  if (j != i)
390  dtiTensor(j,i) = dtiTensor(i,j);
391  ++pos;
392  }
393 
394  EigenAnalysis.ComputeEigenValues(dtiTensor,eigVals);
395 
396  meanLambda = 0;
397  perpLambda = 0;
398  for (unsigned int i = 0;i < 3;++i)
399  {
400  meanLambda += eigVals[i];
401  if (i == 1)
402  perpLambda = meanLambda / 2.0;
403  }
404 
405  meanLambda /= 3.0;
406 }
407 
409 {
410  vtkSmartPointer <vtkPolyData> outputPtr = this->GetOutput();
411 
412  InterpolatorPointer modelInterpolator = this->GetModelInterpolator();
413 
414  unsigned int numPoints = outputPtr->GetPoints()->GetNumberOfPoints();
415  vtkPoints *myPoints = outputPtr->GetPoints();
416 
417  vtkSmartPointer <vtkDoubleArray> faArray = vtkDoubleArray::New();
418  faArray->SetNumberOfComponents(1);
419  faArray->SetName("FA");
420 
421  vtkSmartPointer <vtkDoubleArray> adcArray = vtkDoubleArray::New();
422  adcArray->SetNumberOfComponents(1);
423  adcArray->SetName("ADC");
424 
425  PointType tmpPoint;
427 
428  typedef vnl_matrix <double> MatrixType;
429  MatrixType tmpMat(3,3);
430  vnl_diag_matrix <double> eVals(3);
431  itk::SymmetricEigenAnalysis <MatrixType,vnl_diag_matrix <double>,MatrixType> EigenAnalysis(3);
432  VectorType tensorValue(6);
433 
434  for (unsigned int i = 0;i < numPoints;++i)
435  {
436  for (unsigned int j = 0;j < 3;++j)
437  tmpPoint[j] = myPoints->GetPoint(i)[j];
438 
439  this->GetInputModelImage()->TransformPhysicalPointToContinuousIndex(tmpPoint,tmpIndex);
440  tensorValue.Fill(0.0);
441  if (modelInterpolator->IsInsideBuffer(tmpIndex))
442  this->ComputeModelValue(modelInterpolator,tmpIndex,tensorValue);
443 
444  anima::GetTensorFromVectorRepresentation(tensorValue,tmpMat,3,false);
445 
446  double adcValue = 0;
447  for (unsigned int j = 0;j < 3;++j)
448  adcValue += tmpMat(j,j);
449 
450  adcArray->InsertNextValue(adcValue / 3.0);
451 
452  double faValue = 0;
453  double faValueDenom = 0;
454  EigenAnalysis.ComputeEigenValues(tmpMat,eVals);
455  for (unsigned int j = 0;j < 3;++j)
456  {
457  faValueDenom += eVals[j] * eVals[j];
458  for (unsigned int k = j + 1;k < 3;++k)
459  faValue += (eVals[j] - eVals[k]) * (eVals[j] - eVals[k]);
460  }
461 
462  faValue = std::sqrt(faValue / (2.0 * faValueDenom));
463  faArray->InsertNextValue(faValue);
464  }
465 
466  outputPtr->GetPointData()->AddArray(faArray);
467  outputPtr->GetPointData()->AddArray(adcArray);
468 }
469 
470 } // end of namespace anima
virtual Vector3DType ProposeNewDirection(Vector3DType &oldDirection, VectorType &modelValue, Vector3DType &sampling_direction, double &log_prior, double &log_proposal, std::mt19937 &random_generator, unsigned int threadId) ITK_OVERRIDE
void GetEigenValueCombinations(VectorType &modelValue, double &meanLambda, double &perpLambda)
virtual Vector3DType InitializeFirstIterationFromModel(Vector3DType &colinearDir, VectorType &modelValue, unsigned int threadId) ITK_OVERRIDE
void GetDTIPrincipalDirection(const VectorType &modelValue, Vector3DType &resVec, bool is2d)
double EvaluateWatsonPDF(const VectorType &v, const VectorType &meanAxis, const ScalarType &kappa)
void GetVectorRepresentation(const vnl_matrix< T1 > &tensor, itk::VariableLengthVector< T2 > &vector, unsigned int vecDim=0, bool scale=false)
void ComputeAdditionalScalarMaps() ITK_OVERRIDE
Computes additional scalar maps that are model dependent to add to the output.
void GetTensorFromVectorRepresentation(const itk::VariableLengthVector< T1 > &vector, vnl_matrix< T2 > &tensor, unsigned int tensDim=0, bool scale=false)
void GetDTIMinorDirection(VectorType &modelValue, Vector3DType &resVec)
virtual bool CheckModelProperties(double estimatedB0Value, double estimatedNoiseValue, VectorType &modelValue, unsigned int threadId) ITK_OVERRIDE
double ComputeScalarProduct(const VectorType &v1, const VectorType &v2, const unsigned int NDimension)
double safe_log(const ScalarType x)
virtual double ComputeLogWeightUpdate(double b0Value, double noiseValue, Vector3DType &newDirection, VectorType &modelValue, double &log_prior, double &log_proposal, unsigned int threadId) ITK_OVERRIDE
void SampleFromWatsonDistribution(const ScalarType &kappa, const VectorType &meanDirection, VectorType &resVec, unsigned int DataDimension, std::mt19937 &generator)
virtual void ComputeModelValue(InterpolatorPointer &modelInterpolator, ContinuousIndexType &index, VectorType &modelValue) ITK_OVERRIDE