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
itkTractsToDWIImageFilter.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 
18 #include <boost/progress.hpp>
19 #include <vtkSmartPointer.h>
20 #include <vtkPolyData.h>
21 #include <vtkCellArray.h>
22 #include <vtkPoints.h>
23 #include <vtkPolyLine.h>
24 #include <itkImageRegionIteratorWithIndex.h>
25 #include <itkResampleImageFilter.h>
26 #include <itkNearestNeighborInterpolateImageFunction.h>
27 #include <itkBSplineInterpolateImageFunction.h>
28 #include <itkCastImageFilter.h>
29 #include <itkImageFileWriter.h>
30 #include <itkRescaleIntensityImageFilter.h>
31 #include <itkWindowedSincInterpolateImageFunction.h>
33 #include <itkKspaceImageFilter.h>
34 #include <itkDftImageFilter.h>
35 #include <itkAddImageFilter.h>
36 #include <itkConstantPadImageFilter.h>
37 #include <itkCropImageFilter.h>
38 #include <mitkAstroStickModel.h>
39 #include <vtkTransform.h>
40 #include <iostream>
41 #include <fstream>
42 #include <exception>
43 #include <itkImageDuplicator.h>
44 #include <itksys/SystemTools.hxx>
45 #include <mitkIOUtil.h>
46 #include <itkDiffusionTensor3DReconstructionImageFilter.h>
47 #include <itkDiffusionTensor3D.h>
49 #include <boost/lexical_cast.hpp>
51 #include <itkInvertIntensityImageFilter.h>
52 #include <itkShiftScaleImageFilter.h>
53 #include <itkExtractImageFilter.h>
55 #include <boost/algorithm/string/replace.hpp>
56 
57 namespace itk
58 {
59 
60  template< class PixelType >
62  : m_FiberBundle(NULL)
63  , m_StatusText("")
64  , m_UseConstantRandSeed(false)
65  , m_RandGen(itk::Statistics::MersenneTwisterRandomVariateGenerator::New())
66  {
67  m_RandGen->SetSeed();
68  }
69 
70  template< class PixelType >
72  {
73 
74  }
75 
76  template< class PixelType >
78  SimulateKspaceAcquisition( std::vector< DoubleDwiType::Pointer >& images )
79  {
80  int numFiberCompartments = m_Parameters.m_FiberModelList.size();
81  // create slice object
82  ImageRegion<2> sliceRegion;
83  sliceRegion.SetSize(0, m_WorkingImageRegion.GetSize()[0]);
84  sliceRegion.SetSize(1, m_WorkingImageRegion.GetSize()[1]);
85  Vector< double, 2 > sliceSpacing;
86  sliceSpacing[0] = m_WorkingSpacing[0];
87  sliceSpacing[1] = m_WorkingSpacing[1];
88 
89  DoubleDwiType::PixelType nullPix; nullPix.SetSize(images.at(0)->GetVectorLength()); nullPix.Fill(0.0);
90  auto magnitudeDwiImage = DoubleDwiType::New();
91  magnitudeDwiImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing );
92  magnitudeDwiImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin );
93  magnitudeDwiImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection );
94  magnitudeDwiImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion );
95  magnitudeDwiImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion );
96  magnitudeDwiImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion );
97  magnitudeDwiImage->SetVectorLength( images.at(0)->GetVectorLength() );
98  magnitudeDwiImage->Allocate();
99  magnitudeDwiImage->FillBuffer(nullPix);
100 
101  m_PhaseImage = DoubleDwiType::New();
102  m_PhaseImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing );
103  m_PhaseImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin );
104  m_PhaseImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection );
105  m_PhaseImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion );
106  m_PhaseImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion );
107  m_PhaseImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion );
108  m_PhaseImage->SetVectorLength( images.at(0)->GetVectorLength() );
109  m_PhaseImage->Allocate();
110  m_PhaseImage->FillBuffer(nullPix);
111 
112  m_KspaceImage = DoubleDwiType::New();
113  m_KspaceImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing );
114  m_KspaceImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin );
115  m_KspaceImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection );
116  m_KspaceImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion );
117  m_KspaceImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion );
118  m_KspaceImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion );
119  m_KspaceImage->SetVectorLength( m_Parameters.m_SignalGen.m_NumberOfCoils );
120  m_KspaceImage->Allocate();
121  m_KspaceImage->FillBuffer(nullPix);
122 
123  std::vector< unsigned int > spikeVolume;
124  for (unsigned int i=0; i<m_Parameters.m_SignalGen.m_Spikes; i++)
125  spikeVolume.push_back(m_RandGen->GetIntegerVariate()%(images.at(0)->GetVectorLength()));
126  std::sort (spikeVolume.begin(), spikeVolume.end());
127  std::reverse (spikeVolume.begin(), spikeVolume.end());
128 
129  // calculate coil positions
130  double a = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(0)*m_Parameters.m_SignalGen.m_ImageSpacing[0];
131  double b = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1)*m_Parameters.m_SignalGen.m_ImageSpacing[1];
132  double c = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(2)*m_Parameters.m_SignalGen.m_ImageSpacing[2];
133  double diagonal = sqrt(a*a+b*b)/1000; // image diagonal in m
134 
135  m_CoilPointset = mitk::PointSet::New();
136  std::vector< itk::Vector<double, 3> > coilPositions;
137  itk::Vector<double, 3> pos; pos.Fill(0.0); pos[1] = -diagonal/2;
138  itk::Vector<double, 3> center;
139  center[0] = a/2-m_Parameters.m_SignalGen.m_ImageSpacing[0]/2;
140  center[1] = b/2-m_Parameters.m_SignalGen.m_ImageSpacing[2]/2;
141  center[2] = c/2-m_Parameters.m_SignalGen.m_ImageSpacing[1]/2;
142  for (int c=0; c<m_Parameters.m_SignalGen.m_NumberOfCoils; c++)
143  {
144  coilPositions.push_back(pos);
145  m_CoilPointset->InsertPoint(c, pos*1000 + m_Parameters.m_SignalGen.m_ImageOrigin.GetVectorFromOrigin() + center );
146 
147  double rz = 360.0/m_Parameters.m_SignalGen.m_NumberOfCoils * M_PI/180;
148  vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity();
149  rotZ[0][0] = cos(rz);
150  rotZ[1][1] = rotZ[0][0];
151  rotZ[0][1] = -sin(rz);
152  rotZ[1][0] = -rotZ[0][1];
153 
154  pos.SetVnlVector(rotZ*pos.GetVnlVector());
155  }
156 
157  PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false);
158  PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false);
159  unsigned long lastTick = 0;
160 
161  boost::progress_display disp(images.at(0)->GetVectorLength()*images.at(0)->GetLargestPossibleRegion().GetSize(2));
162  for (unsigned int g=0; g<images.at(0)->GetVectorLength(); g++)
163  {
164  std::vector< unsigned int > spikeSlice;
165  while (!spikeVolume.empty() && spikeVolume.back()==g)
166  {
167  spikeSlice.push_back(m_RandGen->GetIntegerVariate()%images.at(0)->GetLargestPossibleRegion().GetSize(2));
168  spikeVolume.pop_back();
169  }
170  std::sort (spikeSlice.begin(), spikeSlice.end());
171  std::reverse (spikeSlice.begin(), spikeSlice.end());
172 
173  for (unsigned int z=0; z<images.at(0)->GetLargestPossibleRegion().GetSize(2); z++)
174  {
175  std::vector< SliceType::Pointer > compartmentSlices;
176  std::vector< double > t2Vector;
177  std::vector< double > t1Vector;
178 
179  for (unsigned int i=0; i<images.size(); i++)
180  {
181  DiffusionSignalModel<double>* signalModel;
182  if (i<numFiberCompartments)
183  signalModel = m_Parameters.m_FiberModelList.at(i);
184  else
185  signalModel = m_Parameters.m_NonFiberModelList.at(i-numFiberCompartments);
186 
187  auto slice = SliceType::New();
188  slice->SetLargestPossibleRegion( sliceRegion );
189  slice->SetBufferedRegion( sliceRegion );
190  slice->SetRequestedRegion( sliceRegion );
191  slice->SetSpacing(sliceSpacing);
192  slice->Allocate();
193  slice->FillBuffer(0.0);
194 
195  // extract slice from channel g
196  for (unsigned int y=0; y<images.at(0)->GetLargestPossibleRegion().GetSize(1); y++)
197  for (unsigned int x=0; x<images.at(0)->GetLargestPossibleRegion().GetSize(0); x++)
198  {
199  SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y;
200  DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z;
201 
202  slice->SetPixel(index2D, images.at(i)->GetPixel(index3D)[g]);
203  }
204 
205  compartmentSlices.push_back(slice);
206  t2Vector.push_back(signalModel->GetT2());
207  t1Vector.push_back(signalModel->GetT1());
208  }
209 
210  int numSpikes = 0;
211  while (!spikeSlice.empty() && spikeSlice.back()==z)
212  {
213  numSpikes++;
214  spikeSlice.pop_back();
215  }
216  int spikeCoil = m_RandGen->GetIntegerVariate()%m_Parameters.m_SignalGen.m_NumberOfCoils;
217 
218  if (this->GetAbortGenerateData())
219  return NULL;
220 
221 #pragma omp parallel for
222  for (int c=0; c<m_Parameters.m_SignalGen.m_NumberOfCoils; c++)
223  {
224  // create k-sapce (inverse fourier transform slices)
226  idft->SetCompartmentImages(compartmentSlices);
227  idft->SetT2(t2Vector);
228  idft->SetT1(t1Vector);
229  idft->SetUseConstantRandSeed(m_UseConstantRandSeed);
230  idft->SetParameters(&m_Parameters);
231  idft->SetZ((double)z-(double)( images.at(0)->GetLargestPossibleRegion().GetSize(2)
232  -images.at(0)->GetLargestPossibleRegion().GetSize(2)%2 ) / 2.0);
233  idft->SetZidx(z);
234  idft->SetCoilPosition(coilPositions.at(c));
235  idft->SetFiberBundle(m_FiberBundleWorkingCopy);
236  idft->SetTranslation(m_Translations.at(g));
237  idft->SetRotation(m_Rotations.at(g));
238  idft->SetDiffusionGradientDirection(m_Parameters.m_SignalGen.GetGradientDirection(g));
239  if (c==spikeCoil)
240  idft->SetSpikesPerSlice(numSpikes);
241  idft->Update();
242 
243 #pragma omp critical
244  if (c==spikeCoil && numSpikes>0)
245  {
246  m_SpikeLog += "Volume " + boost::lexical_cast<std::string>(g) + " Coil " + boost::lexical_cast<std::string>(c) + "\n";
247  m_SpikeLog += idft->GetSpikeLog();
248  }
249 
251  fSlice = idft->GetOutput();
252 
253  // fourier transform slice
254  ComplexSliceType::Pointer newSlice;
256  dft->SetInput(fSlice);
257  dft->SetParameters(m_Parameters);
258  dft->Update();
259  newSlice = dft->GetOutput();
260 
261  // put slice back into channel g
262  for (unsigned int y=0; y<fSlice->GetLargestPossibleRegion().GetSize(1); y++)
263  for (unsigned int x=0; x<fSlice->GetLargestPossibleRegion().GetSize(0); x++)
264  {
265  DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z;
266  ComplexSliceType::IndexType index2D; index2D[0]=x; index2D[1]=y;
267 
268  ComplexSliceType::PixelType cPix = newSlice->GetPixel(index2D);
269  double magn = sqrt(cPix.real()*cPix.real()+cPix.imag()*cPix.imag());
270  double phase = 0;
271  if (cPix.real()!=0)
272  phase = atan( cPix.imag()/cPix.real() );
273 
274 
275  DoubleDwiType::PixelType dwiPix = magnitudeDwiImage->GetPixel(index3D);
276  DoubleDwiType::PixelType phasePix = m_PhaseImage->GetPixel(index3D);
277 
278  if (m_Parameters.m_SignalGen.m_NumberOfCoils>1)
279  {
280  dwiPix[g] += magn*magn;
281  phasePix[g] += phase*phase;
282  }
283  else
284  {
285  dwiPix[g] = magn;
286  phasePix[g] = phase;
287  }
288 
289 #pragma omp critical
290  {
291  magnitudeDwiImage->SetPixel(index3D, dwiPix);
292  m_PhaseImage->SetPixel(index3D, phasePix);
293 
294  // k-space image
295  if (g==0)
296  {
297  DoubleDwiType::PixelType kspacePix = m_KspaceImage->GetPixel(index3D);
298  kspacePix[c] = idft->GetKSpaceImage()->GetPixel(index2D);
299  m_KspaceImage->SetPixel(index3D, kspacePix);
300  }
301  }
302  }
303  }
304 
305  if (m_Parameters.m_SignalGen.m_NumberOfCoils>1)
306  {
307 #ifdef WIN32
308 #pragma omp parallel for
309 #else
310 #pragma omp parallel for collapse(2)
311 #endif
312  for (int y=0; y<magnitudeDwiImage->GetLargestPossibleRegion().GetSize(1); y++)
313  for (int x=0; x<magnitudeDwiImage->GetLargestPossibleRegion().GetSize(0); x++)
314  {
315  DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z;
316  DoubleDwiType::PixelType magPix = magnitudeDwiImage->GetPixel(index3D);
317  magPix[g] = sqrt(magPix[g]/m_Parameters.m_SignalGen.m_NumberOfCoils);
318 
319  DoubleDwiType::PixelType phasePix = m_PhaseImage->GetPixel(index3D);
320  phasePix[g] = sqrt(phasePix[g]/m_Parameters.m_SignalGen.m_NumberOfCoils);
321 
322 #pragma omp critical
323  {
324  magnitudeDwiImage->SetPixel(index3D, magPix);
325  m_PhaseImage->SetPixel(index3D, phasePix);
326  }
327  }
328  }
329 
330  ++disp;
331  unsigned long newTick = 50*disp.count()/disp.expected_count();
332  for (unsigned long tick = 0; tick<(newTick-lastTick); tick++)
333  PrintToLog("*", false, false, false);
334  lastTick = newTick;
335  }
336  }
337  PrintToLog("\n", false);
338  return magnitudeDwiImage;
339  }
340 
341  template< class PixelType >
344  {
347 
348  itk::ImageRegionIterator< ItkDoubleImgType > it(image, image->GetLargestPossibleRegion());
349  while(!it.IsAtEnd())
350  {
351  if (m_Parameters.m_SignalGen.m_MaskImage.IsNotNull() && m_Parameters.m_SignalGen.m_MaskImage->GetPixel(it.GetIndex())<=0)
352  {
353  it.Set(0.0);
354  ++it;
355  continue;
356  }
357  // if (it.Get()>900)
358  // it.Set(900);
359 
360  if (it.Get()>max)
361  max = it.Get();
362  if (it.Get()<min)
363  min = it.Get();
364  ++it;
365  }
367  scaler->SetInput(image);
368  scaler->SetShift(-min);
369  scaler->SetScale(1.0/(max-min));
370  scaler->Update();
371  return scaler->GetOutput();
372  }
373 
374  template< class PixelType >
376  {
377  m_UseRelativeNonFiberVolumeFractions = false;
378 
379  // check for fiber volume fraction maps
380  int fibVolImages = 0;
381  for (int i=0; i<m_Parameters.m_FiberModelList.size(); i++)
382  {
383  if (m_Parameters.m_FiberModelList[i]->GetVolumeFractionImage().IsNotNull())
384  {
385  PrintToLog("Using volume fraction map for fiber compartment " + boost::lexical_cast<std::string>(i+1));
386  fibVolImages++;
387  }
388  }
389 
390  // check for non-fiber volume fraction maps
391  int nonfibVolImages = 0;
392  for (int i=0; i<m_Parameters.m_NonFiberModelList.size(); i++)
393  {
394  if (m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage().IsNotNull())
395  {
396  PrintToLog("Using volume fraction map for non-fiber compartment " + boost::lexical_cast<std::string>(i+1));
397  nonfibVolImages++;
398  }
399  }
400 
401  // not all fiber compartments are using volume fraction maps
402  // --> non-fiber volume fractions are assumed to be relative to the
403  // non-fiber volume and not absolute voxel-volume fractions.
404  // this means if two non-fiber compartments are used but only one of them
405  // has an associated volume fraction map, the repesctive other volume fraction map
406  // can be determined as inverse (1-val) of the present volume fraction map-
407  if ( fibVolImages<m_Parameters.m_FiberModelList.size() && nonfibVolImages==1 && m_Parameters.m_NonFiberModelList.size()==2)
408  {
409  PrintToLog("Calculating missing non-fiber volume fraction image by inverting the other.\n"
410  "Assuming non-fiber volume fraction images to contain values relative to the"
411  " remaining non-fiber volume, not absolute values.");
412 
414  inverter->SetMaximum(1.0);
415  if ( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage().IsNull()
416  && m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage().IsNotNull() )
417  {
418  // m_Parameters.m_NonFiberModelList[1]->SetVolumeFractionImage(
419  // NormalizeInsideMask( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage() ) );
420  inverter->SetInput( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage() );
421  inverter->Update();
422  m_Parameters.m_NonFiberModelList[0]->SetVolumeFractionImage(inverter->GetOutput());
423  }
424  else if ( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage().IsNull()
425  && m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage().IsNotNull() )
426  {
427  // m_Parameters.m_NonFiberModelList[0]->SetVolumeFractionImage(
428  // NormalizeInsideMask( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage() ) );
429  inverter->SetInput( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage() );
430  inverter->Update();
431  m_Parameters.m_NonFiberModelList[1]->SetVolumeFractionImage(inverter->GetOutput());
432  }
433  else
434  {
435  itkExceptionMacro("Something went wrong in automatically calculating the missing non-fiber volume fraction image!"
436  " Did you use two non fiber compartments but only one volume fraction image?"
437  " Then it should work and this error is really strange.");
438  }
439  m_UseRelativeNonFiberVolumeFractions = true;
440 
441  nonfibVolImages++;
442  }
443 
444  // Up to two fiber compartments are allowed without volume fraction maps since the volume fractions can then be determined automatically
445  if (m_Parameters.m_FiberModelList.size()>2
446  && fibVolImages!=m_Parameters.m_FiberModelList.size())
447  itkExceptionMacro("More than two fiber compartment selected but no corresponding volume fraction maps set!");
448 
449  // One non-fiber compartment is allowed without volume fraction map since the volume fraction can then be determined automatically
450  if (m_Parameters.m_NonFiberModelList.size()>1
451  && nonfibVolImages!=m_Parameters.m_NonFiberModelList.size())
452  itkExceptionMacro("More than one non-fiber compartment selected but no volume fraction maps set!");
453 
454  if (fibVolImages<m_Parameters.m_FiberModelList.size() && nonfibVolImages>0)
455  {
456  PrintToLog("Not all fiber compartments are using an associated volume fraction image.\n"
457  "Assuming non-fiber volume fraction images to contain values relative to the"
458  " remaining non-fiber volume, not absolute values.");
459  m_UseRelativeNonFiberVolumeFractions = true;
460 
461  // itk::ImageFileWriter<ItkDoubleImgType>::Pointer wr = itk::ImageFileWriter<ItkDoubleImgType>::New();
462  // wr->SetInput(m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage());
463  // wr->SetFileName("/local/volumefraction.nrrd");
464  // wr->Update();
465  }
466 
467  // initialize the images that store the output volume fraction of each compartment
468  m_VolumeFractions.clear();
469  for (int i=0; i<m_Parameters.m_FiberModelList.size()+m_Parameters.m_NonFiberModelList.size(); i++)
470  {
471  auto doubleImg = ItkDoubleImgType::New();
472  doubleImg->SetSpacing( m_WorkingSpacing );
473  doubleImg->SetOrigin( m_WorkingOrigin );
474  doubleImg->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection );
475  doubleImg->SetLargestPossibleRegion( m_WorkingImageRegion );
476  doubleImg->SetBufferedRegion( m_WorkingImageRegion );
477  doubleImg->SetRequestedRegion( m_WorkingImageRegion );
478  doubleImg->Allocate();
479  doubleImg->FillBuffer(0);
480  m_VolumeFractions.push_back(doubleImg);
481  }
482  }
483 
484  template< class PixelType >
486  {
487  m_Rotations.clear();
488  m_Translations.clear();
489  m_MotionLog = "";
490  m_SpikeLog = "";
491 
492  // initialize output dwi image
493  m_Parameters.m_SignalGen.m_CroppedRegion = m_Parameters.m_SignalGen.m_ImageRegion;
494  m_Parameters.m_SignalGen.m_CroppedRegion.SetSize( 1, m_Parameters.m_SignalGen.m_CroppedRegion.GetSize(1)
495  *m_Parameters.m_SignalGen.m_CroppingFactor);
496 
497  itk::Point<double,3> shiftedOrigin = m_Parameters.m_SignalGen.m_ImageOrigin;
498  shiftedOrigin[1] += (m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1)
499  -m_Parameters.m_SignalGen.m_CroppedRegion.GetSize(1))*m_Parameters.m_SignalGen.m_ImageSpacing[1]/2;
500 
501  m_OutputImage = OutputImageType::New();
502  m_OutputImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing );
503  m_OutputImage->SetOrigin( shiftedOrigin );
504  m_OutputImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection );
505  m_OutputImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion );
506  m_OutputImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion );
507  m_OutputImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion );
508  m_OutputImage->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() );
509  m_OutputImage->Allocate();
510  typename OutputImageType::PixelType temp;
511  temp.SetSize(m_Parameters.m_SignalGen.GetNumVolumes());
512  temp.Fill(0.0);
513  m_OutputImage->FillBuffer(temp);
514 
515  // Apply in-plane upsampling for Gibbs ringing artifact
516  double upsampling = 1;
517  if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging)
518  upsampling = 2;
519  m_WorkingSpacing = m_Parameters.m_SignalGen.m_ImageSpacing;
520  m_WorkingSpacing[0] /= upsampling;
521  m_WorkingSpacing[1] /= upsampling;
522  m_WorkingImageRegion = m_Parameters.m_SignalGen.m_ImageRegion;
523  m_WorkingImageRegion.SetSize(0, m_Parameters.m_SignalGen.m_ImageRegion.GetSize()[0]*upsampling);
524  m_WorkingImageRegion.SetSize(1, m_Parameters.m_SignalGen.m_ImageRegion.GetSize()[1]*upsampling);
525  m_WorkingOrigin = m_Parameters.m_SignalGen.m_ImageOrigin;
526  m_WorkingOrigin[0] -= m_Parameters.m_SignalGen.m_ImageSpacing[0]/2;
527  m_WorkingOrigin[0] += m_WorkingSpacing[0]/2;
528  m_WorkingOrigin[1] -= m_Parameters.m_SignalGen.m_ImageSpacing[1]/2;
529  m_WorkingOrigin[1] += m_WorkingSpacing[1]/2;
530  m_WorkingOrigin[2] -= m_Parameters.m_SignalGen.m_ImageSpacing[2]/2;
531  m_WorkingOrigin[2] += m_WorkingSpacing[2]/2;
532  m_VoxelVolume = m_WorkingSpacing[0]*m_WorkingSpacing[1]*m_WorkingSpacing[2];
533 
534  // generate double images to store the individual compartment signals
535  m_CompartmentImages.clear();
536  int numFiberCompartments = m_Parameters.m_FiberModelList.size();
537  int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size();
538  for (int i=0; i<numFiberCompartments+numNonFiberCompartments; i++)
539  {
540  auto doubleDwi = DoubleDwiType::New();
541  doubleDwi->SetSpacing( m_WorkingSpacing );
542  doubleDwi->SetOrigin( m_WorkingOrigin );
543  doubleDwi->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection );
544  doubleDwi->SetLargestPossibleRegion( m_WorkingImageRegion );
545  doubleDwi->SetBufferedRegion( m_WorkingImageRegion );
546  doubleDwi->SetRequestedRegion( m_WorkingImageRegion );
547  doubleDwi->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() );
548  doubleDwi->Allocate();
550  pix.SetSize(m_Parameters.m_SignalGen.GetNumVolumes());
551  pix.Fill(0.0);
552  doubleDwi->FillBuffer(pix);
553  m_CompartmentImages.push_back(doubleDwi);
554  }
555 
556  if (m_FiberBundle.IsNull() && m_InputImage.IsNotNull())
557  {
558  m_CompartmentImages.clear();
559 
560  m_Parameters.m_SignalGen.m_DoAddMotion = false;
561  m_Parameters.m_SignalGen.m_DoSimulateRelaxation = false;
562 
563  PrintToLog("Simulating acquisition for input diffusion-weighted image.", false);
565  caster->SetInput(m_InputImage);
566  caster->Update();
567 
568  if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging)
569  {
570  PrintToLog("Upsampling input diffusion-weighted image for Gibbs ringing simulation.", false);
571 
573  resampler->SetInput(caster->GetOutput());
574  itk::Vector< double, 3 > samplingFactor;
575  samplingFactor[0] = upsampling;
576  samplingFactor[1] = upsampling;
577  samplingFactor[2] = 1;
578  resampler->SetSamplingFactor(samplingFactor);
580  resampler->Update();
581  m_CompartmentImages.push_back(resampler->GetOutput());
582  }
583  else
584  m_CompartmentImages.push_back(caster->GetOutput());
585 
586  for (unsigned int g=0; g<m_Parameters.m_SignalGen.GetNumVolumes(); g++)
587  {
588  m_Rotation.Fill(0.0);
589  m_Translation.Fill(0.0);
590  m_Rotations.push_back(m_Rotation);
591  m_Translations.push_back(m_Translation);
592  }
593  }
594 
595  // resample mask image and frequency map to fit upsampled geometry
596  if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging)
597  {
598  if (m_Parameters.m_SignalGen.m_MaskImage.IsNotNull())
599  {
600  // rescale mask image (otherwise there are problems with the resampling)
602  rescaler->SetInput(0,m_Parameters.m_SignalGen.m_MaskImage);
603  rescaler->SetOutputMaximum(100);
604  rescaler->SetOutputMinimum(0);
605  rescaler->Update();
606 
607  // resample mask image
609  resampler->SetInput(rescaler->GetOutput());
610  resampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_MaskImage);
611  resampler->SetSize(m_WorkingImageRegion.GetSize());
612  resampler->SetOutputSpacing(m_WorkingSpacing);
613  resampler->SetOutputOrigin(m_WorkingOrigin);
615  resampler->SetInterpolator(nn_interpolator);
616  resampler->Update();
617  m_Parameters.m_SignalGen.m_MaskImage = resampler->GetOutput();
618  }
619  // resample frequency map
620  if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull())
621  {
623  resampler->SetInput(m_Parameters.m_SignalGen.m_FrequencyMap);
624  resampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_FrequencyMap);
625  resampler->SetSize(m_WorkingImageRegion.GetSize());
626  resampler->SetOutputSpacing(m_WorkingSpacing);
627  resampler->SetOutputOrigin(m_WorkingOrigin);
629  resampler->SetInterpolator(nn_interpolator);
630  resampler->Update();
631  m_Parameters.m_SignalGen.m_FrequencyMap = resampler->GetOutput();
632  }
633  }
634 
635  m_MaskImageSet = true;
636  if (m_Parameters.m_SignalGen.m_MaskImage.IsNull())
637  {
638  // no input tissue mask is set -> create default
639  PrintToLog("No tissue mask set", false);
640  m_Parameters.m_SignalGen.m_MaskImage = ItkUcharImgType::New();
641  m_Parameters.m_SignalGen.m_MaskImage->SetSpacing( m_WorkingSpacing );
642  m_Parameters.m_SignalGen.m_MaskImage->SetOrigin( m_WorkingOrigin );
643  m_Parameters.m_SignalGen.m_MaskImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection );
644  m_Parameters.m_SignalGen.m_MaskImage->SetLargestPossibleRegion( m_WorkingImageRegion );
645  m_Parameters.m_SignalGen.m_MaskImage->SetBufferedRegion( m_WorkingImageRegion );
646  m_Parameters.m_SignalGen.m_MaskImage->SetRequestedRegion( m_WorkingImageRegion );
647  m_Parameters.m_SignalGen.m_MaskImage->Allocate();
648  m_Parameters.m_SignalGen.m_MaskImage->FillBuffer(100);
649  m_MaskImageSet = false;
650  }
651  else
652  {
653  if (m_Parameters.m_SignalGen.m_MaskImage->GetLargestPossibleRegion()!=m_WorkingImageRegion)
654  {
655  itkExceptionMacro("Mask image and specified DWI geometry are not matching!");
656  }
657  PrintToLog("Using tissue mask", false);
658  }
659 
660  if (m_Parameters.m_SignalGen.m_DoAddMotion)
661  {
662  if (m_Parameters.m_SignalGen.m_DoRandomizeMotion)
663  {
664  PrintToLog("Random motion artifacts:", false);
665  PrintToLog("Maximum rotation: +/-" + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_Rotation) + "°", false);
666  PrintToLog("Maximum translation: +/-" + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_Translation) + "mm", false);
667  }
668  else
669  {
670  PrintToLog("Linear motion artifacts:", false);
671  PrintToLog("Maximum rotation: " + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_Rotation) + "°", false);
672  PrintToLog("Maximum translation: " + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_Translation) + "mm", false);
673  }
674  }
675  if ( m_Parameters.m_SignalGen.m_MotionVolumes.empty() )
676  {
677  // no motion in first volume
678  m_Parameters.m_SignalGen.m_MotionVolumes.push_back(false);
679 
680  // motion in all other volumes
681  while ( m_Parameters.m_SignalGen.m_MotionVolumes.size() < m_Parameters.m_SignalGen.GetNumVolumes() )
682  {
683  m_Parameters.m_SignalGen.m_MotionVolumes.push_back(true);
684  }
685  }
686  // we need to know for every volume if there is motion. if this information is missing, then set corresponding fal to false
687  while ( m_Parameters.m_SignalGen.m_MotionVolumes.size()<m_Parameters.m_SignalGen.GetNumVolumes() )
688  {
689  m_Parameters.m_SignalGen.m_MotionVolumes.push_back(false);
690  }
691 
692  m_NumMotionVolumes = 0;
693  for (int i=0; i<m_Parameters.m_SignalGen.GetNumVolumes(); i++)
694  {
695  if (m_Parameters.m_SignalGen.m_MotionVolumes[i])
696  {
697  m_NumMotionVolumes++;
698  }
699  }
700  m_MotionCounter = 0;
701 
702  // creat image to hold transformed mask (motion artifact)
703  m_TransformedMaskImage = ItkUcharImgType::New();
704  auto duplicator = itk::ImageDuplicator<ItkUcharImgType>::New();
705  duplicator->SetInputImage(m_Parameters.m_SignalGen.m_MaskImage);
706  duplicator->Update();
707  m_TransformedMaskImage = duplicator->GetOutput();
708 
709  // second upsampling needed for motion artifacts
710  ImageRegion<3> upsampledImageRegion = m_WorkingImageRegion;
711  DoubleVectorType upsampledSpacing = m_WorkingSpacing;
712  upsampledSpacing[0] /= 4;
713  upsampledSpacing[1] /= 4;
714  upsampledSpacing[2] /= 4;
715  upsampledImageRegion.SetSize(0, m_WorkingImageRegion.GetSize()[0]*4);
716  upsampledImageRegion.SetSize(1, m_WorkingImageRegion.GetSize()[1]*4);
717  upsampledImageRegion.SetSize(2, m_WorkingImageRegion.GetSize()[2]*4);
718  itk::Point<double,3> upsampledOrigin = m_WorkingOrigin;
719  upsampledOrigin[0] -= m_WorkingSpacing[0]/2;
720  upsampledOrigin[0] += upsampledSpacing[0]/2;
721  upsampledOrigin[1] -= m_WorkingSpacing[1]/2;
722  upsampledOrigin[1] += upsampledSpacing[1]/2;
723  upsampledOrigin[2] -= m_WorkingSpacing[2]/2;
724  upsampledOrigin[2] += upsampledSpacing[2]/2;
725 
726  m_UpsampledMaskImage = ItkUcharImgType::New();
728  upsampler->SetInput(m_Parameters.m_SignalGen.m_MaskImage);
729  upsampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_MaskImage);
730  upsampler->SetSize(upsampledImageRegion.GetSize());
731  upsampler->SetOutputSpacing(upsampledSpacing);
732  upsampler->SetOutputOrigin(upsampledOrigin);
733 
735  upsampler->SetInterpolator(nn_interpolator);
736  upsampler->Update();
737  m_UpsampledMaskImage = upsampler->GetOutput();
738  }
739 
740  template< class PixelType >
742  {
743  // resample fiber bundle for sufficient voxel coverage
744  PrintToLog("Resampling fibers ...");
745  m_SegmentVolume = 0.0001;
746  float minSpacing = 1;
747  if( m_WorkingSpacing[0]<m_WorkingSpacing[1]
748  && m_WorkingSpacing[0]<m_WorkingSpacing[2])
749  {
750  minSpacing = m_WorkingSpacing[0];
751  }
752  else if (m_WorkingSpacing[1] < m_WorkingSpacing[2])
753  {
754  minSpacing = m_WorkingSpacing[1];
755  }
756  else
757  {
758  minSpacing = m_WorkingSpacing[2];
759  }
760 
761  // working copy is needed because we need to resample the fibers but do not want to change the original bundle
762  m_FiberBundleWorkingCopy = m_FiberBundle->GetDeepCopy();
763  double volumeAccuracy = 10;
764  m_FiberBundleWorkingCopy->ResampleSpline(minSpacing/volumeAccuracy);
765  m_mmRadius = m_Parameters.m_SignalGen.m_AxonRadius/1000;
766 
767  if (m_mmRadius>0) { m_SegmentVolume = M_PI*m_mmRadius*m_mmRadius*minSpacing/volumeAccuracy; }
768  // a second fiber bundle is needed to store the transformed version of the m_FiberBundleWorkingCopy
769  m_FiberBundleTransformed = m_FiberBundleWorkingCopy;
770  }
771 
772 
773  template< class PixelType >
775  {
776  assert( ! m_Logfile.is_open() );
777 
778  std::string filePath;
779  std::string fileName;
780 
781  // Get directory name:
782  if (m_Parameters.m_Misc.m_OutputPath.size() > 0)
783  {
784  filePath = m_Parameters.m_Misc.m_OutputPath;
785  if( *(--(filePath.cend())) != '/')
786  {
787  filePath.push_back('/');
788  }
789  }
790  else
791  {
792  filePath = mitk::IOUtil::GetTempPath() + '/';
793  }
794  // check if directory exists, else use /tmp/:
795  if( itksys::SystemTools::FileIsDirectory( filePath ) )
796  {
797  while( *(--(filePath.cend())) == '/')
798  {
799  filePath.pop_back();
800  }
801  filePath = filePath + '/';
802  }
803  else
804  {
805  filePath = mitk::IOUtil::GetTempPath() + '/';
806  }
807 
808  // Get file name:
809  if( ! m_Parameters.m_Misc.m_ResultNode->GetName().empty() )
810  {
811  fileName = m_Parameters.m_Misc.m_ResultNode->GetName();
812  }
813  else
814  {
815  fileName = "";
816  }
817 
818  if( ! m_Parameters.m_Misc.m_OutputPrefix.empty() )
819  {
820  fileName = m_Parameters.m_Misc.m_OutputPrefix + fileName;
821  }
822  else
823  {
824  fileName = "fiberfox";
825  }
826 
827  // check if file already exists and DO NOT overwrite existing files:
828  std::string NameTest = fileName;
829  int c = 0;
830  while( itksys::SystemTools::FileExists( filePath + '/' + fileName + ".log" )
832  {
833  fileName = NameTest + "_" + boost::lexical_cast<std::string>(c);
834  ++c;
835  }
836 
837  try
838  {
839  m_Logfile.open( ( filePath + '/' + fileName + ".log" ).c_str() );
840  }
841  catch (const std::ios_base::failure &fail)
842  {
843  MITK_ERROR << "itkTractsToDWIImageFilter.cpp: Exception " << fail.what()
844  << " while trying to open file" << filePath << '/' << fileName << ".log";
845  return false;
846  }
847 
848  if ( m_Logfile.is_open() )
849  {
850  PrintToLog( "Logfile: " + filePath + '/' + fileName + ".log", false );
851  return true;
852  }
853  else
854  {
855  m_StatusText += "Logfile could not be opened!\n";
856  MITK_ERROR << "itkTractsToDWIImageFilter.cpp: Logfile could not be opened!";
857  return false;
858  }
859  }
860 
861 
862  template< class PixelType >
864  {
865  // prepare logfile
866  if ( ! PrepareLogFile() )
867  {
868  this->SetAbortGenerateData( true );
869  return;
870  }
871 
872  m_TimeProbe.Start();
873 
874  // check input data
875  if (m_FiberBundle.IsNull() && m_InputImage.IsNull())
876  itkExceptionMacro("Input fiber bundle and input diffusion-weighted image is NULL!");
877 
878  if (m_Parameters.m_FiberModelList.empty() && m_InputImage.IsNull())
879  itkExceptionMacro("No diffusion model for fiber compartments defined and input diffusion-weighted"
880  " image is NULL! At least one fiber compartment is necessary to simulate diffusion.");
881 
882  if (m_Parameters.m_NonFiberModelList.empty() && m_InputImage.IsNull())
883  itkExceptionMacro("No diffusion model for non-fiber compartments defined and input diffusion-weighted"
884  " image is NULL! At least one non-fiber compartment is necessary to simulate diffusion.");
885 
886  int baselineIndex = m_Parameters.m_SignalGen.GetFirstBaselineIndex();
887  if (baselineIndex<0) { itkExceptionMacro("No baseline index found!"); }
888 
889  if (!m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition) // No upsampling of input image needed if no k-space simulation is performed
890  {
891  m_Parameters.m_SignalGen.m_DoAddGibbsRinging = false;
892  }
893 
894  if (m_UseConstantRandSeed) // always generate the same random numbers?
895  { m_RandGen->SetSeed(0); }
896  else { m_RandGen->SetSeed(); }
897 
898  InitializeData();
899  if ( m_FiberBundle.IsNotNull() ) // if no fiber bundle is found, we directly proceed to the k-space acquisition simulation
900  {
901  CheckVolumeFractionImages();
902  InitializeFiberData();
903 
904  int numFiberCompartments = m_Parameters.m_FiberModelList.size();
905  int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size();
906 
907  double maxVolume = 0;
908  unsigned long lastTick = 0;
909  int signalModelSeed = m_RandGen->GetIntegerVariate();
910 
911  PrintToLog("\n", false, false);
912  PrintToLog("Generating " + boost::lexical_cast<std::string>(numFiberCompartments+numNonFiberCompartments)
913  + "-compartment diffusion-weighted signal.");
914 
915  int numFibers = m_FiberBundleWorkingCopy->GetNumFibers();
916  boost::progress_display disp(numFibers*m_Parameters.m_SignalGen.GetNumVolumes());
917 
918  PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false);
919  PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false);
920 
921  for (unsigned int g=0; g<m_Parameters.m_SignalGen.GetNumVolumes(); g++)
922  {
923  // move fibers
924  SimulateMotion(g);
925 
926  // Set signal model random generator seeds to get same configuration in each voxel
927  for (int i=0; i<m_Parameters.m_FiberModelList.size(); i++)
928  m_Parameters.m_FiberModelList.at(i)->SetSeed(signalModelSeed);
929  for (int i=0; i<m_Parameters.m_NonFiberModelList.size(); i++)
930  m_Parameters.m_NonFiberModelList.at(i)->SetSeed(signalModelSeed);
931 
932  // storing voxel-wise intra-axonal volume in mm³
933  auto intraAxonalVolumeImage = ItkDoubleImgType::New();
934  intraAxonalVolumeImage->SetSpacing( m_WorkingSpacing );
935  intraAxonalVolumeImage->SetOrigin( m_WorkingOrigin );
936  intraAxonalVolumeImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection );
937  intraAxonalVolumeImage->SetLargestPossibleRegion( m_WorkingImageRegion );
938  intraAxonalVolumeImage->SetBufferedRegion( m_WorkingImageRegion );
939  intraAxonalVolumeImage->SetRequestedRegion( m_WorkingImageRegion );
940  intraAxonalVolumeImage->Allocate();
941  intraAxonalVolumeImage->FillBuffer(0);
942  maxVolume = 0;
943 
944  vtkPolyData* fiberPolyData = m_FiberBundleTransformed->GetFiberPolyData();
945  // generate fiber signal (if there are any fiber models present)
946  if (!m_Parameters.m_FiberModelList.empty())
947  for( int i=0; i<numFibers; i++ )
948  {
949  float fiberWeight = m_FiberBundleTransformed->GetFiberWeight(i);
950  vtkCell* cell = fiberPolyData->GetCell(i);
951  int numPoints = cell->GetNumberOfPoints();
952  vtkPoints* points = cell->GetPoints();
953 
954  if (numPoints<2)
955  continue;
956 
957  for( int j=0; j<numPoints; j++)
958  {
959  if (this->GetAbortGenerateData())
960  {
961  PrintToLog("\n", false, false);
962  PrintToLog("Simulation aborted");
963  return;
964  }
965 
966  double* temp = points->GetPoint(j);
967  itk::Point<float, 3> vertex = GetItkPoint(temp);
968  itk::Vector<double> v = GetItkVector(temp);
969 
970  itk::Vector<double, 3> dir(3);
971  if (j<numPoints-1) { dir = GetItkVector(points->GetPoint(j+1))-v; }
972  else { dir = v-GetItkVector(points->GetPoint(j-1)); }
973 
974  if ( dir.GetSquaredNorm()<0.0001 || dir[0]!=dir[0] || dir[1]!=dir[1] || dir[2]!=dir[2] )
975  {
976  continue;
977  }
978 
979  itk::Index<3> idx;
980  itk::ContinuousIndex<float, 3> contIndex;
981  m_TransformedMaskImage->TransformPhysicalPointToIndex(vertex, idx);
982  m_TransformedMaskImage->TransformPhysicalPointToContinuousIndex(vertex, contIndex);
983 
984  if (!m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(idx) || m_TransformedMaskImage->GetPixel(idx)<=0)
985  {
986  continue;
987  }
988 
989  // generate signal for each fiber compartment
990  for (int k=0; k<numFiberCompartments; k++)
991  {
992  m_Parameters.m_FiberModelList[k]->SetFiberDirection(dir);
993  DoubleDwiType::PixelType pix = m_CompartmentImages.at(k)->GetPixel(idx);
994  pix[g] += fiberWeight*m_SegmentVolume*m_Parameters.m_FiberModelList[k]->SimulateMeasurement(g);
995 
996  m_CompartmentImages.at(k)->SetPixel(idx, pix);
997  }
998 
999  // update fiber volume image
1000  double vol = intraAxonalVolumeImage->GetPixel(idx) + m_SegmentVolume*fiberWeight;
1001  intraAxonalVolumeImage->SetPixel(idx, vol);
1002 
1003  // we assume that the first volume is always unweighted!
1004  if (vol>maxVolume) { maxVolume = vol; }
1005  }
1006 
1007  // progress report
1008  ++disp;
1009  unsigned long newTick = 50*disp.count()/disp.expected_count();
1010  for (unsigned int tick = 0; tick<(newTick-lastTick); tick++)
1011  {
1012  PrintToLog("*", false, false, false);
1013  }
1014  lastTick = newTick;
1015  }
1016 
1017  // generate non-fiber signal
1018  ImageRegionIterator<ItkUcharImgType> it3(m_TransformedMaskImage, m_TransformedMaskImage->GetLargestPossibleRegion());
1019  double fact = 1; // density correction factor in mm³
1020  if (m_Parameters.m_SignalGen.m_AxonRadius<0.0001 || maxVolume>m_VoxelVolume) // the fullest voxel is always completely full
1021  fact = m_VoxelVolume/maxVolume;
1022  while(!it3.IsAtEnd())
1023  {
1024  if (it3.Get()>0)
1025  {
1026  DoubleDwiType::IndexType index = it3.GetIndex();
1027  itk::Point<double, 3> point;
1028  m_TransformedMaskImage->TransformIndexToPhysicalPoint(index, point);
1029  if ( m_Parameters.m_SignalGen.m_DoAddMotion && g>=0
1030  && m_Parameters.m_SignalGen.m_MotionVolumes[g] )
1031  {
1032  if (m_Parameters.m_SignalGen.m_DoRandomizeMotion)
1033  {
1034  point = m_FiberBundleWorkingCopy->TransformPoint( point.GetVnlVector(), -m_Rotation[0], -m_Rotation[1], -m_Rotation[2],
1035  -m_Translation[0], -m_Translation[1], -m_Translation[2] );
1036  }
1037  else
1038  {
1039  point = m_FiberBundleWorkingCopy->TransformPoint( point.GetVnlVector(),
1040  -m_Rotation[0]*m_MotionCounter, -m_Rotation[1]*m_MotionCounter, -m_Rotation[2]*m_MotionCounter,
1041  -m_Translation[0]*m_MotionCounter, -m_Translation[1]*m_MotionCounter, -m_Translation[2]*m_MotionCounter );
1042  }
1043  }
1044 
1045  double iAxVolume = intraAxonalVolumeImage->GetPixel(index);
1046 
1047  // if volume fraction image is set use it, otherwise use scaling factor to obtain one full fiber voxel
1048  double fact2 = fact;
1049  if ( m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()!=nullptr
1050  && iAxVolume>0.0001 )
1051  {
1052  double val = InterpolateValue(point, m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage());
1053  if (val>=0) { fact2 = m_VoxelVolume*val/iAxVolume; }
1054  }
1055 
1056  // adjust intra-axonal image value
1057  for (int i=0; i<numFiberCompartments; i++)
1058  {
1059  DoubleDwiType::PixelType pix = m_CompartmentImages.at(i)->GetPixel(index);
1060  pix[g] *= fact2;
1061  m_CompartmentImages.at(i)->SetPixel(index, pix);
1062  }
1063 
1064  // simulate other compartments
1065  SimulateExtraAxonalSignal(index, iAxVolume*fact2, g);
1066  }
1067  ++it3;
1068  }
1069  }
1070 
1071  PrintToLog("\n", false);
1072  if (this->GetAbortGenerateData())
1073  {
1074  PrintToLog("\n", false, false);
1075  PrintToLog("Simulation aborted");
1076  return;
1077  }
1078  }
1079 
1080  DoubleDwiType::Pointer doubleOutImage;
1081  double signalScale = m_Parameters.m_SignalGen.m_SignalScale;
1082  if ( m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition ) // do k-space stuff
1083  {
1084  PrintToLog("\n", false, false);
1085  PrintToLog("Simulating k-space acquisition using "
1086  +boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_NumberOfCoils)
1087  +" coil(s)");
1088 
1089  switch (m_Parameters.m_SignalGen.m_AcquisitionType)
1090  {
1091  case SignalGenerationParameters::SingleShotEpi:
1092  {
1093  PrintToLog("Acquisition type: single shot EPI", false);
1094  break;
1095  }
1096  case SignalGenerationParameters::SpinEcho:
1097  {
1098  PrintToLog("Acquisition type: classic spin echo with cartesian k-space trajectory", false);
1099  break;
1100  }
1101  default:
1102  {
1103  PrintToLog("Acquisition type: single shot EPI", false);
1104  break;
1105  }
1106  }
1107 
1108  if (m_Parameters.m_SignalGen.m_NoiseVariance>0)
1109  PrintToLog("Simulating complex Gaussian noise", false);
1110  if (m_Parameters.m_SignalGen.m_DoSimulateRelaxation)
1111  PrintToLog("Simulating signal relaxation", false);
1112  if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull())
1113  PrintToLog("Simulating distortions", false);
1114  if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging)
1115  PrintToLog("Simulating ringing artifacts", false);
1116  if (m_Parameters.m_SignalGen.m_EddyStrength>0)
1117  PrintToLog("Simulating eddy currents", false);
1118  if (m_Parameters.m_SignalGen.m_Spikes>0)
1119  PrintToLog("Simulating spikes", false);
1120  if (m_Parameters.m_SignalGen.m_CroppingFactor<1.0)
1121  PrintToLog("Simulating aliasing artifacts", false);
1122  if (m_Parameters.m_SignalGen.m_KspaceLineOffset>0)
1123  PrintToLog("Simulating ghosts", false);
1124 
1125  doubleOutImage = SimulateKspaceAcquisition(m_CompartmentImages);
1126  signalScale = 1; // already scaled in SimulateKspaceAcquisition()
1127  }
1128  else // don't do k-space stuff, just sum compartments
1129  {
1130  PrintToLog("Summing compartments");
1131  doubleOutImage = m_CompartmentImages.at(0);
1132 
1133  for (unsigned int i=1; i<m_CompartmentImages.size(); i++)
1134  {
1136  adder->SetInput1(doubleOutImage);
1137  adder->SetInput2(m_CompartmentImages.at(i));
1138  adder->Update();
1139  doubleOutImage = adder->GetOutput();
1140  }
1141  }
1142  if (this->GetAbortGenerateData())
1143  {
1144  PrintToLog("\n", false, false);
1145  PrintToLog("Simulation aborted");
1146  return;
1147  }
1148 
1149  PrintToLog("Finalizing image");
1150  if (signalScale>1)
1151  PrintToLog(" Scaling signal", false);
1152  if (m_Parameters.m_NoiseModel)
1153  PrintToLog(" Adding noise", false);
1154  unsigned int window = 0;
1155  unsigned int min = itk::NumericTraits<unsigned int>::max();
1156  ImageRegionIterator<OutputImageType> it4 (m_OutputImage, m_OutputImage->GetLargestPossibleRegion());
1157  DoubleDwiType::PixelType signal; signal.SetSize(m_Parameters.m_SignalGen.GetNumVolumes());
1158  boost::progress_display disp2(m_OutputImage->GetLargestPossibleRegion().GetNumberOfPixels());
1159 
1160  PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false);
1161  PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false);
1162  int lastTick = 0;
1163 
1164  while(!it4.IsAtEnd())
1165  {
1166  if (this->GetAbortGenerateData())
1167  {
1168  PrintToLog("\n", false, false);
1169  PrintToLog("Simulation aborted");
1170  return;
1171  }
1172 
1173  ++disp2;
1174  unsigned long newTick = 50*disp2.count()/disp2.expected_count();
1175  for (unsigned long tick = 0; tick<(newTick-lastTick); tick++)
1176  PrintToLog("*", false, false, false);
1177  lastTick = newTick;
1178 
1179  typename OutputImageType::IndexType index = it4.GetIndex();
1180  signal = doubleOutImage->GetPixel(index)*signalScale;
1181 
1182  if (m_Parameters.m_NoiseModel)
1183  m_Parameters.m_NoiseModel->AddNoise(signal);
1184 
1185  for (unsigned int i=0; i<signal.Size(); i++)
1186  {
1187  if (signal[i]>0)
1188  signal[i] = floor(signal[i]+0.5);
1189  else
1190  signal[i] = ceil(signal[i]-0.5);
1191 
1192  if ( (!m_Parameters.m_SignalGen.IsBaselineIndex(i) || signal.Size()==1) && signal[i]>window)
1193  window = signal[i];
1194  if ( (!m_Parameters.m_SignalGen.IsBaselineIndex(i) || signal.Size()==1) && signal[i]<min)
1195  min = signal[i];
1196  }
1197  it4.Set(signal);
1198  ++it4;
1199  }
1200  window -= min;
1201  unsigned int level = window/2 + min;
1202  m_LevelWindow.SetLevelWindow(level, window);
1203  this->SetNthOutput(0, m_OutputImage);
1204 
1205  PrintToLog("\n", false);
1206  PrintToLog("Finished simulation");
1207  m_TimeProbe.Stop();
1208 
1209  if (m_Parameters.m_SignalGen.m_DoAddMotion)
1210  {
1211  PrintToLog("\nHead motion log:", false);
1212  PrintToLog(m_MotionLog, false, false);
1213  }
1214 
1215  if (m_Parameters.m_SignalGen.m_Spikes>0)
1216  {
1217  PrintToLog("\nSpike log:", false);
1218  PrintToLog(m_SpikeLog, false, false);
1219  }
1220 
1221  if (m_Logfile.is_open())
1222  m_Logfile.close();
1223  } // Heilliger Spaghetti-Code, Batman! todo/mdh
1224 
1225 
1226  template< class PixelType >
1227  void TractsToDWIImageFilter< PixelType >::PrintToLog(string m, bool addTime, bool linebreak, bool stdOut)
1228  {
1229  // timestamp
1230  if (addTime)
1231  {
1232  m_Logfile << this->GetTime() << " > ";
1233  m_StatusText += this->GetTime() + " > ";
1234  if (stdOut)
1235  std::cout << this->GetTime() << " > ";
1236  }
1237 
1238  // message
1239  if (m_Logfile.is_open())
1240  m_Logfile << m;
1241  m_StatusText += m;
1242  if (stdOut)
1243  std::cout << m;
1244 
1245  // new line
1246  if (linebreak)
1247  {
1248  if (m_Logfile.is_open())
1249  m_Logfile << "\n";
1250  m_StatusText += "\n";
1251  if (stdOut)
1252  std::cout << "\n";
1253  }
1254  }
1255 
1256  template< class PixelType >
1258  {
1259  // is motion artifact enabled?
1260  // is the current volume g affected by motion?
1261  if ( m_Parameters.m_SignalGen.m_DoAddMotion
1262  && m_Parameters.m_SignalGen.m_MotionVolumes[g]
1263  && g<m_Parameters.m_SignalGen.GetNumVolumes() )
1264  {
1265  if ( m_Parameters.m_SignalGen.m_DoRandomizeMotion )
1266  {
1267  // either undo last transform or work on fresh copy of untransformed fibers
1268  m_FiberBundleTransformed = m_FiberBundleWorkingCopy->GetDeepCopy();
1269 
1270  m_Rotation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[0]*2)
1271  -m_Parameters.m_SignalGen.m_Rotation[0];
1272  m_Rotation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[1]*2)
1273  -m_Parameters.m_SignalGen.m_Rotation[1];
1274  m_Rotation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[2]*2)
1275  -m_Parameters.m_SignalGen.m_Rotation[2];
1276 
1277  m_Translation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[0]*2)
1278  -m_Parameters.m_SignalGen.m_Translation[0];
1279  m_Translation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[1]*2)
1280  -m_Parameters.m_SignalGen.m_Translation[1];
1281  m_Translation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[2]*2)
1282  -m_Parameters.m_SignalGen.m_Translation[2];
1283  }
1284  else
1285  {
1286  m_Rotation = m_Parameters.m_SignalGen.m_Rotation / m_NumMotionVolumes;
1287  m_Translation = m_Parameters.m_SignalGen.m_Translation / m_NumMotionVolumes;
1288  m_MotionCounter++;
1289  }
1290 
1291  // move mask image
1292  if (m_MaskImageSet)
1293  {
1294  ImageRegionIterator<ItkUcharImgType> maskIt(m_UpsampledMaskImage, m_UpsampledMaskImage->GetLargestPossibleRegion());
1295  m_TransformedMaskImage->FillBuffer(0);
1296 
1297  while(!maskIt.IsAtEnd())
1298  {
1299  if (maskIt.Get()<=0)
1300  {
1301  ++maskIt;
1302  continue;
1303  }
1304 
1305  DoubleDwiType::IndexType index = maskIt.GetIndex();
1306  itk::Point<double, 3> point;
1307  m_UpsampledMaskImage->TransformIndexToPhysicalPoint(index, point);
1308  if (m_Parameters.m_SignalGen.m_DoRandomizeMotion)
1309  {
1310  point = m_FiberBundleWorkingCopy->TransformPoint(point.GetVnlVector(),
1311  m_Rotation[0],m_Rotation[1],m_Rotation[2],
1312  m_Translation[0],m_Translation[1],m_Translation[2]);
1313  }
1314  else
1315  {
1316  point = m_FiberBundleWorkingCopy->TransformPoint(point.GetVnlVector(),
1317  m_Rotation[0]*m_MotionCounter,m_Rotation[1]*m_MotionCounter,m_Rotation[2]*m_MotionCounter,
1318  m_Translation[0]*m_MotionCounter,m_Translation[1]*m_MotionCounter,m_Translation[2]*m_MotionCounter);
1319  }
1320 
1321  m_TransformedMaskImage->TransformPhysicalPointToIndex(point, index);
1322 
1323  if (m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(index))
1324  { m_TransformedMaskImage->SetPixel(index,100); }
1325  ++maskIt;
1326  }
1327  }
1328 
1329  if (m_Parameters.m_SignalGen.m_DoRandomizeMotion)
1330  {
1331  m_Rotations.push_back(m_Rotation);
1332  m_Translations.push_back(m_Translation);
1333 
1334  m_MotionLog += boost::lexical_cast<std::string>(g) + " rotation: " + boost::lexical_cast<std::string>(m_Rotation[0])
1335  + "," + boost::lexical_cast<std::string>(m_Rotation[1])
1336  + "," + boost::lexical_cast<std::string>(m_Rotation[2]) + ";";
1337 
1338  m_MotionLog += " translation: " + boost::lexical_cast<std::string>(m_Translation[0])
1339  + "," + boost::lexical_cast<std::string>(m_Translation[1])
1340  + "," + boost::lexical_cast<std::string>(m_Translation[2]) + "\n";
1341  }
1342  else
1343  {
1344  m_Rotations.push_back(m_Rotation*m_MotionCounter);
1345  m_Translations.push_back(m_Translation*m_MotionCounter);
1346 
1347  m_MotionLog += boost::lexical_cast<std::string>(g) + " rotation: " + boost::lexical_cast<std::string>(m_Rotation[0]*m_MotionCounter)
1348  + "," + boost::lexical_cast<std::string>(m_Rotation[1]*m_MotionCounter)
1349  + "," + boost::lexical_cast<std::string>(m_Rotation[2]*m_MotionCounter) + ";";
1350 
1351  m_MotionLog += " translation: " + boost::lexical_cast<std::string>(m_Translation[0]*m_MotionCounter)
1352  + "," + boost::lexical_cast<std::string>(m_Translation[1]*m_MotionCounter)
1353  + "," + boost::lexical_cast<std::string>(m_Translation[2]*m_MotionCounter) + "\n";
1354  }
1355 
1356  m_FiberBundleTransformed->TransformFibers(m_Rotation[0],m_Rotation[1],m_Rotation[2],m_Translation[0],m_Translation[1],m_Translation[2]);
1357  }
1358  else
1359  {
1360  m_Rotation.Fill(0.0);
1361  m_Translation.Fill(0.0);
1362  m_Rotations.push_back(m_Rotation);
1363  m_Translations.push_back(m_Translation);
1364 
1365  m_MotionLog += boost::lexical_cast<std::string>(g) + " rotation: " + boost::lexical_cast<std::string>(m_Rotation[0])
1366  + "," + boost::lexical_cast<std::string>(m_Rotation[1])
1367  + "," + boost::lexical_cast<std::string>(m_Rotation[2]) + ";";
1368 
1369  m_MotionLog += " translation: " + boost::lexical_cast<std::string>(m_Translation[0])
1370  + "," + boost::lexical_cast<std::string>(m_Translation[1])
1371  + "," + boost::lexical_cast<std::string>(m_Translation[2]) + "\n";
1372  }
1373  }
1374 
1375  template< class PixelType >
1377  SimulateExtraAxonalSignal(ItkUcharImgType::IndexType index, double intraAxonalVolume, int g)
1378  {
1379  int numFiberCompartments = m_Parameters.m_FiberModelList.size();
1380  int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size();
1381 
1382  if (intraAxonalVolume>0.0001 && m_Parameters.m_SignalGen.m_DoDisablePartialVolume) // only fiber in voxel
1383  {
1384  DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(index);
1385  if (g>=0)
1386  pix[g] *= m_VoxelVolume/intraAxonalVolume;
1387  else
1388  pix *= m_VoxelVolume/intraAxonalVolume;
1389  m_CompartmentImages.at(0)->SetPixel(index, pix);
1390  if (g==0)
1391  m_VolumeFractions.at(0)->SetPixel(index, 1);
1392  for (int i=1; i<numFiberCompartments; i++)
1393  {
1394  DoubleDwiType::PixelType pix = m_CompartmentImages.at(i)->GetPixel(index);
1395  if (g>=0)
1396  pix[g] = 0.0;
1397  else
1398  pix.Fill(0.0);
1399  m_CompartmentImages.at(i)->SetPixel(index, pix);
1400  }
1401  }
1402  else
1403  {
1404  if (g==0)
1405  {
1406  m_VolumeFractions.at(0)->SetPixel(index, intraAxonalVolume/m_VoxelVolume);
1407  }
1408 
1409  // get non-transformed point (remove headmotion tranformation)
1410  // this point can then be transformed to each of the original images, regardless of their geometry
1411  itk::Point<double, 3> point;
1412  m_TransformedMaskImage->TransformIndexToPhysicalPoint(index, point);
1413 
1414  if ( m_Parameters.m_SignalGen.m_DoAddMotion && g>=0
1415  && m_Parameters.m_SignalGen.m_MotionVolumes[g] )
1416  {
1417  if (m_Parameters.m_SignalGen.m_DoRandomizeMotion)
1418  {
1419  point = m_FiberBundleWorkingCopy->TransformPoint(point.GetVnlVector(),
1420  -m_Rotation[0],-m_Rotation[1],-m_Rotation[2],
1421  -m_Translation[0],-m_Translation[1],-m_Translation[2]);
1422  }
1423  else
1424  {
1425  point = m_FiberBundleWorkingCopy->TransformPoint(point.GetVnlVector(),
1426  -m_Rotation[0]*m_MotionCounter,-m_Rotation[1]*m_MotionCounter,-m_Rotation[2]*m_MotionCounter,
1427  -m_Translation[0]*m_MotionCounter,-m_Translation[1]*m_MotionCounter,-m_Translation[2]*m_MotionCounter);
1428  }
1429  }
1430 
1431  if (m_Parameters.m_SignalGen.m_DoDisablePartialVolume)
1432  {
1433  int maxVolumeIndex = 0;
1434  double maxWeight = 0;
1435  for (int i=0; i<numNonFiberCompartments; i++)
1436  {
1437  double weight = 0;
1438  if (numNonFiberCompartments>1)
1439  {
1440  double val = InterpolateValue(point, m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage());
1441  if (val<0)
1442  continue;
1443  else
1444  weight = val;
1445  }
1446 
1447  if (weight>maxWeight)
1448  {
1449  maxWeight = weight;
1450  maxVolumeIndex = i;
1451  }
1452  }
1453 
1454  DoubleDwiType::Pointer doubleDwi = m_CompartmentImages.at(maxVolumeIndex+numFiberCompartments);
1455  DoubleDwiType::PixelType pix = doubleDwi->GetPixel(index);
1456 
1457  if (g>=0)
1458  pix[g] += m_Parameters.m_NonFiberModelList[maxVolumeIndex]->SimulateMeasurement(g)*m_VoxelVolume;
1459  else
1460  pix += m_Parameters.m_NonFiberModelList[maxVolumeIndex]->SimulateMeasurement()*m_VoxelVolume;
1461  doubleDwi->SetPixel(index, pix);
1462  if (g==0)
1463  m_VolumeFractions.at(maxVolumeIndex+numFiberCompartments)->SetPixel(index, 1);
1464  }
1465  else
1466  {
1467  double extraAxonalVolume = m_VoxelVolume-intraAxonalVolume; // non-fiber volume
1468  if (extraAxonalVolume<0)
1469  {
1470  MITK_ERROR << "Corrupted intra-axonal signal voxel detected. Fiber volume larger voxel volume!";
1471  extraAxonalVolume = 0;
1472  }
1473  double interAxonalVolume = 0;
1474  if (numFiberCompartments>1)
1475  interAxonalVolume = extraAxonalVolume * intraAxonalVolume/m_VoxelVolume; // inter-axonal fraction of non fiber compartment
1476  double other = extraAxonalVolume - interAxonalVolume; // rest of compartment
1477  if (other<0)
1478  {
1479  MITK_ERROR << "Corrupted signal voxel detected. Fiber volume larger voxel volume!";
1480  other = 0;
1481  }
1482 
1483  // adjust non-fiber and intra-axonal signal
1484  for (int i=1; i<numFiberCompartments; i++)
1485  {
1486  double weight = interAxonalVolume;
1487  DoubleDwiType::PixelType pix = m_CompartmentImages.at(i)->GetPixel(index);
1488  if (intraAxonalVolume>0) // remove scaling by intra-axonal volume from inter-axonal compartment
1489  {
1490  if (g>=0)
1491  pix[g] /= intraAxonalVolume;
1492  else
1493  pix /= intraAxonalVolume;
1494  }
1495 
1496  if (m_Parameters.m_FiberModelList[i]->GetVolumeFractionImage()!=nullptr)
1497  {
1498  double val = InterpolateValue(point, m_Parameters.m_FiberModelList[i]->GetVolumeFractionImage());
1499  if (val<0)
1500  continue;
1501  else
1502  weight = val*m_VoxelVolume;
1503  }
1504 
1505  if (g>=0)
1506  pix[g] *= weight;
1507  else
1508  pix *= weight;
1509  m_CompartmentImages.at(i)->SetPixel(index, pix);
1510  if (g==0)
1511  m_VolumeFractions.at(i)->SetPixel(index, weight/m_VoxelVolume);
1512  }
1513 
1514  for (int i=0; i<numNonFiberCompartments; i++)
1515  {
1516  double weight = other;
1517  DoubleDwiType::PixelType pix = m_CompartmentImages.at(i+numFiberCompartments)->GetPixel(index);
1518  if (m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()!=nullptr)
1519  {
1520  double val = InterpolateValue(point, m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage());
1521  if (val<0)
1522  continue;
1523  else
1524  weight = val*m_VoxelVolume;
1525 
1526  if (m_UseRelativeNonFiberVolumeFractions)
1527  weight *= other/m_VoxelVolume;
1528  }
1529 
1530  if (g>=0)
1531  pix[g] += m_Parameters.m_NonFiberModelList[i]->SimulateMeasurement(g)*weight;
1532  else
1533  pix += m_Parameters.m_NonFiberModelList[i]->SimulateMeasurement()*weight;
1534  m_CompartmentImages.at(i+numFiberCompartments)->SetPixel(index, pix);
1535  if (g==0)
1536  m_VolumeFractions.at(i+numFiberCompartments)->SetPixel(index, weight/m_VoxelVolume);
1537  }
1538  }
1539  }
1540  }
1541 
1542  template< class PixelType >
1544  InterpolateValue(itk::Point<float, 3> itkP, ItkDoubleImgType::Pointer img)
1545  {
1546  itk::Index<3> idx;
1547  itk::ContinuousIndex< double, 3> cIdx;
1548  img->TransformPhysicalPointToIndex(itkP, idx);
1549  img->TransformPhysicalPointToContinuousIndex(itkP, cIdx);
1550 
1551  double pix = -1;
1552  if ( img->GetLargestPossibleRegion().IsInside(idx) )
1553  pix = img->GetPixel(idx);
1554  else
1555  return pix;
1556 
1557  double frac_x = cIdx[0] - idx[0];
1558  double frac_y = cIdx[1] - idx[1];
1559  double frac_z = cIdx[2] - idx[2];
1560  if (frac_x<0)
1561  {
1562  idx[0] -= 1;
1563  frac_x += 1;
1564  }
1565  if (frac_y<0)
1566  {
1567  idx[1] -= 1;
1568  frac_y += 1;
1569  }
1570  if (frac_z<0)
1571  {
1572  idx[2] -= 1;
1573  frac_z += 1;
1574  }
1575  frac_x = 1-frac_x;
1576  frac_y = 1-frac_y;
1577  frac_z = 1-frac_z;
1578 
1579  // int coordinates inside image?
1580  if (idx[0] >= 0 && idx[0] < img->GetLargestPossibleRegion().GetSize(0)-1 &&
1581  idx[1] >= 0 && idx[1] < img->GetLargestPossibleRegion().GetSize(1)-1 &&
1582  idx[2] >= 0 && idx[2] < img->GetLargestPossibleRegion().GetSize(2)-1)
1583  {
1584  vnl_vector_fixed<double, 8> interpWeights;
1585  interpWeights[0] = ( frac_x)*( frac_y)*( frac_z);
1586  interpWeights[1] = (1-frac_x)*( frac_y)*( frac_z);
1587  interpWeights[2] = ( frac_x)*(1-frac_y)*( frac_z);
1588  interpWeights[3] = ( frac_x)*( frac_y)*(1-frac_z);
1589  interpWeights[4] = (1-frac_x)*(1-frac_y)*( frac_z);
1590  interpWeights[5] = ( frac_x)*(1-frac_y)*(1-frac_z);
1591  interpWeights[6] = (1-frac_x)*( frac_y)*(1-frac_z);
1592  interpWeights[7] = (1-frac_x)*(1-frac_y)*(1-frac_z);
1593 
1594  pix = img->GetPixel(idx) * interpWeights[0];
1595  ItkDoubleImgType::IndexType tmpIdx = idx; tmpIdx[0]++;
1596  pix += img->GetPixel(tmpIdx) * interpWeights[1];
1597  tmpIdx = idx; tmpIdx[1]++;
1598  pix += img->GetPixel(tmpIdx) * interpWeights[2];
1599  tmpIdx = idx; tmpIdx[2]++;
1600  pix += img->GetPixel(tmpIdx) * interpWeights[3];
1601  tmpIdx = idx; tmpIdx[0]++; tmpIdx[1]++;
1602  pix += img->GetPixel(tmpIdx) * interpWeights[4];
1603  tmpIdx = idx; tmpIdx[1]++; tmpIdx[2]++;
1604  pix += img->GetPixel(tmpIdx) * interpWeights[5];
1605  tmpIdx = idx; tmpIdx[2]++; tmpIdx[0]++;
1606  pix += img->GetPixel(tmpIdx) * interpWeights[6];
1607  tmpIdx = idx; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++;
1608  pix += img->GetPixel(tmpIdx) * interpWeights[7];
1609  }
1610 
1611  return pix;
1612  }
1613 
1614  template< class PixelType >
1615  itk::Point<float, 3> TractsToDWIImageFilter< PixelType >::GetItkPoint(double point[3])
1616  {
1617  itk::Point<float, 3> itkPoint;
1618  itkPoint[0] = point[0];
1619  itkPoint[1] = point[1];
1620  itkPoint[2] = point[2];
1621  return itkPoint;
1622  }
1623 
1624  template< class PixelType >
1625  itk::Vector<double, 3> TractsToDWIImageFilter< PixelType >::GetItkVector(double point[3])
1626  {
1627  itk::Vector<double, 3> itkVector;
1628  itkVector[0] = point[0];
1629  itkVector[1] = point[1];
1630  itkVector[2] = point[2];
1631  return itkVector;
1632  }
1633 
1634  template< class PixelType >
1635  vnl_vector_fixed<double, 3> TractsToDWIImageFilter< PixelType >::GetVnlVector(double point[3])
1636  {
1637  vnl_vector_fixed<double, 3> vnlVector;
1638  vnlVector[0] = point[0];
1639  vnlVector[1] = point[1];
1640  vnlVector[2] = point[2];
1641  return vnlVector;
1642  }
1643 
1644  template< class PixelType >
1646  {
1647  vnl_vector_fixed<double, 3> vnlVector;
1648  vnlVector[0] = vector[0];
1649  vnlVector[1] = vector[1];
1650  vnlVector[2] = vector[2];
1651  return vnlVector;
1652  }
1653 
1654  template< class PixelType >
1656  return (num > 0.0) ? floor(num + 0.5) : ceil(num - 0.5);
1657  }
1658 
1659  template< class PixelType >
1661  {
1662  m_TimeProbe.Stop();
1663  unsigned long total = RoundToNearest(m_TimeProbe.GetTotal());
1664  unsigned long hours = total/3600;
1665  unsigned long minutes = (total%3600)/60;
1666  unsigned long seconds = total%60;
1667  std::string out = "";
1668  out.append(boost::lexical_cast<std::string>(hours));
1669  out.append(":");
1670  out.append(boost::lexical_cast<std::string>(minutes));
1671  out.append(":");
1672  out.append(boost::lexical_cast<std::string>(seconds));
1673  m_TimeProbe.Start();
1674  return out;
1675  }
1676 
1677 }
void PrintToLog(string m, bool addTime=true, bool linebreak=true, bool stdOut=true)
itk::SmartPointer< Self > Pointer
void SimulateExtraAxonalSignal(ItkUcharImgType::IndexType index, double intraAxonalVolume, int g=-1)
Generates artificial diffusion weighted image volume from the input fiberbundle using a generic multi...
static std::string GetTempPath()
Definition: mitkIOUtil.cpp:372
ItkDoubleImgType::Pointer NormalizeInsideMask(ItkDoubleImgType::Pointer image)
#define MITK_ERROR
Definition: mitkLogMacros.h:24
static Pointer New()
DoubleDwiType::Pointer SimulateKspaceAcquisition(std::vector< DoubleDwiType::Pointer > &images)
itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer m_RandGen
static Pointer New()
static Pointer New()
Abstract class for diffusion signal models.
itk::Vector< double, 3 > DoubleVectorType
itk::Point< float, 3 > GetItkPoint(double point[3])
double InterpolateValue(itk::Point< float, 3 > itkP, ItkDoubleImgType::Pointer img)
static T max(T x, T y)
Definition: svm.cpp:70
static T min(T x, T y)
Definition: svm.cpp:67
Resample DWI channel by channel.
unsigned short PixelType
vnl_vector_fixed< double, 3 > GetVnlVector(double point[3])
itk::Vector< double, 3 > GetItkVector(double point[3])
section MAP_FRAME_Mapper_Settings Mapper settings For the mapping of corrected images
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.