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
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.