18 #ifndef __itkDiffusionTensor_hxx 19 #define __itkDiffusionTensor_hxx 24 #include "vnl/vnl_matrix.h" 25 #include <vnl/vnl_math.h> 26 #include "vnl/vnl_vector.h" 27 #include "vnl/vnl_trace.h" 28 #include "vnl/algo/vnl_determinant.h" 37 template<
class TPrecision >
46 k = row * NDimension + col - row * ( row + 1 ) / 2;
50 k = col * NDimension + row - col * ( col + 1 ) / 2;
53 utlAssert(k < NDegreesOfFreedom,
"wrong dimension");
61 template<
class TPrecision >
70 k = row * NDimension + col - row * ( row + 1 ) / 2;
74 k = col * NDimension + row - col * ( col + 1 ) / 2;
76 utlAssert(k < NDegreesOfFreedom,
"wrong dimension");
81 template<
class TPrecision >
88 this->ComputeEigenAnalysis(values, vectors);
90 eigenValues.set_size(NDimension);
91 for (
int i = 0; i < NDimension; i += 1 )
92 eigenValues[i] = values[i];
93 eigenVectors = vectors.GetVnlMatrix().transpose();
96 template<
class TPrecision>
97 template<
class TArrayType,
class TMatrixType >
102 if (IsDiagonal(1e-10))
104 for (
int i = 0; i < 3; ++i )
106 eigenValues[i] = (*this)(i,i);
107 eigenVectors(i,i) = 1.0;
108 for (
int j = 0; j < 3; ++j )
111 eigenVectors(i,j) = 0.0;
116 if (eigenValues[0]>eigenValues[1])
118 std::swap(eigenValues[0], eigenValues[1]);
119 for (
int i = 0; i < 3; ++i )
120 std::swap(eigenVectors(i,0), eigenVectors(i,1));
122 if (eigenValues[1]>eigenValues[2])
124 std::swap(eigenValues[1], eigenValues[2]);
125 for (
int i = 0; i < 3; ++i )
126 std::swap(eigenVectors(i,1), eigenVectors(i,2));
128 if (eigenValues[0]>eigenValues[1])
130 std::swap(eigenValues[0], eigenValues[1]);
131 for (
int i = 0; i < 3; ++i )
132 std::swap(eigenVectors(i,0), eigenVectors(i,1));
137 std::vector<double> detCoef(4);
138 std::vector<std::complex<double> > lambdaVec;
140 const TPrecision* p = this->GetDataPointer();
141 detCoef[0] = p[2]*p[2]*p[3] - 2.0*p[1]*p[2]*p[4] + p[0]*p[4]*p[4] + p[1]*p[1]*p[5] - p[0]*p[3]*p[5];
142 detCoef[1] = -p[1]*p[1] - p[2]*p[2] + p[0]*p[3] - p[4]*p[4] + p[0]*p[5] + p[3]*p[5];
143 detCoef[2] = -p[0] - p[3] - p[5];
147 for (
int i = 0; i < 3; ++i )
148 eigenValues[i] = std::real(lambdaVec[i]);
151 if (eigenValues[0]>eigenValues[1])
152 std::swap(eigenValues[0], eigenValues[1]);
153 if (eigenValues[1]>eigenValues[2])
154 std::swap(eigenValues[1], eigenValues[2]);
155 if (eigenValues[0]>eigenValues[1])
156 std::swap(eigenValues[0], eigenValues[1]);
158 bool numericalZero =
false;
159 if (std::fabs(p[2])<1e-5)
160 numericalZero =
true;
164 double norm, v1,v2,v3;
166 double p2=p[2], p1=p[1];
168 double cebf = -p2*p[4]+p1*p[5];
169 double cdbe = -p2*p[3]+p1*p[4];
170 for (
int i = 0; i < 3; ++i )
172 v1 = -(p[5]-eigenValues[i])*(cdbe+p2*eigenValues[i]) + p[4]*(cebf-p1*eigenValues[i]);
173 v2 = -p2*(cebf-p1*eigenValues[i]);
174 v3 = p2*(cdbe+p2*eigenValues[i]);
175 norm = std::sqrt(v1*v1 + v2*v2 + v3*v3);
176 if (std::fabs(p2)<1e-5 || std::fabs(cdbe+p2*eigenValues[i])<1e-5 )
182 eigenVectors(0,i) = v1/norm;
183 eigenVectors(1,i) = v2/norm;
184 eigenVectors(2,i) = v3/norm;
190 vnl_diag_matrix<TPrecision> val;
191 vnl_matrix<double> vec;
192 GetEigenValuesVectors(val, vec);
193 for (
int i = 0; i < 3; ++i )
194 for (
int j = 0; j < 3; ++j )
195 eigenVectors(i,j) = vec(i,j);
199 template<
class TPrecision>
200 template<
class TArrayType >
205 if (this->IsDiagonal())
207 for (
int i = 0; i < NDimension; i += 1 )
208 (*
this)(i,i) = array[i];
212 vnl_diag_matrix<TPrecision> eigenValues(NDimension);
213 vnl_matrix<TPrecision> eigenVectors(NDimension, NDimension);
214 this->GetEigenValuesVectorsAnalytic(eigenValues, eigenVectors);
215 for (
int i = 0; i < NDimension; i += 1 )
216 eigenValues[i] = array[i];
217 *
this = eigenVectors * eigenValues.asMatrix() * eigenVectors.transpose();
221 template<
class TPrecision>
222 template<
class TMatrixType >
227 vnl_matrix<TPrecision> eigenVectors(NDimension, NDimension);
228 for (
int i = 0; i < NDimension; i += 1 )
229 for (
int j = 0; j < NDimension; j += 1 )
230 eigenVectors(i,j) = (TPrecision)vectors(i,j);
231 if (this->IsDiagonal())
232 *
this = eigenVectors * (*
this) * eigenVectors.transpose();
235 vnl_diag_matrix<TPrecision> eigenValues(NDimension);
236 this->GetEigenValuesVectorsAnalytic(eigenValues, eigenVectors);
237 *
this = eigenVectors * eigenValues.asMatrix() * eigenVectors.transpose();
242 template<
class TPrecision >
243 vnl_matrix<TPrecision>
247 TPrecision* block =
new TPrecision[9];
248 for(
unsigned int i=0;i<NDimension;i++)
249 for(
unsigned int j=0;j<NDimension;j++)
250 block[NDimension*i+j] = (*
this)(i,j);
252 vnl_matrix< TPrecision > result = vnl_matrix< TPrecision >(block, NDimension, NDimension);
257 template<
class TPrecision>
262 for(
unsigned int i=0; i<NDimension; i++)
264 for(
unsigned int j=i; j<NDimension; j++)
265 (*
this)[NDimension*i-(i+1)*i/2+j] = mat(i,j);
269 template<
class TPrecision>
274 this->SetVnlMatrix ( this->GetRotate (R.GetVnlMatrix() ) );
278 template<
class TPrecision>
284 res.
SetVnlMatrix ( this->GetRotate (R.GetVnlMatrix() ) );
289 template<
class TPrecision>
290 vnl_matrix<TPrecision>
294 vnl_matrix<TPrecision> res;
295 res = ( R*(this->GetVnlMatrix())*R.transpose() );
299 template <
class TPrecision>
304 return (*
this)[0]*x*x + 2*(*this)[1]*x*y + 2*(*this)[2]*x*z +
305 (*this)[3]*y*y + 2*(*this)[4]*y*z + (*this)[5]*z*z;
308 template <
class TPrecision>
309 template <
class TVectorType >
314 for (
int i = 0; i < gradients.Rows(); i += 1 )
316 TPrecision x=gradients(i,0), y=gradients(i,1), z=gradients(i,2);
317 double quadratic = GetQuadraticForm(x,y,z);
318 samples[i] = GetQuadraticForm(x,y,z);
322 template <
class TPrecision>
323 template <
class TVectorType >
328 utlAssert(gradients.Rows()==bValues.size(),
"wrong size! gradients.Rows()="<< gradients.Rows() <<
", bValues.size()="<<bValues.size());
330 for (
int i = 0; i < gradients.Rows(); i += 1 )
332 TPrecision x=gradients(i,0), y=gradients(i,1), z=gradients(i,2);
333 double quadratic = GetQuadraticForm(x,y,z);
334 dwisignal[i] = std::exp(-1.0*bValues[i]*quadratic);
338 template <
class TPrecision >
339 template <
class TVectorType >
345 TPrecision D_det = this->GetDeterminant();
346 for (
int i = 0; i < gradients.Rows(); i += 1 )
348 TPrecision x=gradients(i,0), y=gradients(i,1), z=gradients(i,2);
349 TPrecision quadratic_inv = D_inv(0,0)*x*x + 2*D_inv(0,1)*x*y + 2*D_inv(0,2)*x*z +
350 D_inv(1,1)*y*y + 2*D_inv(1,2)*y*z + D_inv(2,2)*z*z;
352 odf[i] = 1.0 / ( std::pow(D_det, 0.5) * std::pow(quadratic_inv,0.5*(odfOrder+1)) ) ;
354 odf[i] *= 1.0/(4*
M_PI);
358 if (isNormalize && odfOrder!=2)
360 TPrecision normFactor = 4*
M_PI*utl::GetSumOfVector<TVectorType>(odf,gradients.Rows()) / gradients.Rows();
363 for (
int i = 0; i < gradients.Rows(); i += 1 )
364 odf[i] /= normFactor;
369 template <
class TPrecision >
370 template <
class TVectorType >
375 utlAssert(gradients.Rows()==rValues.size(),
"wrong size! gradients.Rows()="<< gradients.Rows() <<
", rValues.size()="<<rValues.size());
378 TPrecision D_det = this->GetDeterminant();
379 for (
int i = 0; i < gradients.Rows(); i += 1 )
381 TPrecision x=gradients(i,0), y=gradients(i,1), z=gradients(i,2);
382 TPrecision quadratic_inv = D_inv(0,0)*x*x + 2*D_inv(0,1)*x*y + 2*D_inv(0,2)*x*z +
383 D_inv(1,1)*y*y + 2*D_inv(1,2)*y*z + D_inv(2,2)*z*z;
384 eap[i] = 1.0 / (std::pow(4.0*
M_PI*tau,(
double)1.5)*std::sqrt(D_det) ) * std::exp(-1.0/(4.0*tau)*rValues[i]*rValues[i]*quadratic_inv);
388 template <
class TPrecision >
394 return 1.0 / (std::pow(4*
M_PI*tau,(
double)1.5)*std::sqrt(D_det) );
397 template <
class TPrecision >
402 return this->GetTrace()*2.0*tau;
405 template <
class TPrecision >
410 vnl_diag_matrix<TPrecision> eigenValues(NDimension);
411 vnl_matrix<TPrecision> eigenVectors(NDimension, NDimension);
412 this->GetEigenValuesVectorsAnalytic(eigenValues, eigenVectors);
414 vnl_diag_matrix<TPrecision> logeigenValues(NDimension);
415 for (
int i = 0; i < NDimension; i += 1 )
416 logeigenValues[i] = std::log(eigenValues[i]);
418 TPrecision meanEigenValues=0.0, ga=0.0;
419 for (
int i = 0; i < NDimension; i += 1 )
420 meanEigenValues += logeigenValues[i];
421 meanEigenValues /= NDimension;
422 for (
int i = 0; i < NDimension; i += 1 )
424 double tmp = logeigenValues[i]-meanEigenValues;
427 return std::sqrt(ga);
430 template <
class TPrecision >
435 return this->GetFractionalAnisotropy();
438 template <
class TPrecision >
446 template <
class TPrecision >
451 return this->GetRelativeAnisotropy();
454 template <
class TPrecision >
466 double dtNorm = dTensor.
GetNorm();
471 template<
class TPrecision>
476 utlAssert (this->IsFinite(),
"Tensor is not finite");
478 this->ComputeEigenValues(eigenValues);
479 if( eigenValues[0] <= NumericTraits<double>::Zero )
484 template<
class TPrecision>
492 vnl_diag_matrix<TPrecision> eigenValues(NDimension);
493 vnl_matrix<TPrecision> eigenVectors(NDimension, NDimension);
494 this->GetEigenValuesVectorsAnalytic(eigenValues, eigenVectors);
496 for (
int i = 0; i < NDimension; i += 1 )
498 if (eigenValues[i]<0)
501 *
this = eigenVectors* eigenValues.asMatrix()* eigenVectors.transpose();
504 template<
class TPrecision>
509 for (
int i = 0; i < NDegreesOfFreedom; i += 1 )
511 if (std::fabs((*
this)[i])>eps)
517 template<
class TPrecision>
522 for (
int i = 0; i < NDimension; i += 1 )
523 for (
int j = i+1; j < NDimension; j += 1 )
525 if (std::fabs((*
this)(i,j))>eps)
531 template<
class TPrecision>
536 return this->GetVnlMatrix().is_finite();
539 template<
class TPrecision>
544 return this->GetVnlMatrix().has_nans();
547 template<
class TPrecision>
552 const TPrecision* p = this->GetDataPointer();
553 return -p[2]*p[2]*p[3] + 2.0*p[1]*p[2]*p[4] - p[0]*p[4]*p[4] - p[1]*p[1]*p[5] + p[0]*p[3]*p[5];
556 template<
class TPrecision>
561 const TPrecision* p = this->GetDataPointer();
562 return std::sqrt(p[0]*p[0]+2.0*p[1]*p[1]+2.0*p[2]*p[2] + p[3]*p[3]+ 2.0*p[4]*p[4] + p[5]*p[5]);
565 template<
class TPrecision>
570 utlException (!this->IsFinite(),
"Tensor is not finite");
572 vnl_diag_matrix<TPrecision> eigenValues(NDimension);
573 vnl_matrix<TPrecision> eigenVectors(NDimension, NDimension);
574 this->GetEigenValuesVectorsAnalytic(eigenValues, eigenVectors);
575 for(
unsigned int i=0;i<NDimension;i++)
577 utlException (eigenValues[i] < 0.0,
"Negative eigenvalue encountered.");
578 eigenValues[i] = vcl_log (eigenValues[i]);
581 vnl_matrix<TPrecision> vnl_result = eigenVectors * eigenValues.asMatrix() * eigenVectors.transpose();
586 template<
class TPrecision>
591 utlAssert(this->IsFinite(),
"Tensor is not finite");
593 vnl_diag_matrix<TPrecision> eigenValues(NDimension);
594 vnl_matrix<TPrecision> eigenVectors(NDimension, NDimension);
595 this->GetEigenValuesVectorsAnalytic(eigenValues, eigenVectors);
596 for(
unsigned int i=0;i<NDimension;i++)
597 eigenValues[i] = vcl_exp (eigenValues[i]);
599 vnl_matrix<TPrecision> vnl_result = eigenVectors * eigenValues.asMatrix() * eigenVectors.transpose();
604 template<
class TPrecision>
609 utlAssert (this->IsFinite(),
"Tensor is not finite");
612 vnl_diag_matrix<TPrecision> eigenValues(NDimension);
613 vnl_matrix<TPrecision> eigenVectors(NDimension, NDimension);
614 this->GetEigenValuesVectorsAnalytic(eigenValues, eigenVectors);
624 for(
unsigned int i=0;i<NDimension;i++)
626 utlException(n<0 &&
std::abs(eigenValues[i])<=1e-10,
"pow="<<n<<
", eigenValues["<<i<<
"]="<<eigenValues[i] <<
" close to zero");
627 eigenValues[i] =
static_cast<TPrecision
> (vcl_pow (static_cast<double>(eigenValues[i]), n));
630 vnl_matrix<TPrecision> vnl_result = eigenVectors * eigenValues.asMatrix() * eigenVectors.transpose();
635 template<
class TPrecision>
640 double det = GetDeterminant();
642 double detInv=1.0/det;
643 const TPrecision* p = this->GetDataPointer();
645 result[0] = (-p[4]*p[4] + p[3]*p[5]) *detInv;
646 result[1] = ( p[2]*p[4] - p[1]*p[5]) *detInv;
647 result[2] = (-p[2]*p[3] + p[1]*p[4]) *detInv;
648 result[3] = (-p[2]*p[2] + p[0]*p[5]) *detInv;
649 result[4] = ( p[1]*p[2] - p[0]*p[4]) *detInv;
650 result[5] = (-p[1]*p[1] + p[0]*p[3]) *detInv;
655 template<
class TPrecision>
660 return this->
Pow (0.5);
664 template<
class TPrecision>
669 return this->
Pow (-0.5);
672 template<
typename TPrecision>
677 return (*
this - X).GetInnerScalarProduct();
680 template<
typename TPrecision>
687 const TPrecision tr = (ithis*X + iX*(*this)).GetTrace();
688 return 0.5*std::sqrt(tr - 2*NDimension);
691 template<
typename TPrecision>
698 return std::sqrt(0.5*(A*A).GetTrace());
701 template<
typename TPrecision>
708 return (logThis-logX).GetInnerScalarProduct();
Superclass::RealValueType RealValueType
NDArray is a N-Dimensional array class (row-major, c version)
void GetEAPSamples(TVectorType &vec, const utl::NDArray< TPrecision, 2 > &gradients, const std::vector< TPrecision > &rValues, const TPrecision &tau) const
RealValueType GetMODE() const
helper functions specifically used in dmritool
TPrecision GeodesicDistance(const DiffusionTensor< TPrecision > &X) const
TPrecision LogEucDistance(const DiffusionTensor< TPrecision > &X) const
auto Pow(const TLeft &lhs, const TRight &rhs) -> decltype(utl::F< utl::Functor::Pow< Expr2ValueType< TLeft, TRight >> >(lhs, rhs))
TPrecision EuclideanDistance(const DiffusionTensor< TPrecision > &X) const
RealValueType GetRA() const
void GetDWISamples(TVectorType &vec, const utl::NDArray< TPrecision, 2 > &gradients, const std::vector< TPrecision > &bValues) const
auto Log(const ExprT &expr) -> decltype(utl::F< utl::Functor::Log< typename ExprT::ValueType > >(expr))
#define utlException(cond, expout)
RealValueType GetReturnToOrigin(const TPrecision tau) const
Self Pow(const double &n) const
void GetEigenValuesVectors(vnl_diag_matrix< TPrecision > &eigenValues, vnl_matrix< TPrecision > &eigenVectors) const
Return an array containing EigenValues in ascending order, and a matrix containing the corresponding ...
void GetEigenValuesVectorsAnalytic(TArrayType &eigenValues, TMatrixType &eigenVectors) const
analytic way to calculate eigenValues (in ascending order) and eigenVectors. In mathematica, Eigenvectors[( { {a, b, c}, {b, d, e}, {c, e, f} } )]
double GetDeterminant() const
std::vector< std::complex< double > > PolynomialRoot(const std::vector< double > &coef)
RealValueType GetFA() const
Self & Rotate(const typename Self::MatrixType &mat)
ValueType & operator()(unsigned int row, unsigned int col)
RealValueType GetADC() const
T abs(const T x)
template version of the fabs function
#define utlGlobalException(cond, expout)
Superclass::EigenValuesArrayType EigenValuesArrayType
void SetEigenValues(const TArrayType &array)
vnl_matrix< TPrecision > GetVnlMatrix() const
Superclass::EigenVectorsMatrixType EigenVectorsMatrixType
#define utlAssert(cond, expout)
void SetVnlMatrix(const vnl_matrix< TPrecision > &mat)
bool IsZero(const double eps=1e-10) const
bool IsDiagonal(const double eps=1e-10) const
RealValueType GetGA() const
void GetSphericalSamples(TVectorType &vec, const utl::NDArray< TPrecision, 2 > &gradients) const
RealValueType GetMeanSquaredDisplacement(const TPrecision tau) const
void GetODFSamples(TVectorType &vec, const utl::NDArray< TPrecision, 2 > &gradients, const int &odfOrder=2, const bool &isNormalize=false) const
Self GetRotate(const typename Self::MatrixType &mat) const
TPrecision KLDistance(const DiffusionTensor< TPrecision > &X) const
double GetQuadraticForm(const double x, const double y, const double z) const
tensor with some useful functions
Superclass::ValueType ValueType
void SetEigenVectors(const TMatrixType &vectors)