Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
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)