Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
itkDiffusionKurtosisReconstructionImageFilter.h
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 
17 #ifndef DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_H
18 #define DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_H
19 
20 #include "itkImageToImageFilter.h"
21 #include "itkVectorImage.h"
22 
24 
25 // vnl includes
26 #include <vnl/algo/vnl_levenberg_marquardt.h>
27 #include <vnl/vnl_least_squares_function.h>
28 
29 namespace itk
30 {
31 
32  // Fitting routines
33 
40  public vnl_least_squares_function
41  {
42  public:
44  kurtosis_fit_lsq_function( unsigned int num_params, unsigned int num_measurements, UseGradient g=no_gradient)
45  : vnl_least_squares_function( num_params, num_measurements, g),
46  m_use_bounds(false),
47  m_use_logscale(false),
48  m_skip_fit(false)
49  {}
50 
52  kurtosis_fit_lsq_function( unsigned int number_measurements)
53  : kurtosis_fit_lsq_function( 2, number_measurements, no_gradient )
54  {}
55 
56 
58  void initialize( vnl_vector< double > const& _meas, vnl_vector< double> const& _bvals )
59  {
60  meas = _meas;
61  if( m_use_logscale )
62  {
63  for( unsigned int i=0; i< meas.size(); ++i)
64  {
65  // would produce NaN values, skip the fit
66  // using the virtual function from the superclass (sets a boolean flag)
67  if( meas[i] < vnl_math::eps )
68  {
69  m_skip_fit = true;
70  throw_failure();
71 
72  continue;
73  }
74 
75  meas[i] = log( meas[i] );
76 
77  }
78  }
79 
80  bvalues = _bvals;
81  }
82 
83 
85  void use_bounds()
86  {
87  m_use_bounds = true;
88 
89  // initialize bounds
90  double upper_bounds[2] = {4e-3, 4 };
91  kurtosis_upper_bounds = vnl_vector<double>(2, 2, upper_bounds);
92  kurtosis_lower_bounds = vnl_vector<double>(2, 0);
93  }
94 
95  void set_fit_logscale( bool flag )
96  {
97  this->m_use_logscale = flag;
98  }
99 
100  void set_K_bounds( const vnl_vector_fixed<double, 2> k_bounds )
101  {
102  // init
103  this->use_bounds();
104 
105  // override K bounds
106  kurtosis_lower_bounds[1] = k_bounds[0];
107  kurtosis_upper_bounds[1] = k_bounds[1];
108  }
109 
110  virtual void f(const vnl_vector<double> &x, vnl_vector<double> &fx)
111  {
112  for ( unsigned int s=0; s < fx.size(); s++ )
113  {
114  const double factor = ( meas[s] - M(x, s) );
115  fx[s] = factor * factor + penalty_term(x);
116  }
117 
118  MITK_DEBUG("Fit.x_and_f") << x << " | " << fx;
119  }
120 
121  protected:
122 
124  double Diff( double x1, double x2, double b)
125  {
126  const double quotient = -1. * b * x1 + b*b * x1 * x1 * x2 / 6;
127 
128  if( m_use_logscale )
129  return quotient;
130  else
131  return exp(quotient);
132  }
133 
135  virtual double M( vnl_vector<double> const& x, unsigned int idx )
136  {
137  const double bvalue = bvalues[idx];
138 
139  double result = Diff( x[0], x[1], bvalue);
140 
141  if( m_use_logscale )
142  return meas[0] + result;
143  else
144  return meas[0] * result ;
145  }
146 
148  virtual double penalty_term( vnl_vector<double> const& x)
149  {
150  double penalty = 0;
151 
152  // skip when turned off
153  if( !m_use_bounds )
154  return penalty;
155 
156  // we have bounds for D and K only (the first two params )
157  for( unsigned int i=0; i< 2; i++)
158  {
159  // 5% penalty boundary
160  // use exponential function to scale the penalty (max when x[i] == bounds )
161  double penalty_boundary = 0.02 * (kurtosis_upper_bounds[i] - kurtosis_lower_bounds[i]);
162 
163  if( x[i] < kurtosis_lower_bounds[i] + penalty_boundary )
164  {
165  penalty += 1e6 * exp( -1 * ( x[i] - kurtosis_lower_bounds[i]) / penalty_boundary );
166  }
167  else if ( x[i] > kurtosis_upper_bounds[i] - penalty_boundary )
168  {
169  penalty += 1e6 * exp( -1 * ( kurtosis_upper_bounds[i] - x[i]) / penalty_boundary );
170  }
171  }
172 
173  MITK_DEBUG("Fit.Orig.Penalty") << x << " || penalty: " << penalty;
174 
175  return penalty;
176  }
177 
179 
181 
183 
184  vnl_vector<double> kurtosis_upper_bounds;
185  vnl_vector<double> kurtosis_lower_bounds;
186 
187  vnl_vector<double> meas;
188  vnl_vector<double> bvalues;
189 
190  };
191 
196  {
197  public:
199  kurtosis_fit_omit_unweighted( unsigned int number_measurements)
200  : kurtosis_fit_lsq_function( 3, number_measurements, no_gradient )
201  {}
202 
203  protected:
204  virtual double M(const vnl_vector<double> &x, unsigned int idx) override
205  {
206  const double bvalue = bvalues[idx];
207 
208  double result = Diff( x[0], x[1], bvalue);
209 
210  if( m_use_logscale )
211  return log( x[2] ) + result;
212  else
213  return x[2] * result ;
214  }
215  };
216 
217  enum FitScale
218  {
219  STRAIGHT = 0,
221  };
222 
224  {
226  : omit_bzero(false),use_K_limits(false),exclude_high_b(false) {}
227 
230 
232  vnl_vector_fixed<double, 2> K_limits;
233 
236  };
237 
245 template< class TInputPixelType, class TOutputPixelType >
247  public ImageToImageFilter< VectorImage< TInputPixelType, 3>, Image<TOutputPixelType, 3> >
248 {
249 public:
250 
257  {
259  : m_f(1), m_BzeroFit(1), m_D(0.001), m_K(0) {}
260 
261  // input data structures
262  //vnl_vector<double> filtered_measurements;
263  vnl_vector<double> bvalues;
264  vnl_vector<double> measurements;
265 
266  vnl_vector<double> fit_bvalues;
267  vnl_vector<double> fit_measurements;
268  vnl_vector<unsigned int> weighted_image_indices;
269 
271 
272  // variables holding the fitted values
273  double m_f;
274  double m_BzeroFit;
275  double m_D;
276  double m_K;
277  };
278 
279  //-- class typedefs
283  typedef ImageToImageFilter< VectorImage< TInputPixelType, 3>,
284  Image< TOutputPixelType,3 > > Superclass;
285 
287  itkFactorylessNewMacro(Self)
288  itkCloneMacro(Self)
289 
291  itkTypeMacro(DiffusionKurtosisReconstructionImageFilter, ImageToImageFilter)
292 
293  typedef TOutputPixelType OutputPixelType;
294  typedef TInputPixelType InputPixelType;
295 
296  typedef typename Superclass::InputImageType InputImageType;
297  typedef Image< OutputPixelType, 3 > OutputImageType;
298 
299  typedef itk::Image< short , 3> MaskImageType;
300 
301  typedef typename Superclass::OutputImageRegionType OutputImageRegionType;
302 
303 
305  typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType
307 
308  // vector image typedefs for regularized fit
309  typedef itk::VectorImage<float,3> VectorImageType;
310  typedef itk::Image<itk::Vector<double, 3>, 3> InitialFitImageType;
311 
312  //-- input (Set) methods
317  void SetInitialSolution(const vnl_vector<double>& x0 );
318 
320  void SetOmitUnweightedValue( bool flag)
321  { this->m_OmitBZero = flag; }
322 
325  KurtosisSnapshot GetSnapshot( const itk::VariableLengthVector< TInputPixelType > &input, vnl_vector<double> bvalues, KurtosisFitConfiguration kf_conf);
326 
330 
336  KurtosisSnapshot GetCurrentSnapshot(bool omit_bzero);
337 
339  void SetReferenceBValue( double bvalue )
340  { this->m_ReferenceBValue = bvalue; }
341 
344 
347  {
348  m_MapOutputRegion = region;
349  this->m_ApplyPriorSmoothing = true;
350  }
351 
353 
355  void SetSmoothingSigma( double sigma )
356  {
357  this->m_SmoothingSigma = sigma;
358  this->m_ApplyPriorSmoothing = true;
359  }
360 
363  {
364  this->m_ApplyPriorSmoothing = flag;
365  }
366 
368  void SetBoundariesForKurtosis( double lower, double upper )
369  {
370  m_UseKBounds = true;
371 
372  m_KurtosisBounds[0] = lower; m_KurtosisBounds[1] = upper;
373  }
374 
376  void SetMaximalBValueUsedForFitting( double max_bvalue )
377  {
378  m_MaxFitBValue = max_bvalue;
379  }
380 
386  void SetFittingScale( FitScale scale )
387  {
388  m_ScaleForFitting = scale;
389  }
390 
391 protected:
394 
395  void GenerateOutputInformation() override;
396 
397  void AfterThreadedGenerateData() override;
398 
399  void BeforeThreadedGenerateData() override;
400 
401  void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId) override;
402 
404 
405  vnl_vector<double> m_BValues;
406 
407  vnl_vector<double> m_InitialPosition;
408 
410 
412 
414 
416 
419 
421  vnl_vector_fixed<double, 2> m_KurtosisBounds;
423 
425 
426 private:
427 
428 
429 };
430 
431 } //end namespace itk
432 
433 #ifndef ITK_MANUAL_INSTANTIATION
435 #endif
436 
437 
438 #endif // DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_H
A fitting function handling the unweighted signal b_0 as a fitted parameter.
itk::SmartPointer< Self > Pointer
#define MITK_DEBUG
Definition: mitkLogMacros.h:26
DataCollection - Class to facilitate loading/accessing structured data.
virtual double M(vnl_vector< double > const &x, unsigned int idx)
void initialize(vnl_vector< double > const &_meas, vnl_vector< double > const &_bvals)
virtual double penalty_term(vnl_vector< double > const &x)
kurtosis_fit_lsq_function(unsigned int num_params, unsigned int num_measurements, UseGradient g=no_gradient)
class ITK_EXPORT Image
mitk::DiffusionPropertyHelper::GradientDirectionsContainerType GradientDirectionContainerType
virtual void f(const vnl_vector< double > &x, vnl_vector< double > &fx)
Struct describing a result (and the data) of a Kurtosis model fit.
ImageToImageFilter< VectorImage< TInputPixelType, 3 >, Image< TOutputPixelType, 3 > > Superclass
KurtosisSnapshot GetCurrentSnapshot(bool omit_bzero)
virtual double M(const vnl_vector< double > &x, unsigned int idx) override
KurtosisSnapshot GetSnapshot(const itk::VariableLengthVector< TInputPixelType > &input, vnl_vector< double > bvalues, KurtosisFitConfiguration kf_conf)
void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId) override
void set_K_bounds(const vnl_vector_fixed< double, 2 > k_bounds)
void SetGradientDirections(GradientDirectionContainerType::Pointer gradients)
MITKCORE_EXPORT const ScalarType eps
This filter provides the fit of the kurtosis (non-IVIM) signal to the data.