Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
mitkGibbsEnergyComputer.cpp
Go to the documentation of this file.
2 
3 #include <vnl/vnl_vector_fixed.h>
4 #include <vnl/vnl_copy.h>
5 #include <itkNumericTraits.h>
6 #include <MitkFiberTrackingExports.h>
7 #include <itkMersenneTwisterRandomVariateGenerator.h>
8 
9 using namespace mitk;
10 
12 :EnergyComputer(mask, particleGrid, interpolator, randGen)
13 
14 {
15  m_Image = qballImage;
16 }
17 
19 {
20 
21 }
22 
23 float GibbsEnergyComputer::EvaluateOdf(vnl_vector_fixed<float, 3>& pos, vnl_vector_fixed<float, 3> dir)
24 {
25  const int sampleSteps = 10; // evaluate ODF at 2*sampleSteps+1 positions along dir
26  vnl_vector_fixed<float, 3> samplePos; // current position to evaluate
27  float result = 0; // average of sampled ODF values
28  int xint, yint, zint; // voxel containing samplePos
29 
30  // rotate particle direction according to image rotation
31  dir = m_RotationMatrix*dir;
32 
33  // get interpolation for rotated direction
35 
36  // sample ODF values along particle direction
37  for (int i=-sampleSteps; i <= sampleSteps;i++)
38  {
39  samplePos = pos + (dir * m_ParticleLength) * ((float)i/sampleSteps);
40 
41  if (!m_UseTrilinearInterpolation) // image has not enough slices to use trilinear interpolation
42  {
43  ItkQBallImgType::IndexType index;
44  index[0] = floor(pos[0]/m_Spacing[0]);
45  index[1] = floor(pos[1]/m_Spacing[1]);
46  index[2] = floor(pos[2]/m_Spacing[2]);
47  if (m_Image->GetLargestPossibleRegion().IsInside(index))
48  {
49  result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] +
50  m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] +
51  m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2]);
52  }
53  }
54  else // use trilinear interpolation
55  {
56  float Rx = samplePos[0]/m_Spacing[0]-0.5;
57  float Ry = samplePos[1]/m_Spacing[1]-0.5;
58  float Rz = samplePos[2]/m_Spacing[2]-0.5;
59 
60  xint = floor(Rx);
61  yint = floor(Ry);
62  zint = floor(Rz);
63 
64  if (xint >= 0 && xint < m_Size[0]-1 && yint >= 0 && yint < m_Size[1]-1 && zint >= 0 && zint < m_Size[2]-1)
65  {
66  float xfrac = Rx-xint;
67  float yfrac = Ry-yint;
68  float zfrac = Rz-zint;
69 
70  ItkQBallImgType::IndexType index;
71  float weight;
72 
73  weight = (1-xfrac)*(1-yfrac)*(1-zfrac);
74  index[0] = xint; index[1] = yint; index[2] = zint;
75  result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] +
76  m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] +
77  m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight;
78 
79  weight = (xfrac)*(1-yfrac)*(1-zfrac);
80  index[0] = xint+1; index[1] = yint; index[2] = zint;
81  result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] +
82  m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] +
83  m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight;
84 
85  weight = (1-xfrac)*(yfrac)*(1-zfrac);
86  index[0] = xint; index[1] = yint+1; index[2] = zint;
87  result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] +
88  m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] +
89  m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight;
90 
91  weight = (1-xfrac)*(1-yfrac)*(zfrac);
92  index[0] = xint; index[1] = yint; index[2] = zint+1;
93  result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] +
94  m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] +
95  m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight;
96 
97  weight = (xfrac)*(yfrac)*(1-zfrac);
98  index[0] = xint+1; index[1] = yint+1; index[2] = zint;
99  result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] +
100  m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] +
101  m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight;
102 
103  weight = (1-xfrac)*(yfrac)*(zfrac);
104  index[0] = xint; index[1] = yint+1; index[2] = zint+1;
105  result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] +
106  m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] +
107  m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight;
108 
109  weight = (xfrac)*(1-yfrac)*(zfrac);
110  index[0] = xint+1; index[1] = yint; index[2] = zint+1;
111  result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] +
112  m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] +
113  m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight;
114 
115  weight = (xfrac)*(yfrac)*(zfrac);
116  index[0] = xint+1; index[1] = yint+1; index[2] = zint+1;
117  result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] +
118  m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] +
119  m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight;
120  }
121  }
122  }
123  result /= (2*sampleSteps+1); // average result over taken samples
124  return result;
125 }
126 
127 float GibbsEnergyComputer::ComputeExternalEnergy(vnl_vector_fixed<float, 3> &R, vnl_vector_fixed<float, 3> &N, Particle *dp)
128 {
129  if (SpatProb(R) == 0) // check if position is inside mask
130  return itk::NumericTraits<float>::NonpositiveMin();
131 
132  float odfVal = EvaluateOdf(R, N); // evaluate ODF in given direction
133 
134  float modelVal = 0;
135  m_ParticleGrid->ComputeNeighbors(R); // retrieve neighbouring particles from particle grid
136  Particle* neighbour = m_ParticleGrid->GetNextNeighbor();
137  while (neighbour!=nullptr) // iterate over nieghbouring particles
138  {
139  if (dp != neighbour) // don't evaluate against itself
140  {
141  // see Reisert et al. "Global Reconstruction of Neuronal Fibers", MICCAI 2009
142  float dot = fabs(dot_product(N,neighbour->GetDir()));
143  float bw = mbesseli0(dot);
144  float dpos = (neighbour->GetPos()-R).squared_magnitude();
145  float w = mexp(dpos*gamma_s);
146  modelVal += w*(bw+m_ParticleChemicalPotential);
147  w = mexp(dpos*gamma_reg_s);
148  }
149  neighbour = m_ParticleGrid->GetNextNeighbor();
150  }
151 
152  float energy = 2*(odfVal/m_ParticleWeight-modelVal) - (mbesseli0(1.0)+m_ParticleChemicalPotential);
153  return energy*m_ExtStrength;
154 }
155 
157 {
158  float energy = 0;
159 
160  if (dp->pID != -1) // has predecessor
161  energy += ComputeInternalEnergyConnection(dp,+1);
162  if (dp->mID != -1) // has successor
163  energy += ComputeInternalEnergyConnection(dp,-1);
164 
165  return energy;
166 }
167 
169 {
170  Particle *p2 = nullptr;
171  int ep2 = 0;
172 
173  if (ep1 == 1)
174  p2 = m_ParticleGrid->GetParticle(p1->pID); // get predecessor
175  else
176  p2 = m_ParticleGrid->GetParticle(p1->mID); // get successor
177 
178  // check in which direction the connected particle is pointing
179  if (p2->mID == p1->ID)
180  ep2 = -1;
181  else if (p2->pID == p1->ID)
182  ep2 = 1;
183  else
184  std::cout << "EnergyComputer: Connections are inconsistent!" << std::endl;
185 
186  return ComputeInternalEnergyConnection(p1,ep1,p2,ep2);
187 }
188 
190 {
191  // see Reisert et al. "Global Reconstruction of Neuronal Fibers", MICCAI 2009
192  if ((dot_product(p1->GetDir(),p2->GetDir()))*ep1*ep2 > -m_CurvatureThreshold) // angle between particles is too sharp
193  return itk::NumericTraits<float>::NonpositiveMin();
194 
195  // calculate the endpoints of the two particles
196  vnl_vector_fixed<float, 3> endPoint1 = p1->GetPos() + (p1->GetDir() * (m_ParticleLength * ep1));
197  vnl_vector_fixed<float, 3> endPoint2 = p2->GetPos() + (p2->GetDir() * (m_ParticleLength * ep2));
198 
199  // check if endpoints are too far apart to connect
200  if ((endPoint1-endPoint2).squared_magnitude() > m_SquaredParticleLength)
201  return itk::NumericTraits<float>::NonpositiveMin();
202 
203  // calculate center point of the two particles
204  vnl_vector_fixed<float, 3> R = (p2->GetPos() + p1->GetPos()); R *= 0.5;
205 
206  // they are not allowed to connect if the mask image does not allow it
207  if (SpatProb(R) == 0)
208  return itk::NumericTraits<float>::NonpositiveMin();
209 
210  // get distances of endpoints to center point
211  float norm1 = (endPoint1-R).squared_magnitude();
212  float norm2 = (endPoint2-R).squared_magnitude();
213 
214  // calculate actual internal energy
215  float energy = (m_ConnectionPotential-norm1-norm2)*m_IntStrength;
216  return energy;
217 }
vnl_vector_fixed< float, 3 > interpw
A particle is the basic element of the Gibbs fiber tractography method.
Definition: mitkParticle.h:30
vnl_vector_fixed< float, 3 > & GetDir()
Definition: mitkParticle.h:56
vnl_vector_fixed< float, 3 > m_Spacing
float EvaluateOdf(vnl_vector_fixed< float, 3 > &pos, vnl_vector_fixed< float, 3 > dir)
void ComputeNeighbors(vnl_vector_fixed< float, 3 > &R)
Contains and manages particles.
Calculates internal and external energy of the new particle configuration proposal.
vnl_matrix_fixed< float, 3, 3 > m_RotationMatrix
DataCollection - Class to facilitate loading/accessing structured data.
SphereInterpolator * m_SphereInterpolator
vnl_vector_fixed< int, 3 > idx
Lookuptable based trilinear interpolation of spherically arranged scalar values.
itk::Image< float, 3 > ItkFloatImageType
vnl_vector_fixed< int, 3 > m_Size
vnl_vector_fixed< float, 3 > & GetPos()
Definition: mitkParticle.h:51
Particle * GetParticle(int ID)
float mexp(float x)
float mbesseli0(float x)
void getInterpolation(const vnl_vector_fixed< float, 3 > &N)
float ComputeExternalEnergy(vnl_vector_fixed< float, 3 > &R, vnl_vector_fixed< float, 3 > &N, Particle *dp) override
ParticleGrid * m_ParticleGrid
GibbsEnergyComputer(ItkQBallImgType *qballImage, ItkFloatImageType *mask, ParticleGrid *particleGrid, SphereInterpolator *interpolator, ItkRandGenType *randGen)
float ComputeInternalEnergyConnection(Particle *p1, int ep1) override
itk::Image< OdfVectorType, 3 > ItkQBallImgType
bool m_UseTrilinearInterpolation
itk::Statistics::MersenneTwisterRandomVariateGenerator ItkRandGenType
Particle * GetNextNeighbor()
float m_ParticleChemicalPotential
float ComputeInternalEnergy(Particle *dp) override
float SpatProb(vnl_vector_fixed< float, 3 > pos)