ANIMA  4.0
animaBaseTensorTools.hxx
Go to the documentation of this file.
1 #pragma once
2 
3 #include "animaBaseTensorTools.h"
4 
7 
8 namespace anima
9 {
10 
11 template <class TScalarType>
12 void
13 LogEuclideanTensorCalculator <TScalarType>
14 ::GetTensorLogarithm(const vnl_matrix <TScalarType> &tensor, vnl_matrix <TScalarType> &log_tensor)
15 {
16  unsigned int tensDim = tensor.rows();
17 
18  m_EigenAnalyzer.SetDimension(tensDim);
19  m_EigenAnalyzer.SetOrder(tensDim);
20  m_EigVals.set_size(tensDim);
21  m_EigVecs.set_size(tensDim,tensDim);
22 
23  m_EigenAnalyzer.ComputeEigenValuesAndVectors(tensor,m_EigVals,m_EigVecs);
24 
25  for (unsigned int i = 0;i < tensDim;++i)
26  {
27  if (m_EigVals[i] <= 1.0e-16)
28  m_EigVals[i] = 1.0e-16;
29 
30  m_EigVals[i] = std::log(m_EigVals[i]);
31  }
32 
33  anima::RecomposeTensor(m_EigVals,m_EigVecs,log_tensor);
34 }
35 
36 template <class TScalarType>
37 void
39 ::GetTensorPower(const vnl_matrix <TScalarType> &tensor, vnl_matrix <TScalarType> &outputTensor, double powerValue)
40 {
41  unsigned int tensDim = tensor.rows();
42 
43  m_EigenAnalyzer.SetDimension(tensDim);
44  m_EigenAnalyzer.SetOrder(tensDim);
45  m_EigVals.set_size(tensDim);
46  m_EigVecs.set_size(tensDim,tensDim);
47 
48  m_EigenAnalyzer.ComputeEigenValuesAndVectors(tensor,m_EigVals,m_EigVecs);
49 
50  for (unsigned int i = 0;i < tensDim;++i)
51  {
52  if (m_EigVals[i] <= 1.0e-16)
53  m_EigVals[i] = 1.0e-16;
54 
55  m_EigVals[i] = std::pow(m_EigVals[i],powerValue);
56  }
57 
58  anima::RecomposeTensor(m_EigVals,m_EigVecs,outputTensor);
59 }
60 
61 template <class TScalarType>
62 void
64 ::GetTensorExponential(const vnl_matrix <TScalarType> &log_tensor, vnl_matrix <TScalarType> &tensor)
65 {
66  unsigned int tensDim = log_tensor.rows();
67 
68  m_EigenAnalyzer.SetDimension(tensDim);
69  m_EigenAnalyzer.SetOrder(tensDim);
70  m_EigVals.set_size(tensDim);
71  m_EigVecs.set_size(tensDim,tensDim);
72 
73  m_EigenAnalyzer.ComputeEigenValuesAndVectors(tensor,m_EigVals,m_EigVecs);
74 
75  for (unsigned int i = 0;i < tensDim;++i)
76  m_EigVals[i] = std::exp(m_EigVals[i]);
77 
78  anima::RecomposeTensor(m_EigVals,m_EigVecs,tensor);
79 }
80 
81 template <class T1, class T2>
82 void
83 GetVectorRepresentation(const vnl_matrix <T1> &tensor, itk::VariableLengthVector <T2> &vector,
84  unsigned int vecDim, bool scale)
85 {
86  unsigned int dim = tensor.rows();
87  if (vecDim == 0)
88  vecDim = dim * (dim + 1) / 2;
89 
90  double sqrt2 = sqrt(2.0);
91  if (vector.GetSize() != vecDim)
92  vector.SetSize(vecDim);
93 
94  unsigned int pos = 0;
95  for (unsigned int i = 0;i < dim;++i)
96  for (unsigned int j = 0;j <= i;++j)
97  {
98  vector[pos] = tensor(i,j);
99  if ((i != j)&&scale)
100  vector[pos] *= sqrt2;
101  ++pos;
102  }
103 }
104 
105 template <class T1, class T2>
106 void
107 GetTensorFromVectorRepresentation(const itk::VariableLengthVector <T1> &vector,
108  vnl_matrix <T2> &tensor, unsigned int tensDim, bool scale)
109 {
110  unsigned int vecDim = vector.GetSize();
111 
112  if (tensDim == 0)
113  tensDim = std::floor((std::sqrt((double)(8 * vecDim + 1)) - 1) / 2.0);
114 
115  double sqrt2 = std::sqrt(2.0);
116  tensor.set_size(tensDim,tensDim);
117 
118  unsigned int pos = 0;
119  for (unsigned int i = 0;i < tensDim;++i)
120  for (unsigned int j = 0;j <= i;++j)
121  {
122  tensor(i,j) = vector[pos];
123  if (i != j)
124  {
125  if (scale)
126  tensor(i,j) /= sqrt2;
127 
128  tensor(j,i) = tensor(i,j);
129  }
130 
131  ++pos;
132  }
133 }
134 
135 template <class T> void ProjectOnTensorSpace(const vnl_matrix <T> &matrix, vnl_matrix <T> &tensor)
136 {
137  typedef itk::SymmetricEigenAnalysis < vnl_matrix <T>, vnl_diag_matrix<T>, vnl_matrix <T> > EigenAnalysisType;
138  unsigned int tensDim = matrix.rows();
139 
140  EigenAnalysisType eigen(tensDim);
141  vnl_matrix <T> eigVecs(tensDim,tensDim);
142  vnl_diag_matrix <T> eigVals(tensDim);
143 
144  eigen.ComputeEigenValuesAndVectors(matrix,eigVals,eigVecs);
145 
146  for (unsigned int i = 0;i < tensDim;++i)
147  {
148  if (eigVals[i] <= 1.0e-16)
149  eigVals[i] = 1.0e-16;
150  }
151 
152  RecomposeTensor(eigVals,eigVecs,tensor);
153 }
154 
155 template <typename RealType>
156 void
157 ExtractRotationFromJacobianMatrix(vnl_matrix <RealType> &jacobianMatrix, vnl_matrix <RealType> &rotationMatrix,
158  vnl_matrix <RealType> &tmpMat)
159 {
160  unsigned int tensorDimension = 3;
161  tmpMat.set_size(tensorDimension, tensorDimension);
162 
163  for (unsigned int l = 0;l < tensorDimension;++l)
164  for (unsigned int m = l;m < tensorDimension;++m)
165  {
166  double tmpVal = 0.0;
167  for (unsigned int n = 0;n < tensorDimension;++n)
168  tmpVal += jacobianMatrix(l,n)*jacobianMatrix(m,n);
169 
170  tmpMat.put(l,m,tmpVal);
171 
172  if (m != l)
173  tmpMat.put(m,l,tmpVal);
174  }
175 
176  itk::SymmetricEigenAnalysis < vnl_matrix <RealType>, vnl_diag_matrix<RealType>, vnl_matrix <RealType> > eigenComputer(tensorDimension);
177  vnl_matrix <RealType> eVec(tensorDimension,tensorDimension);
178  vnl_diag_matrix <RealType> eVals(tensorDimension);
179 
180  eigenComputer.ComputeEigenValuesAndVectors(tmpMat, eVals, eVec);
181 
182  for (unsigned int i = 0;i < tensorDimension;++i)
183  eVals[i] = std::pow(eVals[i], -0.5);
184 
185  RecomposeTensor(eVals,eVec,rotationMatrix);
186 
187  rotationMatrix *= jacobianMatrix;
188 }
189 
190 template <typename RealType, typename MatrixType>
191 void
192 ExtractPPDRotationFromJacobianMatrix(vnl_matrix <RealType> &jacobianMatrix, vnl_matrix <RealType> &rotationMatrix,
193  MatrixType &eigenVectors)
194 {
195  const unsigned int tensorDimension = 3;
196 
197  typedef vnl_vector_fixed <RealType,tensorDimension> VectorType;
198  VectorType transformedPrincipal;
199  VectorType transformedSecondary;
200  for (unsigned int i = 0;i < tensorDimension;++i)
201  {
202  transformedPrincipal[i] = 0;
203  transformedSecondary[i] = 0;
204  for (unsigned int j = 0;j < tensorDimension;++j)
205  {
206  double jacVal = jacobianMatrix.get(i,j);
207  transformedPrincipal[i] += jacVal * eigenVectors(2,j);
208  transformedSecondary[i] += jacVal * eigenVectors(1,j);
209  }
210  }
211 
212  anima::Normalize(transformedPrincipal,transformedPrincipal);
213  anima::Normalize(transformedSecondary,transformedSecondary);
214 
215  VectorType principalEigenVector;
216  for (unsigned int i = 0;i < tensorDimension;++i)
217  principalEigenVector[i] = eigenVectors(2,i);
218  MatrixType firstRotation = anima::GetRotationMatrixFromVectors(principalEigenVector,transformedPrincipal);
219 
220  VectorType rotatedSecondary;
221  double dotProductTransformed = 0;
222  for (unsigned int i = 0;i < tensorDimension;++i)
223  {
224  dotProductTransformed += transformedPrincipal[i] * transformedSecondary[i];
225  rotatedSecondary[i] = 0;
226  for (unsigned int j = 0;j < tensorDimension;++j)
227  rotatedSecondary[i] += firstRotation(i,j) * eigenVectors(1,j);
228  }
229 
230  VectorType projectedSecondary;
231  for (unsigned int i = 0;i < tensorDimension;++i)
232  projectedSecondary[i] = transformedSecondary[i] - dotProductTransformed * transformedPrincipal[i];
233 
234  anima::Normalize(projectedSecondary,projectedSecondary);
235 
236  MatrixType secondRotation = anima::GetRotationMatrixFromVectors(rotatedSecondary,projectedSecondary);
237  rotationMatrix.set_size(tensorDimension,tensorDimension);
238  rotationMatrix.fill(0.0);
239  for (unsigned int i = 0;i < tensorDimension;++i)
240  {
241  for (unsigned int j = 0;j < tensorDimension;++j)
242  {
243  double rotVal = 0.0;
244  for (unsigned int k = 0;k < tensorDimension;++k)
245  rotVal += secondRotation(i,k) * firstRotation(k,j);
246 
247  rotationMatrix.put(i,j,rotVal);
248  }
249  }
250 }
251 
252 template <class T1, class T2>
253 void
254 RecomposeTensor(vnl_diag_matrix <T1> &eigs, vnl_matrix <T1> &eigVecs, vnl_matrix <T2> &resMatrix)
255 {
256  unsigned int tensorDimension = eigs.size();
257  resMatrix.set_size(tensorDimension,tensorDimension);
258 
259  for (unsigned int i = 0;i < tensorDimension;++i)
260  {
261  for (unsigned int j = i;j < tensorDimension;++j)
262  {
263  double resVal = 0.0;
264  for (unsigned int k = 0;k < tensorDimension;++k)
265  resVal += eigs[k] * eigVecs.get(k,i) * eigVecs.get(k,j);
266 
267  resMatrix.put(i,j,resVal);
268 
269  if (j != i)
270  resMatrix.put(j,i,resVal);
271  }
272  }
273 }
274 
275 template <class T1, class T2, class T3>
276 void RotateSymmetricMatrix(T1 &tensor, T2 &rotationMatrix, T3 &rotated_tensor, unsigned int tensorDim)
277 {
278  for (unsigned int i = 0;i < tensorDim;++i)
279  for (unsigned int j = i;j < tensorDim;++j)
280  {
281  double rotatedValue = 0.0;
282  for (unsigned int a = 0;a < tensorDim;++a)
283  for (unsigned int b = a;b < tensorDim;++b)
284  {
285  double factor = rotationMatrix.get(b,i) * rotationMatrix.get(a,j);
286  if (b != a)
287  factor += rotationMatrix.get(a,i) * rotationMatrix.get(b,j);
288 
289  rotatedValue += tensor.get(a,b) * factor;
290  }
291 
292  rotated_tensor.put(i,j,rotatedValue);
293 
294  if (i != j)
295  rotated_tensor.put(j,i,rotatedValue);
296  }
297 }
298 
299 template <class T1, class T2>
300 void RotateSymmetricMatrix(vnl_matrix <T1> &tensor, vnl_matrix <T2> &rotationMatrix, vnl_matrix <T2> &rotated_tensor)
301 {
302  unsigned int tensorDim = tensor.rows();
303  rotated_tensor.set_size(tensorDim,tensorDim);
304 
305  anima::RotateSymmetricMatrix(tensor,rotationMatrix,rotated_tensor,tensorDim);
306 }
307 
308 template <class T1, class T2, unsigned int NDim>
309 void RotateSymmetricMatrix(itk::Matrix <T1,NDim,NDim> &tensor, itk::Matrix <T2,NDim,NDim> &rotationMatrix,
310  itk::Matrix <T2,NDim,NDim> &rotated_tensor)
311 {
312  anima::RotateSymmetricMatrix(tensor,rotationMatrix,rotated_tensor,NDim);
313 }
314 
315 template <class T1>
316 double
317 ovlScore(vnl_diag_matrix <T1> &eigsX, vnl_matrix <T1> &eigVecsX,
318  vnl_diag_matrix <T1> &eigsY, vnl_matrix <T1> &eigVecsY)
319 {
320  unsigned int sizeData = eigsX.size();
321 
322  long double resVal = 0;
323  long double denomVal = 0;
324 
325  for (unsigned int i = 0;i < sizeData;++i)
326  {
327  long double dotProd = 0;
328  for (unsigned int j = 0;j < sizeData;++j)
329  dotProd += eigVecsX.get(i,j)*eigVecsY.get(i,j);
330 
331  resVal += dotProd * dotProd * eigsX[i] * eigsY[i];
332  denomVal += eigsX[i] * eigsY[i];
333  }
334 
335  return resVal/denomVal;
336 }
337 
338 
339 } // end of namespace anima
double ovlScore(vnl_diag_matrix< T1 > &eigsX, vnl_matrix< T1 > &eigVecsX, vnl_diag_matrix< T1 > &eigsY, vnl_matrix< T1 > &eigVecsY)
itk::Matrix< double, 3, 3 > GetRotationMatrixFromVectors(const VectorType &first_direction, const VectorType &second_direction, const unsigned int dimension)
void ExtractRotationFromJacobianMatrix(vnl_matrix< RealType > &jacobianMatrix, vnl_matrix< RealType > &rotationMatrix, vnl_matrix< RealType > &tmpMat)
void GetVectorRepresentation(const vnl_matrix< T1 > &tensor, itk::VariableLengthVector< T2 > &vector, unsigned int vecDim=0, bool scale=false)
void RotateSymmetricMatrix(T1 &tensor, T2 &rotationMatrix, T3 &rotated_tensor, unsigned int tensorDim)
Rotates a symmetric matrix by performing R^T D R where R is a rotation matrix and D the symmetric mat...
void GetTensorFromVectorRepresentation(const itk::VariableLengthVector< T1 > &vector, vnl_matrix< T2 > &tensor, unsigned int tensDim=0, bool scale=false)
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)
void ProjectOnTensorSpace(const vnl_matrix< T > &matrix, vnl_matrix< T > &tensor)
void ExtractPPDRotationFromJacobianMatrix(vnl_matrix< RealType > &jacobianMatrix, vnl_matrix< RealType > &rotationMatrix, MatrixType &eigenVectors)