ANIMA  4.0
animaODFFunctions.cxx
Go to the documentation of this file.
1 #include <cmath>
2 
3 #include "animaODFFunctions.h"
4 
5 #include <iostream>
6 #include <fstream>
7 
9 #include <animaBaseTensorTools.h>
10 #include <itkSymmetricEigenAnalysis.h>
11 
12 namespace anima
13 {
14 
15 std::vector <std::vector <double> > InitializeSampleDirections(unsigned int nbTheta, unsigned int nbPhi,
16  std::string sampleDirFileName)
17 {
18  std::vector <std::vector <double> > resVal;
19 
20  if (sampleDirFileName == "")
21  {
22  if ((nbTheta == 0)&&(nbPhi == 0))
23  return resVal;
24 
25  std::vector <double> tmpVector(2,0);
26  for (unsigned int i = 0;i < nbTheta;++i)
27  {
28  // Theta varies between 0 and pi/2
29  tmpVector[0] = M_PI/(4*nbTheta) + i*M_PI/(2*nbTheta);
30  for (unsigned int j = 0;j < nbPhi;++j)
31  {
32  // Phi varies between 0 and 2 pi
33  tmpVector[1] = M_PI/nbPhi + 2*i*M_PI/nbPhi;
34  resVal.push_back(tmpVector);
35  }
36  }
37  }
38  else
39  {
40  std::ifstream inputDirectionsFile(sampleDirFileName.c_str());
41  std::string errorMsg = "Could not open sample directions file (";
42  errorMsg += sampleDirFileName;
43  errorMsg += ")";
44 
45  if (!inputDirectionsFile.is_open())
46  throw itk::ExceptionObject(__FILE__, __LINE__,errorMsg,ITK_LOCATION);
47 
48  std::vector <double> gradTmp(3,0);
49  std::vector <double> sphericalGrad(2,0);
50 
51  std::cout << "Using sample directions from file " << sampleDirFileName.c_str() << "..." << std::endl;
52 
53  while (!inputDirectionsFile.eof())
54  {
55  char tmpStr[2048];
56  inputDirectionsFile.getline(tmpStr,2048);
57 
58  if (strcmp(tmpStr,"") == 0)
59  continue;
60 
61  std::stringstream tmpStrStream(tmpStr);
62  tmpStrStream >> gradTmp[0] >> gradTmp[1] >> gradTmp[2];
63 
65  resVal.push_back(sphericalGrad);
66  }
67 
68  inputDirectionsFile.close();
69  }
70 
71  return resVal;
72 }
73 
74 void GetEulerAnglesFromRotationMatrix(vnl_matrix <double> &R, std::vector <double> &resVal)
75 {
76  // This is not really clean. There are still undetermined cases.
77  // R is actually R^T so adapting the values given by Geng et al.
78  // TO DO : or is it ???
79  resVal.resize(3);
80 
81  if (R(2,2) != 1)
82  {
83  resVal[0] = std::atan2(R(1,2),R(0,2)); // alpha
84  resVal[1] = std::acos(R(2,2)); // beta
85  resVal[2] = std::atan2(R(2,1),-R(2,0)); // gamma
86  }
87  else
88  {
89  if (R(1,0) < 0)
90  resVal[0] = - std::acos(R(0,0));
91  else
92  resVal[0] = std::acos(R(0,0));
93 
94  resVal[1] = 0;
95  resVal[2] = 0;
96  }
97 }
98 
99 double GetDValue(unsigned int l, int m, int mp, double angle)
100 {
101  int globalSign = 1;
102  if ((m - mp) % 2 == 1)
103  globalSign = -1;
104 
105  long double factor = std::sqrt(std::tgamma(l+m+1) * std::tgamma(l-m+1) *
106  std::tgamma(l+mp+1) * std::tgamma(l-mp+1));
107 
108  int lowBoundK = 0;
109  if (lowBoundK < mp - m)
110  lowBoundK = mp - m;
111 
112  int supBoundK = l + mp;
113  if (supBoundK > (int)l - m)
114  supBoundK = (int)l - m;
115 
116  long double resVal = 0;
117 
118  for (int k = lowBoundK;k <= supBoundK;++k)
119  {
120  long double cosVal = 1, sinVal = 1;
121 
122  long double factDenom = std::tgamma(k+1) * std::tgamma(l - m - k + 1) *
123  std::tgamma(l + mp - k + 1) * std::tgamma(m - mp + k + 1);
124 
125  int powNum = 2*(l-k) - m + mp;
126 
127  double cosValTmp = cos(angle/2);
128  for (int i = 1;i <= abs(powNum);++i)
129  cosVal *= cosValTmp;
130 
131  if (powNum < 0)
132  cosVal = 1.0/cosVal;
133 
134  powNum = 2*k + m - mp;
135 
136  long double sinValTmp = sin(angle/2);
137  for (int i = 1;i <= abs(powNum);++i)
138  sinVal *= sinValTmp;
139 
140  if (powNum < 0)
141  sinVal = 1.0/sinVal;
142 
143  int kSign = 1;
144  if (k % 2 == 1)
145  kSign = -1;
146 
147  resVal += kSign*cosVal*sinVal/factDenom;
148  }
149 
150  resVal *= factor*globalSign;
151  return resVal;
152 }
153 
154 void EstimateLocalODFRotationMatrix(vnl_matrix <double> &resVal, unsigned int l,
155  double alpha, double beta, double gamma)
156 {
157  unsigned int sizeMat = 2*l + 1;
158  resVal.set_size(sizeMat,sizeMat);
159 
160  // Precompute d-values for use in inner loops
161  vnl_matrix <double> dValues(2*l+1,2*l+1);
162 
163  dValues(l,l) = GetDValue(l,0,0,beta);
164  for (unsigned int m = 1;m <= l;++m)
165  dValues(l+m,l) = GetDValue(l,m,0,beta);
166 
167  for (unsigned int mp = 1;mp <= l;++mp)
168  {
169  for (unsigned int m = 1;m <= l;++m)
170  {
171  dValues(m+l,mp+l) = GetDValue(l,m,mp,beta);
172  dValues(l-m,mp+l) = GetDValue(l,-m,mp,beta);
173  }
174  }
175 
176  for (int m = -l;m < 0;++m)
177  {
178  unsigned int absm = abs(m);
179 
180  int signm = 1;
181  if (m % 2 == 1)
182  signm = -1;
183 
184  for (int mp = -l;mp < 0;++mp)
185  {
186  int signmp = 1;
187  if (mp % 2 == 1)
188  signmp = -1;
189 
190  // Case all inferior to 0 ->double checked
191  unsigned int absmp = abs(mp);
192  resVal(m+l,mp+l) = dValues(absmp+l,absm+l)*cos(m*alpha+mp*gamma) + signmp*dValues(m+l,absmp+l)*cos(m*alpha-mp*gamma);
193  }
194 
195  for (int mp = 1;mp <= (int)l;++mp)
196  {
197  // Case m < 0, mp > 0
198  resVal(m+l,mp+l) = dValues(m+l,mp+l)*sin(m*alpha+mp*gamma) - signm*dValues(l+absm,l+mp)*sin(m*alpha-mp*gamma);
199  }
200  }
201 
202  for (int m = 1;m <= (int)l;++m)
203  {
204  int signm1 = 1;
205  if (m % 2 == 0)
206  signm1 = -1;
207 
208  for (int mp = -l;mp < 0;++mp)
209  {
210  int signall = 1;
211  if ((m+mp) % 2 == 1)
212  signall = -1;
213 
214  int signmp1 = 1;
215  if (mp % 2 == 0)
216  signmp1 = -1;
217 
218  // Case m > 0, mp < 0
219  resVal(m+l,mp+l) = - signall*dValues(l-m,l-mp)*sin(m*alpha+mp*gamma) + signmp1*dValues(l+m,l-mp)*sin(m*alpha-mp*gamma);
220  }
221 
222 
223  for (int mp = 1;mp <= (int)l;++mp)
224  {
225  // Case m > 0, mp > 0 ->double checked
226  resVal(m+l,mp+l) = dValues(l+m,l+mp)*cos(m*alpha+mp*gamma) + signm1*dValues(l-m,l+mp)*cos(m*alpha-mp*gamma);
227  }
228  }
229 
230  // This leaves only cases where one or all of m or mp are 0
231 
232  double sqrt2 = sqrt(2.0);
233  for (int m = 1;m <= (int)l;++m)
234  {
235  double dValue = dValues(l+m,l);
236  double oppDValue = dValue;
237  if (m % 2 == 1)
238  oppDValue = -dValue;
239 
240  resVal(l-m,l) = sqrt2*oppDValue*cos(m*alpha);
241  resVal(l,l-m) = sqrt2*dValue*cos(m*gamma);
242 
243  resVal(m+l,l) = - sqrt2*dValue*sin(m*alpha);
244  resVal(l,m+l) = sqrt2*oppDValue*sin(m*gamma);
245  }
246 
247  resVal(l,l) = GetDValue(l,0,0,beta);
248 }
249 
250 } // end of namespace anima
void GetEulerAnglesFromRotationMatrix(vnl_matrix< double > &R, std::vector< double > &resVal)
void EstimateLocalODFRotationMatrix(vnl_matrix< double > &resVal, unsigned int l, double alpha, double beta, double gamma)
double GetDValue(unsigned int l, int m, int mp, double angle)
std::vector< std::vector< double > > InitializeSampleDirections(unsigned int nbTheta, unsigned int nbPhi, std::string sampleDirFileName)
void TransformCartesianToSphericalCoordinates(const VectorType &v, VectorType &resVec)