Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkRawShModel.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 #include <vnl/vnl_cross.h>
17 #include <vnl/vnl_quaternion.h>
18 #include <mitkRawShModel.h>
19 #include <boost/math/special_functions.hpp>
21 #include <mitkFiberfoxParameters.h>
22 #include <itkDiffusionTensor3DReconstructionImageFilter.h>
23 #include <itkAdcImageFilter.h>
26 #include <mitkImageCast.h>
27 #include <mitkProperties.h>
28 
29 using namespace mitk;
30 using namespace boost::math;
31 
32 template< class ScalarType >
34  : m_ShOrder(0)
35  , m_ModelIndex(-1)
36  , m_MaxNumKernels(1000)
37 {
39  this->m_RandGen->SetSeed();
40  m_AdcRange.first = 0;
41  m_AdcRange.second = 0.004;
42  m_FaRange.first = 0;
43  m_FaRange.second = 1;
44 }
45 
46 template< class ScalarType >
48 {
49 
50 }
51 
52 template< class ScalarType >
54 {
55  m_ShCoefficients.clear();
56  m_PrototypeMaxDirection.clear();
57  m_B0Signal.clear();
58 }
59 
60 template< class ScalarType >
62 {
63  m_ModelIndex = this->m_RandGen->GetIntegerVariate(m_B0Signal.size()-1);
64 }
65 
66 template< class ScalarType >
68 {
69  return m_B0Signal.size();
70 }
71 
72 template< class ScalarType >
74 {
75  if (diffImg.IsNull())
76  return false;
77 
78  typedef itk::VectorImage<short, 3> ITKDiffusionImageType;
80  mitk::CastToItkImage(diffImg, itkVectorImagePointer);
81 
82  const int shOrder = 2;
83 
84  if (tensorImage.IsNull())
85  {
86  typedef itk::DiffusionTensor3DReconstructionImageFilter< short, short, double > TensorReconstructionImageFilterType;
87 
89  filter->SetGradientImage( static_cast<mitk::GradientDirectionsProperty*>( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(), itkVectorImagePointer );
90  filter->SetBValue(static_cast<mitk::FloatProperty*>( diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue());
91  filter->Update();
92  tensorImage = filter->GetOutput();
93  }
94 
95  const int NumCoeffs = (shOrder*shOrder + shOrder + 2)/2 + shOrder;
96  if (itkFeatureImage.IsNull())
97  {
99  qballfilter->SetGradientImage( static_cast<mitk::GradientDirectionsProperty*>( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(), itkVectorImagePointer );
100  qballfilter->SetBValue(static_cast<mitk::FloatProperty*>( diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue());
101  qballfilter->SetLambda(0.006);
102  qballfilter->SetNormalizationMethod(QballFilterType::QBAR_RAW_SIGNAL);
103  qballfilter->Update();
104  itkFeatureImage = qballfilter->GetCoefficientImage();
105  }
106 
107  if (adcImage.IsNull())
108  {
110  adcFilter->SetInput(itkVectorImagePointer);
111  adcFilter->SetGradientDirections(static_cast<mitk::GradientDirectionsProperty*>( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer());
112  adcFilter->SetB_value(static_cast<mitk::FloatProperty*>( diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue());
113  adcFilter->Update();
114  adcImage = adcFilter->GetOutput();
115  }
116 
117  int b0Index;
118  for (unsigned int i=0; i<static_cast<mitk::GradientDirectionsProperty*>( diffImg->GetProperty(mitk::DiffusionPropertyHelper::ORIGINALGRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer()->Size(); i++)
119  if ( static_cast<mitk::GradientDirectionsProperty*>( diffImg->GetProperty(mitk::DiffusionPropertyHelper::ORIGINALGRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer()->GetElement(i).magnitude()<0.001 )
120  {
121  b0Index = i;
122  break;
123  }
124 
125  double max = 0;
126  {
127  itk::ImageRegionIterator< itk::VectorImage< short, 3 > > it(itkVectorImagePointer, itkVectorImagePointer->GetLargestPossibleRegion());
128  while(!it.IsAtEnd())
129  {
130  if (maskImage.IsNotNull() && maskImage->GetPixel(it.GetIndex())<=0)
131  {
132  ++it;
133  continue;
134  }
135  if (it.Get()[b0Index]>max)
136  max = it.Get()[b0Index];
137  ++it;
138  }
139  }
140 
141  MITK_INFO << "Sampling signal kernels.";
142  unsigned int count = 0;
143  itk::ImageRegionIterator< itk::Image< itk::DiffusionTensor3D< double >, 3 > > it(tensorImage, tensorImage->GetLargestPossibleRegion());
144  while(!it.IsAtEnd())
145  {
146  bool skipPixel = false;
147  if (maskImage.IsNotNull() && maskImage->GetPixel(it.GetIndex())<=0)
148  {
149  ++it;
150  continue;
151  }
152  for (unsigned int i=0; i<static_cast<mitk::GradientDirectionsProperty*>( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer()->Size(); i++)
153  {
154  if (itkVectorImagePointer->GetPixel(it.GetIndex())[i]!=itkVectorImagePointer->GetPixel(it.GetIndex())[i] || itkVectorImagePointer->GetPixel(it.GetIndex())[i]<=0 || itkVectorImagePointer->GetPixel(it.GetIndex())[i]>itkVectorImagePointer->GetPixel(it.GetIndex())[b0Index])
155  {
156  skipPixel = true;
157  break;
158  }
159  }
160  if (skipPixel)
161  {
162  ++it;
163  continue;
164  }
165 
166  typedef itk::DiffusionTensor3D<double> TensorType;
167  TensorType::EigenValuesArrayType eigenvalues;
168  TensorType::EigenVectorsMatrixType eigenvectors;
169  TensorType tensor = it.Get();
170  double FA = tensor.GetFractionalAnisotropy();
171  double ADC = adcImage->GetPixel(it.GetIndex());
172  QballFilterType::CoefficientImageType::PixelType itkv = itkFeatureImage->GetPixel(it.GetIndex());
173  vnl_vector_fixed< double, NumCoeffs > coeffs;
174  for (unsigned int c=0; c<itkv.Size(); c++)
175  coeffs[c] = itkv[c]/max;
176 
177  if ( this->GetMaxNumKernels()>this->GetNumberOfKernels() && FA>m_FaRange.first && FA<m_FaRange.second && ADC>m_AdcRange.first && ADC<m_AdcRange.second)
178  {
179  if (this->SetShCoefficients( coeffs, (double)itkVectorImagePointer->GetPixel(it.GetIndex())[b0Index]/max ))
180  {
181  tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors);
182  itk::Vector<double,3> dir;
183  dir[0] = eigenvectors(2, 0);
184  dir[1] = eigenvectors(2, 1);
185  dir[2] = eigenvectors(2, 2);
186  m_PrototypeMaxDirection.push_back(dir);
187  count++;
188  MITK_INFO << "KERNEL: " << it.GetIndex() << " (" << count << ")";
189  }
190  }
191  ++it;
192  }
193 
194  if (m_ShCoefficients.size()>0)
195  return true;
196  return false;
197 }
198 
199 // convert cartesian to spherical coordinates
200 template< class ScalarType >
202 {
203  m_SphCoords.set_size(gradients.size(), 2);
204  m_SphCoords.fill(0.0);
205 
206  for (unsigned int i=0; i<gradients.size(); i++)
207  {
208  GradientType g = gradients[i];
209  if( g.GetNorm() > 0.0001 )
210  {
211  gradients[i].Normalize();
212  m_SphCoords(i,0) = acos(gradients[i][2]); // theta
213  m_SphCoords(i,1) = atan2(gradients[i][1], gradients[i][0]); // phi
214  }
215  }
216 }
217 
218 template< class ScalarType >
220 {
221  this->m_FiberDirection = fiberDirection;
222  this->m_FiberDirection.Normalize();
223 
224  RandomModel();
225  GradientType axis = itk::CrossProduct(this->m_FiberDirection, m_PrototypeMaxDirection.at(m_ModelIndex));
226  axis.Normalize();
227 
228  vnl_quaternion<double> rotation(axis.GetVnlVector(), acos(dot_product(this->m_FiberDirection.GetVnlVector(), m_PrototypeMaxDirection.at(m_ModelIndex).GetVnlVector())));
229  rotation.normalize();
230 
232  for (unsigned int i=0; i<this->m_GradientList.size(); i++)
233  {
234  GradientType dir = this->m_GradientList.at(i);
235  if( dir.GetNorm() > 0.0001 )
236  {
237  dir.Normalize();
238  vnl_vector_fixed< double, 3 > vnlDir = rotation.rotate(dir.GetVnlVector());
239  dir[0] = vnlDir[0]; dir[1] = vnlDir[1]; dir[2] = vnlDir[2];
240  dir.Normalize();
241  }
242  gradients.push_back(dir);
243  }
244 
245  Cart2Sph( gradients );
246 }
247 
248 template< class ScalarType >
249 bool RawShModel< ScalarType >::SetShCoefficients(vnl_vector< double > shCoefficients, double b0 )
250 {
251  m_ShOrder = 2;
252  while ( (m_ShOrder*m_ShOrder + m_ShOrder + 2)/2 + m_ShOrder <= shCoefficients.size() )
253  m_ShOrder += 2;
254  m_ShOrder -= 2;
255 
256  m_ModelIndex = m_B0Signal.size();
257  m_B0Signal.push_back(b0);
258  m_ShCoefficients.push_back(shCoefficients);
259 
260  // itk::OrientationDistributionFunction<double, 10000> odf;
261  // GradientListType gradients;
262  // for (unsigned int i=0; i<odf.GetNumberOfComponents(); i++)
263  // {
264  // GradientType dir; dir[0]=odf.GetDirection(i)[0]; dir[1]=odf.GetDirection(i)[1]; dir[2]=odf.GetDirection(i)[2];
265  // dir.Normalize();
266  // gradients.push_back(dir);
267  // }
268  // Cart2Sph( this->m_GradientList );
269  // PixelType signal = SimulateMeasurement();
270 
271  // int minDirIdx = 0;
272  // double min = itk::NumericTraits<double>::max();
273  // for (unsigned int i=0; i<signal.GetSize(); i++)
274  // {
275  // if (signal[i]>b0 || signal[i]<0)
276  // {
277  // MITK_INFO << "Corrupted signal value detected. Kernel rejected.";
278  // m_B0Signal.pop_back();
279  // m_ShCoefficients.pop_back();
280  // return false;
281  // }
282  // if (signal[i]<min)
283  // {
284  // min = signal[i];
285  // minDirIdx = i;
286  // }
287  // }
288  // GradientType maxDir = this->m_GradientList.at(minDirIdx);
289  // maxDir.Normalize();
290  // m_PrototypeMaxDirection.push_back(maxDir);
291 
292  Cart2Sph( this->m_GradientList );
293  m_ModelIndex = -1;
294 
295  return true;
296 }
297 
298 template< class ScalarType >
300 {
301  ScalarType signal = 0;
302 
303  if (m_ModelIndex==-1)
304  RandomModel();
305 
306  if (dir>=this->m_GradientList.size())
307  return signal;
308 
309  int j, m; double mag, plm;
310 
311  if (this->m_GradientList[dir].GetNorm()>0.001)
312  {
313  j=0;
314  for (int l=0; l<=m_ShOrder; l=l+2)
315  for (m=-l; m<=l; m++)
316  {
317  plm = legendre_p<double>(l,abs(m),cos(m_SphCoords(dir,0)));
318  mag = sqrt((double)(2*l+1)/(4.0*M_PI)*factorial<double>(l-abs(m))/factorial<double>(l+abs(m)))*plm;
319  double basis;
320 
321  if (m<0)
322  basis = sqrt(2.0)*mag*cos(fabs((double)m)*m_SphCoords(dir,1));
323  else if (m==0)
324  basis = mag;
325  else
326  basis = pow(-1.0, m)*sqrt(2.0)*mag*sin(m*m_SphCoords(dir,1));
327 
328  signal += m_ShCoefficients.at(m_ModelIndex)[j]*basis;
329  j++;
330  }
331  }
332  else
333  signal = m_B0Signal.at(m_ModelIndex);
334 
335  m_ModelIndex = -1;
336 
337  return signal;
338 }
339 
340 template< class ScalarType >
342 {
343  if (m_ModelIndex==-1)
344  RandomModel();
345 
346  PixelType signal;
347  signal.SetSize(this->m_GradientList.size());
348 
349  int M = this->m_GradientList.size();
350  int j, m; double mag, plm;
351 
352  vnl_matrix< double > shBasis;
353  shBasis.set_size(M, m_ShCoefficients.at(m_ModelIndex).size());
354  shBasis.fill(0.0);
355 
356  for (int p=0; p<M; p++)
357  {
358  if (this->m_GradientList[p].GetNorm()>0.001)
359  {
360  j=0;
361  for (int l=0; l<=m_ShOrder; l=l+2)
362  for (m=-l; m<=l; m++)
363  {
364  plm = legendre_p<double>(l,abs(m),cos(m_SphCoords(p,0)));
365  mag = sqrt((double)(2*l+1)/(4.0*M_PI)*factorial<double>(l-abs(m))/factorial<double>(l+abs(m)))*plm;
366 
367  if (m<0)
368  shBasis(p,j) = sqrt(2.0)*mag*cos(fabs((double)m)*m_SphCoords(p,1));
369  else if (m==0)
370  shBasis(p,j) = mag;
371  else
372  shBasis(p,j) = pow(-1.0, m)*sqrt(2.0)*mag*sin(m*m_SphCoords(p,1));
373 
374  j++;
375  }
376 
377 
378  double val = 0;
379  for (unsigned int cidx=0; cidx<m_ShCoefficients.at(m_ModelIndex).size(); cidx++)
380  val += m_ShCoefficients.at(m_ModelIndex)[cidx]*shBasis(p,cidx);
381  signal[p] = val;
382  }
383  else
384  signal[p] = m_B0Signal.at(m_ModelIndex);
385  }
386 
387  m_ModelIndex = -1;
388 
389  return signal;
390 }
bool SetShCoefficients(vnl_vector< double > shCoefficients, double b0)
static const std::string REFERENCEBVALUEPROPERTYNAME
void Cart2Sph(GradientListType gradients)
itk::SmartPointer< Self > Pointer
PixelType SimulateMeasurement()
#define MITK_INFO
Definition: mitkLogMacros.h:22
bool SampleKernels(Image::Pointer diffImg, ItkUcharImageType::Pointer maskImage, TensorImageType::Pointer tensorImage=NULL, QballFilterType::CoefficientImageType::Pointer coeffImage=NULL, ItkDoubleImageType::Pointer adcImage=NULL)
double ScalarType
void SetFiberDirection(GradientType fiberDirection)
DataCollection - Class to facilitate loading/accessing structured data.
ItkRandGenType::Pointer m_RandGen
Random number generator.
unsigned int GetNumberOfKernels()
static Matrix3D rotation
std::vector< GradientType > GradientListType
itk::Vector< double, 3 > GradientType
static T max(T x, T y)
Definition: svm.cpp:70
std::pair< double, double > m_AdcRange
void MITKCORE_EXPORT CastToItkImage(const mitk::Image *mitkImage, itk::SmartPointer< ItkOutputImageType > &itkOutputImage)
Cast an mitk::Image to an itk::Image with a specific type.
static Pointer New()
std::pair< double, double > m_FaRange
unsigned short PixelType
static const std::string GRADIENTCONTAINERPROPERTYNAME
static const std::string ORIGINALGRADIENTCONTAINERPROPERTYNAME
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.