ANIMA  4.0
animaDTITractographyImageFilter.cxx
Go to the documentation of this file.
2 #include <itkSymmetricEigenAnalysis.h>
4 
5 #include <vtkDoubleArray.h>
6 #include <vtkPointData.h>
7 #include <animaBaseTensorTools.h>
8 
9 namespace anima
10 {
11 
13 {
14  m_StopFAThreshold = 0.1;
15  m_StopADCThreshold = 2.0e-3;
16 }
17 
19 {
20 }
21 
23 {
24  this->Superclass::SetInputImage(input);
25 
26  m_DTIInterpolator = DTIInterpolatorType::New();
27  m_DTIInterpolator->SetInputImage(this->GetInputImage());
28 }
29 
30 bool dtiTractographyImageFilter::CheckModelCompatibility(VectorType &modelValue, itk::ThreadIdType threadId)
31 {
32  typedef vnl_matrix <double> MatrixType;
33 
34  itk::SymmetricEigenAnalysis <MatrixType,vnl_diag_matrix <double>,MatrixType> EigenAnalysis(3);
35  MatrixType tmpMat(3,3);
36 
38 
39  vnl_diag_matrix <double> eVals(3);
40  EigenAnalysis.ComputeEigenValues(tmpMat,eVals);
41 
42  double meanEvals = 0;
43  for (unsigned int i = 0;i < 3;++i)
44  {
45  eVals[i] = std::exp(eVals[i]);
46  meanEvals += eVals[i];
47  }
48 
49  meanEvals /= 3.0;
50 
51  if (meanEvals > m_StopADCThreshold)
52  return false;
53 
54  double num = 0;
55  double denom = 0;
56  for (unsigned int i = 0;i < 3;++i)
57  {
58  num += (eVals[i] - meanEvals) * (eVals[i] - meanEvals);
59  denom += eVals[i] * eVals[i];
60  }
61 
62  double FAValue = std::sqrt(3.0 * num / (2.0 * denom));
63 
64  if (FAValue < m_StopFAThreshold)
65  return false;
66 
67  return true;
68 }
69 
71 {
72  return m_DTIInterpolator->IsInsideBuffer(index);
73 }
74 
75 void
77 {
78  modelValue = m_DTIInterpolator->EvaluateAtContinuousIndex(index);
79 }
80 
82 dtiTractographyImageFilter::GetModelPrincipalDirection(VectorType &modelValue, bool is2d, itk::ThreadIdType threadId)
83 {
84  typedef vnl_matrix <double> MatrixType;
85 
86  itk::SymmetricEigenAnalysis <MatrixType,vnl_diag_matrix <double>,MatrixType> EigenAnalysis(3);
87 
88  MatrixType tmpMat(3,3);
89  vnl_diag_matrix <double> eVals(3);
90  MatrixType eVec(3,3);
91 
93 
94  EigenAnalysis.ComputeEigenValuesAndVectors(tmpMat,eVals,eVec);
95  PointType resDir;
96  resDir.Fill(0);
97 
98  for (unsigned int i = 0;i < 3;++i)
99  resDir[i] = eVec(2,i);
100 
101  if (is2d)
102  {
103  resDir[2] = 0;
104 
105  double norm = 0;
106  for (unsigned int i = 0;i < 2;++i)
107  norm += resDir[i] * resDir[i];
108  norm = std::sqrt(norm);
109 
110  for (unsigned int i = 0;i < 2;++i)
111  resDir[i] /= norm;
112  }
113 
114  return resDir;
115 }
116 
118 dtiTractographyImageFilter::GetNextDirection(PointType &previousDirection, VectorType &modelValue, bool is2d,
119  itk::ThreadIdType threadId)
120 {
121  PointType newDirection = this->GetModelPrincipalDirection(modelValue,is2d,threadId);
122  if (anima::ComputeScalarProduct(previousDirection, newDirection) < 0)
123  anima::Revert(newDirection,newDirection);
124 
125  typedef vnl_matrix <double> MatrixType;
126  MatrixType tmpMat(3,3);
127 
128  anima::GetTensorFromVectorRepresentation(modelValue,tmpMat,3,false);
129 
130  vnl_diag_matrix <double> eVals(3);
131  itk::SymmetricEigenAnalysis <MatrixType,vnl_diag_matrix <double>,MatrixType> EigenAnalysis(3);
132  MatrixType eVecs(3,3);
133  EigenAnalysis.ComputeEigenValuesAndVectors(tmpMat,eVals, eVecs);
134 
135  double sumEigs = 0.0;
136  for (unsigned int i = 0;i < 3;++i)
137  {
138  eVals[i] = std::exp(eVals[i]);
139  sumEigs += eVals[i];
140  }
141 
142  anima::RecomposeTensor(eVals,eVecs,tmpMat);
143 
144  // Compute advected direction as in Weinstein et al.
145  PointType advectedDirection;
146 
147  for (unsigned int i = 0;i < 3;++i)
148  {
149  advectedDirection[i] = 0.0;
150  for (unsigned int j = 0;j < 3;++j)
151  advectedDirection[i] += tmpMat(i,j) * previousDirection[j];
152  }
153 
154  anima::Normalize(advectedDirection,advectedDirection);
155  if (anima::ComputeScalarProduct(previousDirection, advectedDirection) < 0)
156  anima::Revert(advectedDirection,advectedDirection);
157 
158  double linearCoefficient = (eVals[2] - eVals[0]) / sumEigs;
159 
160  for (unsigned int i = 0;i < 3;++i)
161  newDirection[i] = newDirection[i] * linearCoefficient + (1.0 - linearCoefficient) * ((1.0 - this->GetPunctureWeight()) * previousDirection[i] + this->GetPunctureWeight() * advectedDirection[i]);
162 
163  anima::Normalize(newDirection,newDirection);
164 
165  return newDirection;
166 }
167 
168 
170 {
171  vtkSmartPointer <vtkPolyData> outputPtr = this->GetOutput();
172 
173  unsigned int numPoints = outputPtr->GetPoints()->GetNumberOfPoints();
174  vtkPoints *myPoints = outputPtr->GetPoints();
175 
176  vtkSmartPointer <vtkDoubleArray> faArray = vtkDoubleArray::New();
177  faArray->SetNumberOfComponents(1);
178  faArray->SetName("FA");
179 
180  vtkSmartPointer <vtkDoubleArray> adcArray = vtkDoubleArray::New();
181  adcArray->SetNumberOfComponents(1);
182  adcArray->SetName("ADC");
183 
184  PointType tmpPoint;
185  DTIInterpolatorType::ContinuousIndexType tmpIndex;
186 
187  typedef vnl_matrix <double> MatrixType;
188  MatrixType tmpMat(3,3);
189 
190  vnl_diag_matrix <double> eVals(3);
191  itk::SymmetricEigenAnalysis <MatrixType,vnl_diag_matrix <double>,MatrixType> EigenAnalysis(3);
192  VectorType tensorValue(6);
193 
195 
196  for (unsigned int i = 0;i < numPoints;++i)
197  {
198  for (unsigned int j = 0;j < 3;++j)
199  tmpPoint[j] = myPoints->GetPoint(i)[j];
200 
201  this->GetInputImage()->TransformPhysicalPointToContinuousIndex(tmpPoint,tmpIndex);
202  tensorValue.Fill(0.0);
203  if (m_DTIInterpolator->IsInsideBuffer(tmpIndex))
204  this->GetModelValue(tmpIndex,tensorValue);
205 
206  anima::GetTensorFromVectorRepresentation(tensorValue,tmpMat,3,false);
207  leCalculator->GetTensorExponential(tmpMat,tmpMat);
208 
209  double adcValue = 0;
210  for (unsigned int j = 0;j < 3;++j)
211  adcValue += tmpMat(j,j);
212 
213  adcArray->InsertNextValue(adcValue / 3.0);
214 
215  double faValue = 0;
216  double faValueDenom = 0;
217  EigenAnalysis.ComputeEigenValues(tmpMat,eVals);
218  for (unsigned int j = 0;j < 3;++j)
219  {
220  faValueDenom += eVals[j] * eVals[j];
221  for (unsigned int k = j + 1;k < 3;++k)
222  faValue += (eVals[j] - eVals[k]) * (eVals[j] - eVals[k]);
223  }
224 
225  faValue = std::sqrt(faValue / (2.0 * faValueDenom));
226  faArray->InsertNextValue(faValue);
227  }
228 
229  outputPtr->GetPointData()->AddArray(faArray);
230  outputPtr->GetPointData()->AddArray(adcArray);
231 }
232 
233 } // end of namespace anima
void Revert(const VectorType &v, const unsigned int vSize, VectorType &resVec)
virtual PointType GetModelPrincipalDirection(VectorType &modelValue, bool is2d, itk::ThreadIdType threadId) ITK_OVERRIDE
virtual PointType GetNextDirection(PointType &previousDirection, VectorType &modelValue, bool is2d, itk::ThreadIdType threadId) ITK_OVERRIDE
virtual bool CheckModelCompatibility(VectorType &modelValue, itk::ThreadIdType threadId) ITK_OVERRIDE
virtual void SetInputImage(ModelImageType *input)
virtual void SetInputImage(ModelImageType *input) ITK_OVERRIDE
virtual bool CheckIndexInImageBounds(ContinuousIndexType &index) ITK_OVERRIDE
void GetTensorExponential(const vnl_matrix< TScalarType > &tensor, vnl_matrix< TScalarType > &log_tensor)
itk::ContinuousIndex< double, 3 > ContinuousIndexType
void GetTensorFromVectorRepresentation(const itk::VariableLengthVector< T1 > &vector, vnl_matrix< T2 > &tensor, unsigned int tensDim=0, bool scale=false)
virtual void GetModelValue(ContinuousIndexType &index, VectorType &modelValue) ITK_OVERRIDE
Computes value of model from data. May use SNR and previous model value to perform smart interpolatio...
void RecomposeTensor(vnl_diag_matrix< T1 > &eigs, vnl_matrix< T1 > &eigVecs, vnl_matrix< T2 > &resMatrix)
Recompose tensor from values extracted using SymmetricEigenAnalysis (vnl_symmetric_eigensystem transp...
void Normalize(const VectorType &v, const unsigned int NDimension, VectorType &resVec)
double ComputeScalarProduct(const VectorType &v1, const VectorType &v2, const unsigned int NDimension)