Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
itkStreamlineTrackingFilter.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 
17 #ifndef __itkStreamlineTrackingFilter_txx
18 #define __itkStreamlineTrackingFilter_txx
19 
20 #include <time.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 
25 #include <itkImageRegionConstIterator.h>
26 #include <itkImageRegionConstIteratorWithIndex.h>
27 #include <itkImageRegionIterator.h>
28 
29 #define _USE_MATH_DEFINES
30 #include <math.h>
31 
32 namespace itk {
33 
34 template< class TTensorPixelType, class TPDPixelType>
35 StreamlineTrackingFilter< TTensorPixelType,
36 TPDPixelType>
38  : m_FiberPolyData(NULL)
39  , m_Points(NULL)
40  , m_Cells(NULL)
41  , m_FaImage(NULL)
42  , m_NumberOfInputs(1)
43  , m_FaThreshold(0.2)
44  , m_MinCurvatureRadius(0)
45  , m_StepSize(0)
46  , m_MaxLength(10000)
47  , m_MinTractLength(0.0)
48  , m_SeedsPerVoxel(1)
49  , m_F(1.0)
50  , m_G(0.0)
51  , m_Interpolate(true)
52  , m_PointPistance(0.0)
53  , m_ResampleFibers(false)
54  , m_SeedImage(NULL)
55  , m_MaskImage(NULL)
56 {
57  // At least 1 inputs is necessary for a vector image.
58  // For images added one at a time we need at least six
59  this->SetNumberOfRequiredInputs( 1 );
60  this->SetNumberOfIndexedInputs(3);
61 }
62 
63 template< class TTensorPixelType,
64  class TPDPixelType>
66 TPDPixelType>
67 ::RoundToNearest(double num) {
68  return (num > 0.0) ? floor(num + 0.5) : ceil(num - 0.5);
69 }
70 
71 template< class TTensorPixelType,
72  class TPDPixelType>
74 TPDPixelType>
75 ::BeforeThreadedGenerateData()
76 {
77  m_FiberPolyData = FiberPolyDataType::New();
80 
81  InputImageType* inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) );
82  m_ImageSize.resize(3);
83  m_ImageSize[0] = inputImage->GetLargestPossibleRegion().GetSize()[0];
84  m_ImageSize[1] = inputImage->GetLargestPossibleRegion().GetSize()[1];
85  m_ImageSize[2] = inputImage->GetLargestPossibleRegion().GetSize()[2];
86 
87  if (m_ImageSize[0]<3 || m_ImageSize[1]<3 || m_ImageSize[2]<3)
88  m_Interpolate = false;
89 
90  m_ImageSpacing.resize(3);
91  m_ImageSpacing[0] = inputImage->GetSpacing()[0];
92  m_ImageSpacing[1] = inputImage->GetSpacing()[1];
93  m_ImageSpacing[2] = inputImage->GetSpacing()[2];
94 
95  double minSpacing;
96  if(m_ImageSpacing[0]<m_ImageSpacing[1] && m_ImageSpacing[0]<m_ImageSpacing[2])
97  minSpacing = m_ImageSpacing[0];
98  else if (m_ImageSpacing[1] < m_ImageSpacing[2])
99  minSpacing = m_ImageSpacing[1];
100  else
101  minSpacing = m_ImageSpacing[2];
102  if (m_StepSize<0.1*minSpacing)
103  m_StepSize = 0.1*minSpacing;
104 
105  if (m_ResampleFibers)
106  m_PointPistance = 0.5*minSpacing;
107 
109  for (unsigned int i=0; i<this->GetNumberOfThreads(); i++)
110  {
112  m_PolyDataContainer->InsertElement(i, poly);
113  }
114 
115  if (m_SeedImage.IsNull())
116  {
117  // initialize mask image
118  m_SeedImage = ItkUcharImgType::New();
119  m_SeedImage->SetSpacing( inputImage->GetSpacing() );
120  m_SeedImage->SetOrigin( inputImage->GetOrigin() );
121  m_SeedImage->SetDirection( inputImage->GetDirection() );
122  m_SeedImage->SetRegions( inputImage->GetLargestPossibleRegion() );
123  m_SeedImage->Allocate();
124  m_SeedImage->FillBuffer(1);
125  }
126 
127  if (m_MaskImage.IsNull())
128  {
129  // initialize mask image
130  m_MaskImage = ItkUcharImgType::New();
131  m_MaskImage->SetSpacing( inputImage->GetSpacing() );
132  m_MaskImage->SetOrigin( inputImage->GetOrigin() );
133  m_MaskImage->SetDirection( inputImage->GetDirection() );
134  m_MaskImage->SetRegions( inputImage->GetLargestPossibleRegion() );
135  m_MaskImage->Allocate();
136  m_MaskImage->FillBuffer(1);
137  }
138 
139  bool useUserFaImage = true;
140  if (m_FaImage.IsNull())
141  {
142  m_FaImage = ItkFloatImgType::New();
143  m_FaImage->SetSpacing( inputImage->GetSpacing() );
144  m_FaImage->SetOrigin( inputImage->GetOrigin() );
145  m_FaImage->SetDirection( inputImage->GetDirection() );
146  m_FaImage->SetRegions( inputImage->GetLargestPossibleRegion() );
147  m_FaImage->Allocate();
148  m_FaImage->FillBuffer(0.0);
149  useUserFaImage = false;
150  }
151 
152  m_NumberOfInputs = 0;
153  for (unsigned int i=0; i<this->GetNumberOfIndexedInputs(); i++)
154  {
155  if (this->ProcessObject::GetInput(i)==NULL)
156  break;
157 
159  pdImage->SetSpacing( inputImage->GetSpacing() );
160  pdImage->SetOrigin( inputImage->GetOrigin() );
161  pdImage->SetDirection( inputImage->GetDirection() );
162  pdImage->SetRegions( inputImage->GetLargestPossibleRegion() );
163  pdImage->Allocate();
164  m_PdImage.push_back(pdImage);
165 
167  emaxImage->SetSpacing( inputImage->GetSpacing() );
168  emaxImage->SetOrigin( inputImage->GetOrigin() );
169  emaxImage->SetDirection( inputImage->GetDirection() );
170  emaxImage->SetRegions( inputImage->GetLargestPossibleRegion() );
171  emaxImage->Allocate();
172  emaxImage->FillBuffer(1.0);
173  m_EmaxImage.push_back(emaxImage);
174 
175  typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(i) );
176  m_InputImage.push_back(inputImage);
177 
178  m_NumberOfInputs++;
179  }
180  MITK_INFO << "Processing " << m_NumberOfInputs << " tensor files";
181 
182  typedef itk::DiffusionTensor3D<TTensorPixelType> TensorType;
183  typename TensorType::EigenValuesArrayType eigenvalues;
184  typename TensorType::EigenVectorsMatrixType eigenvectors;
185 
186 
187  for (int x=0; x<m_ImageSize[0]; x++)
188  for (int y=0; y<m_ImageSize[1]; y++)
189  for (int z=0; z<m_ImageSize[2]; z++)
190  {
191  typename InputImageType::IndexType index;
192  index[0] = x; index[1] = y; index[2] = z;
193  for (int i=0; i<m_NumberOfInputs; i++)
194  {
195  typename InputImageType::PixelType tensor = m_InputImage.at(i)->GetPixel(index);
196  vnl_vector_fixed<double,3> dir;
197  tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors);
198  dir[0] = eigenvectors(2, 0);
199  dir[1] = eigenvectors(2, 1);
200  dir[2] = eigenvectors(2, 2);
201  dir.normalize();
202  m_PdImage.at(i)->SetPixel(index, dir);
203  if (!useUserFaImage)
204  m_FaImage->SetPixel(index, m_FaImage->GetPixel(index)+tensor.GetFractionalAnisotropy());
205  m_EmaxImage.at(i)->SetPixel(index, 2/eigenvalues[2]);
206  }
207  if (!useUserFaImage)
208  m_FaImage->SetPixel(index, m_FaImage->GetPixel(index)/m_NumberOfInputs);
209  }
210 
211  if (m_Interpolate)
212  std::cout << "StreamlineTrackingFilter: using trilinear interpolation" << std::endl;
213  else
214  {
215  if (m_MinCurvatureRadius<0.0)
216  m_MinCurvatureRadius = 0.1*minSpacing;
217 
218  std::cout << "StreamlineTrackingFilter: using nearest neighbor interpolation" << std::endl;
219  }
220 
221  if (m_MinCurvatureRadius<0.0)
222  m_MinCurvatureRadius = 0.5*minSpacing;
223 
224  std::cout << "StreamlineTrackingFilter: Min. curvature radius: " << m_MinCurvatureRadius << std::endl;
225  std::cout << "StreamlineTrackingFilter: FA threshold: " << m_FaThreshold << std::endl;
226  std::cout << "StreamlineTrackingFilter: stepsize: " << m_StepSize << " mm" << std::endl;
227  std::cout << "StreamlineTrackingFilter: f: " << m_F << std::endl;
228  std::cout << "StreamlineTrackingFilter: g: " << m_G << std::endl;
229  std::cout << "StreamlineTrackingFilter: starting streamline tracking using " << this->GetNumberOfThreads() << " threads." << std::endl;
230 }
231 
232 template< class TTensorPixelType, class TPDPixelType>
234 ::CalculateNewPosition(itk::ContinuousIndex<double, 3>& pos, vnl_vector_fixed<double,3>& dir, typename InputImageType::IndexType& index)
235 {
236  vnl_matrix_fixed< double, 3, 3 > rot = m_InputImage.at(0)->GetDirection().GetTranspose();
237  dir = rot*dir;
238  if (true)
239  {
240  dir *= m_StepSize;
241  pos[0] += dir[0]/m_ImageSpacing[0];
242  pos[1] += dir[1]/m_ImageSpacing[1];
243  pos[2] += dir[2]/m_ImageSpacing[2];
244  index[0] = RoundToNearest(pos[0]);
245  index[1] = RoundToNearest(pos[1]);
246  index[2] = RoundToNearest(pos[2]);
247  }
248  else
249  {
250  dir[0] /= m_ImageSpacing[0];
251  dir[1] /= m_ImageSpacing[1];
252  dir[2] /= m_ImageSpacing[2];
253 
254  int smallest = 0;
255  double x = 100000;
256  if (dir[0]>0)
257  {
258  if (fabs(fabs(RoundToNearest(pos[0])-pos[0])-0.5)>mitk::eps)
259  x = fabs(pos[0]-RoundToNearest(pos[0])-0.5)/dir[0];
260  else
261  x = fabs(pos[0]-std::ceil(pos[0])-0.5)/dir[0];
262  }
263  else if (dir[0]<0)
264  {
265  if (fabs(fabs(RoundToNearest(pos[0])-pos[0])-0.5)>mitk::eps)
266  x = -fabs(pos[0]-RoundToNearest(pos[0])+0.5)/dir[0];
267  else
268  x = -fabs(pos[0]-std::floor(pos[0])+0.5)/dir[0];
269  }
270  double s = x;
271 
272  double y = 100000;
273  if (dir[1]>0)
274  {
275  if (fabs(fabs(RoundToNearest(pos[1])-pos[1])-0.5)>mitk::eps)
276  y = fabs(pos[1]-RoundToNearest(pos[1])-0.5)/dir[1];
277  else
278  y = fabs(pos[1]-std::ceil(pos[1])-0.5)/dir[1];
279  }
280  else if (dir[1]<0)
281  {
282  if (fabs(fabs(RoundToNearest(pos[1])-pos[1])-0.5)>mitk::eps)
283  y = -fabs(pos[1]-RoundToNearest(pos[1])+0.5)/dir[1];
284  else
285  y = -fabs(pos[1]-std::floor(pos[1])+0.5)/dir[1];
286  }
287  if (s>y)
288  {
289  s=y;
290  smallest = 1;
291  }
292 
293  double z = 100000;
294  if (dir[2]>0)
295  {
296  if (fabs(fabs(RoundToNearest(pos[2])-pos[2])-0.5)>mitk::eps)
297  z = fabs(pos[2]-RoundToNearest(pos[2])-0.5)/dir[2];
298  else
299  z = fabs(pos[2]-std::ceil(pos[2])-0.5)/dir[2];
300  }
301  else if (dir[2]<0)
302  {
303  if (fabs(fabs(RoundToNearest(pos[2])-pos[2])-0.5)>mitk::eps)
304  z = -fabs(pos[2]-RoundToNearest(pos[2])+0.5)/dir[2];
305  else
306  z = -fabs(pos[2]-std::floor(pos[2])+0.5)/dir[2];
307  }
308  if (s>z)
309  {
310  s=z;
311  smallest = 2;
312  }
313 
314  // MITK_INFO << "---------------------------------------------";
315  // MITK_INFO << "s: " << s;
316  // MITK_INFO << "dir: " << dir;
317  // MITK_INFO << "old: " << pos[0] << ", " << pos[1] << ", " << pos[2];
318 
319  pos[0] += dir[0]*s;
320  pos[1] += dir[1]*s;
321  pos[2] += dir[2]*s;
322 
323  switch (smallest)
324  {
325  case 0:
326  if (dir[0]<0)
327  index[0] = std::floor(pos[0]);
328  else
329  index[0] = std::ceil(pos[0]);
330  index[1] = RoundToNearest(pos[1]);
331  index[2] = RoundToNearest(pos[2]);
332  break;
333 
334  case 1:
335  if (dir[1]<0)
336  index[1] = std::floor(pos[1]);
337  else
338  index[1] = std::ceil(pos[1]);
339  index[0] = RoundToNearest(pos[0]);
340  index[2] = RoundToNearest(pos[2]);
341  break;
342 
343  case 2:
344  if (dir[2]<0)
345  index[2] = std::floor(pos[2]);
346  else
347  index[2] = std::ceil(pos[2]);
348  index[1] = RoundToNearest(pos[1]);
349  index[0] = RoundToNearest(pos[0]);
350  }
351 
352  // double x = 100000;
353  // if (dir[0]>0)
354  // x = fabs(pos[0]-RoundToNearest(pos[0])-0.5)/dir[0];
355  // else if (dir[0]<0)
356  // x = -fabs(pos[0]-RoundToNearest(pos[0])+0.5)/dir[0];
357  // double s = x;
358 
359  // double y = 100000;
360  // if (dir[1]>0)
361  // y = fabs(pos[1]-RoundToNearest(pos[1])-0.5)/dir[1];
362  // else if (dir[1]<0)
363  // y = -fabs(pos[1]-RoundToNearest(pos[1])+0.5)/dir[1];
364  // if (s>y)
365  // s=y;
366 
367  // double z = 100000;
368  // if (dir[2]>0)
369  // z = fabs(pos[2]-RoundToNearest(pos[2])-0.5)/dir[2];
370  // else if (dir[2]<0)
371  // z = -fabs(pos[2]-RoundToNearest(pos[2])+0.5)/dir[2];
372 
373  // if (s>z)
374  // s=z;
375  // s *= 1.001;
376 
377  // pos[0] += dir[0]*s;
378  // pos[1] += dir[1]*s;
379  // pos[2] += dir[2]*s;
380 
381  // index[0] = RoundToNearest(pos[0]);
382  // index[1] = RoundToNearest(pos[1]);
383  // index[2] = RoundToNearest(pos[2]);
384 
385  // MITK_INFO << "new: " << pos[0] << ", " << pos[1] << ", " << pos[2];
386  }
387 }
388 
389 template< class TTensorPixelType, class TPDPixelType>
391 ::IsValidPosition(itk::ContinuousIndex<double, 3>& pos, typename InputImageType::IndexType &index, vnl_vector_fixed< double, 8 >& interpWeights, int imageIdx)
392 {
393  if (!m_InputImage.at(imageIdx)->GetLargestPossibleRegion().IsInside(index) || m_MaskImage->GetPixel(index)==0)
394  return false;
395 
396  if (m_Interpolate)
397  {
398  double frac_x = pos[0] - index[0];
399  double frac_y = pos[1] - index[1];
400  double frac_z = pos[2] - index[2];
401 
402  if (frac_x<0)
403  {
404  index[0] -= 1;
405  frac_x += 1;
406  }
407  if (frac_y<0)
408  {
409  index[1] -= 1;
410  frac_y += 1;
411  }
412  if (frac_z<0)
413  {
414  index[2] -= 1;
415  frac_z += 1;
416  }
417 
418  frac_x = 1-frac_x;
419  frac_y = 1-frac_y;
420  frac_z = 1-frac_z;
421 
422  // int coordinates inside image?
423  if (index[0] < 0 || index[0] >= m_ImageSize[0]-1)
424  return false;
425  if (index[1] < 0 || index[1] >= m_ImageSize[1]-1)
426  return false;
427  if (index[2] < 0 || index[2] >= m_ImageSize[2]-1)
428  return false;
429 
430  interpWeights[0] = ( frac_x)*( frac_y)*( frac_z);
431  interpWeights[1] = (1-frac_x)*( frac_y)*( frac_z);
432  interpWeights[2] = ( frac_x)*(1-frac_y)*( frac_z);
433  interpWeights[3] = ( frac_x)*( frac_y)*(1-frac_z);
434  interpWeights[4] = (1-frac_x)*(1-frac_y)*( frac_z);
435  interpWeights[5] = ( frac_x)*(1-frac_y)*(1-frac_z);
436  interpWeights[6] = (1-frac_x)*( frac_y)*(1-frac_z);
437  interpWeights[7] = (1-frac_x)*(1-frac_y)*(1-frac_z);
438 
439  typename InputImageType::IndexType tmpIdx;
440  double FA = m_FaImage->GetPixel(index) * interpWeights[0];
441  tmpIdx = index; tmpIdx[0]++;
442  FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[1];
443  tmpIdx = index; tmpIdx[1]++;
444  FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[2];
445  tmpIdx = index; tmpIdx[2]++;
446  FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[3];
447  tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++;
448  FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[4];
449  tmpIdx = index; tmpIdx[1]++; tmpIdx[2]++;
450  FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[5];
451  tmpIdx = index; tmpIdx[2]++; tmpIdx[0]++;
452  FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[6];
453  tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++;
454  FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[7];
455 
456  if (FA<m_FaThreshold)
457  return false;
458  }
459  else if (m_FaImage->GetPixel(index)<m_FaThreshold)
460  return false;
461 
462  return true;
463 }
464 
465 template< class TTensorPixelType, class TPDPixelType>
467 ::FollowStreamline(itk::ContinuousIndex<double, 3> pos, int dirSign, vtkPoints* points, std::vector< vtkIdType >& ids, int imageIdx)
468 {
469  double tractLength = 0;
470  typedef itk::DiffusionTensor3D<TTensorPixelType> TensorType;
471  typename TensorType::EigenValuesArrayType eigenvalues;
472  typename TensorType::EigenVectorsMatrixType eigenvectors;
473  vnl_vector_fixed< double, 8 > interpWeights;
474 
475  typename InputImageType::IndexType index, indexOld;
476  indexOld[0] = -1; indexOld[1] = -1; indexOld[2] = -1;
477  itk::Point<double> worldPos;
478  double distance = 0;
479  double distanceInVoxel = 0;
480 
481  // starting index and direction
482  index[0] = RoundToNearest(pos[0]);
483  index[1] = RoundToNearest(pos[1]);
484  index[2] = RoundToNearest(pos[2]);
485 
486  vnl_vector_fixed<double,3> dir = m_PdImage.at(imageIdx)->GetPixel(index);
487  dir *= dirSign; // reverse direction
488  vnl_vector_fixed<double,3> dirOld = dir;
489  if (dir.magnitude()<mitk::eps)
490  return tractLength;
491 
492  for (int step=0; step< m_MaxLength/2; step++)
493  {
494  // get new position
495  CalculateNewPosition(pos, dir, index);
496  distance += m_StepSize;
497 
498  // is new position valid (inside image, above FA threshold etc.)
499  if (!IsValidPosition(pos, index, interpWeights, imageIdx)) // if not end streamline
500  {
501 // m_SeedImage->TransformContinuousIndexToPhysicalPoint( pos, worldPos );
502 // ids.push_back(points->InsertNextPoint(worldPos.GetDataPointer()));
503  return tractLength;
504  }
505  else if (distance>=m_PointPistance)
506  {
507  tractLength += m_StepSize;
508  distanceInVoxel += m_StepSize;
509  m_SeedImage->TransformContinuousIndexToPhysicalPoint( pos, worldPos );
510  ids.push_back(points->InsertNextPoint(worldPos.GetDataPointer()));
511  distance = 0;
512  }
513 
514  if (!m_Interpolate) // use nearest neighbour interpolation
515  {
516  if (indexOld!=index) // did we enter a new voxel? if yes, calculate new direction
517  {
518  double minAngle = 0;
519  for (int img=0; img<m_NumberOfInputs; img++)
520  {
521  vnl_vector_fixed<double,3> newDir = m_PdImage.at(img)->GetPixel(index); // get principal direction
522  if (newDir.magnitude()<mitk::eps)
523  continue;
524 
525  typename InputImageType::PixelType tensor = m_InputImage.at(img)->GetPixel(index);
526  double scale = m_EmaxImage.at(img)->GetPixel(index);
527  newDir[0] = m_F*newDir[0] + (1-m_F)*( (1-m_G)*dirOld[0] + scale*m_G*(tensor[0]*dirOld[0] + tensor[1]*dirOld[1] + tensor[2]*dirOld[2]));
528  newDir[1] = m_F*newDir[1] + (1-m_F)*( (1-m_G)*dirOld[1] + scale*m_G*(tensor[1]*dirOld[0] + tensor[3]*dirOld[1] + tensor[4]*dirOld[2]));
529  newDir[2] = m_F*newDir[2] + (1-m_F)*( (1-m_G)*dirOld[2] + scale*m_G*(tensor[2]*dirOld[0] + tensor[4]*dirOld[1] + tensor[5]*dirOld[2]));
530  newDir.normalize();
531 
532  double angle = dot_product(dirOld, newDir);
533  if (angle<0)
534  {
535  newDir *= -1;
536  angle *= -1;
537  }
538 
539  if (angle>minAngle)
540  {
541  minAngle = angle;
542  dir = newDir;
543  }
544  }
545 
546  //double r = m_StepSize/(2*std::asin(std::acos(minAngle)/2));
547  vnl_vector_fixed<double,3> v3 = dir+dirOld; v3 *= m_StepSize;
548  double a = m_StepSize;
549  double b = m_StepSize;
550  double c = v3.magnitude();
551  double r = a*b*c/std::sqrt((a+b+c)*(a+b-c)*(b+c-a)*(a-b+c)); // radius of triangle via Heron's formula (area of triangle)
552 
553  if (r<m_MinCurvatureRadius)
554  {
555  return tractLength;
556  }
557  dirOld = dir;
558  indexOld = index;
559  distanceInVoxel = 0;
560  }
561  else
562  dir = dirOld;
563  }
564  else // use trilinear interpolation (weights calculated in IsValidPosition())
565  {
566  typename InputImageType::PixelType tensor;
567 
568  typename InputImageType::IndexType tmpIdx = index;
569  typename InputImageType::PixelType tmpTensor;
570 
571  if (m_NumberOfInputs>1)
572  {
573  double minAngle = 0;
574  for (int img=0; img<m_NumberOfInputs; img++)
575  {
576  double angle = dot_product(dirOld, m_PdImage.at(img)->GetPixel(tmpIdx));
577  if (fabs(angle)>minAngle)
578  {
579  minAngle = angle;
580  tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx);
581  }
582  }
583  tensor = tmpTensor * interpWeights[0];
584 
585  minAngle = 0;
586  tmpIdx = index; tmpIdx[0]++;
587  for (int img=0; img<m_NumberOfInputs; img++)
588  {
589  double angle = dot_product(dirOld, m_PdImage.at(img)->GetPixel(tmpIdx));
590  if (fabs(angle)>minAngle)
591  {
592  minAngle = angle;
593  tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx);
594  }
595  }
596  tensor += tmpTensor * interpWeights[1];
597 
598  minAngle = 0;
599  tmpIdx = index; tmpIdx[1]++;
600  for (int img=0; img<m_NumberOfInputs; img++)
601  {
602  double angle = dot_product(dirOld, m_PdImage.at(img)->GetPixel(tmpIdx));
603  if (fabs(angle)>minAngle)
604  {
605  minAngle = angle;
606  tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx);
607  }
608  }
609  tensor += tmpTensor * interpWeights[2];
610 
611  minAngle = 0;
612  tmpIdx = index; tmpIdx[2]++;
613  for (int img=0; img<m_NumberOfInputs; img++)
614  {
615  double angle = dot_product(dirOld, m_PdImage.at(img)->GetPixel(tmpIdx));
616  if (fabs(angle)>minAngle)
617  {
618  minAngle = angle;
619  tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx);
620  }
621  }
622  tensor += tmpTensor * interpWeights[3];
623 
624  minAngle = 0;
625  tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++;
626  for (int img=0; img<m_NumberOfInputs; img++)
627  {
628  double angle = dot_product(dirOld, m_PdImage.at(img)->GetPixel(tmpIdx));
629  if (fabs(angle)>minAngle)
630  {
631  minAngle = angle;
632  tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx);
633  }
634  }
635  tensor += tmpTensor * interpWeights[4];
636 
637  minAngle = 0;
638  tmpIdx = index; tmpIdx[1]++; tmpIdx[2]++;
639  for (int img=0; img<m_NumberOfInputs; img++)
640  {
641  double angle = dot_product(dirOld, m_PdImage.at(img)->GetPixel(tmpIdx));
642  if (fabs(angle)>minAngle)
643  {
644  minAngle = angle;
645  tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx);
646  }
647  }
648  tensor += tmpTensor * interpWeights[5];
649 
650  minAngle = 0;
651  tmpIdx = index; tmpIdx[2]++; tmpIdx[0]++;
652  for (int img=0; img<m_NumberOfInputs; img++)
653  {
654  double angle = dot_product(dirOld, m_PdImage.at(img)->GetPixel(tmpIdx));
655  if (fabs(angle)>minAngle)
656  {
657  minAngle = angle;
658  tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx);
659  }
660  }
661  tensor += tmpTensor * interpWeights[6];
662 
663  minAngle = 0;
664  tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++;
665  for (int img=0; img<m_NumberOfInputs; img++)
666  {
667  double angle = dot_product(dirOld, m_PdImage.at(img)->GetPixel(tmpIdx));
668  if (fabs(angle)>minAngle)
669  {
670  minAngle = angle;
671  tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx);
672  }
673  }
674  tensor += tmpTensor * interpWeights[7];
675  }
676  else
677  {
678  tensor = m_InputImage.at(0)->GetPixel(index) * interpWeights[0];
679  typename InputImageType::IndexType tmpIdx = index; tmpIdx[0]++;
680  tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[1];
681  tmpIdx = index; tmpIdx[1]++;
682  tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[2];
683  tmpIdx = index; tmpIdx[2]++;
684  tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[3];
685  tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++;
686  tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[4];
687  tmpIdx = index; tmpIdx[1]++; tmpIdx[2]++;
688  tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[5];
689  tmpIdx = index; tmpIdx[2]++; tmpIdx[0]++;
690  tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[6];
691  tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++;
692  tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[7];
693  }
694 
695  tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors);
696  dir[0] = eigenvectors(2, 0);
697  dir[1] = eigenvectors(2, 1);
698  dir[2] = eigenvectors(2, 2);
699  if (dir.magnitude()<mitk::eps)
700  continue;
701  dir.normalize();
702 
703  double scale = 2/eigenvalues[2];
704  dir[0] = m_F*dir[0] + (1-m_F)*( (1-m_G)*dirOld[0] + scale*m_G*(tensor[0]*dirOld[0] + tensor[1]*dirOld[1] + tensor[2]*dirOld[2]));
705  dir[1] = m_F*dir[1] + (1-m_F)*( (1-m_G)*dirOld[1] + scale*m_G*(tensor[1]*dirOld[0] + tensor[3]*dirOld[1] + tensor[4]*dirOld[2]));
706  dir[2] = m_F*dir[2] + (1-m_F)*( (1-m_G)*dirOld[2] + scale*m_G*(tensor[2]*dirOld[0] + tensor[4]*dirOld[1] + tensor[5]*dirOld[2]));
707  dir.normalize();
708 
709  double angle = dot_product(dirOld, dir);
710  if (angle<0)
711  {
712  dir *= -1;
713  angle *= -1;
714  }
715 
716  vnl_vector_fixed<double,3> v3 = dir+dirOld; v3 *= m_StepSize;
717  double a = m_StepSize;
718  double b = m_StepSize;
719  double c = v3.magnitude();
720  double r = a*b*c/std::sqrt((a+b+c)*(a+b-c)*(b+c-a)*(a-b+c)); // radius of triangle via Heron's formula (area of triangle)
721 
722  if (r<m_MinCurvatureRadius)
723  return tractLength;
724 
725  dirOld = dir;
726  indexOld = index;
727  }
728  }
729  return tractLength;
730 }
731 
732 template< class TTensorPixelType,
733  class TPDPixelType>
735 TPDPixelType>
736 ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread,
737  ThreadIdType threadId)
738 {
739  FiberPolyDataType poly = m_PolyDataContainer->GetElement(threadId);
740  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
741  vtkSmartPointer<vtkCellArray> Cells = vtkSmartPointer<vtkCellArray>::New();
742 
743  typedef itk::DiffusionTensor3D<TTensorPixelType> TensorType;
744  typedef ImageRegionConstIterator< InputImageType > InputIteratorType;
745  typedef ImageRegionConstIterator< ItkUcharImgType > MaskIteratorType;
746  typedef ImageRegionConstIterator< ItkFloatImgType > doubleIteratorType;
747  typedef typename InputImageType::PixelType InputTensorType;
748 
749  MaskIteratorType sit(m_SeedImage, outputRegionForThread );
750  doubleIteratorType fit(m_FaImage, outputRegionForThread );
751  MaskIteratorType mit(m_MaskImage, outputRegionForThread );
752 
753  for (int img=0; img<m_NumberOfInputs; img++)
754  {
755  sit.GoToBegin();
756  mit.GoToBegin();
757  fit.GoToBegin();
758  itk::Point<double> worldPos;
759  while( !sit.IsAtEnd() )
760  {
761  if (sit.Value()==0 || fit.Value()<m_FaThreshold || mit.Value()==0)
762  {
763  ++sit;
764  ++mit;
765  ++fit;
766  continue;
767  }
768 
769  for (int s=0; s<m_SeedsPerVoxel; s++)
770  {
771  vtkSmartPointer<vtkPolyLine> line = vtkSmartPointer<vtkPolyLine>::New();
772  std::vector< vtkIdType > pointIDs;
773  typename InputImageType::IndexType index = sit.GetIndex();
774  itk::ContinuousIndex<double, 3> start;
775  unsigned int counter = 0;
776 
777  if (m_SeedsPerVoxel>1)
778  {
779  start[0] = index[0]+(double)(rand()%99-49)/100;
780  start[1] = index[1]+(double)(rand()%99-49)/100;
781  start[2] = index[2]+(double)(rand()%99-49)/100;
782  }
783  else
784  {
785  start[0] = index[0];
786  start[1] = index[1];
787  start[2] = index[2];
788  }
789 
790  // forward tracking
791  double tractLength = FollowStreamline(start, 1, points, pointIDs, img);
792 
793  // add ids to line
794  counter += pointIDs.size();
795  while (!pointIDs.empty())
796  {
797  line->GetPointIds()->InsertNextId(pointIDs.back());
798  pointIDs.pop_back();
799  }
800 
801  // insert start point
802  m_SeedImage->TransformContinuousIndexToPhysicalPoint( start, worldPos );
803  line->GetPointIds()->InsertNextId(points->InsertNextPoint(worldPos.GetDataPointer()));
804 
805  // backward tracking
806  tractLength += FollowStreamline(start, -1, points, pointIDs, img);
807 
808  counter += pointIDs.size();
809 
810  //MITK_INFO << "Tract length " << tractLength;
811 
812  if (tractLength<m_MinTractLength || counter<2)
813  continue;
814 
815  // add ids to line
816  for (unsigned int i=0; i<pointIDs.size(); i++)
817  line->GetPointIds()->InsertNextId(pointIDs.at(i));
818 
819  Cells->InsertNextCell(line);
820  }
821  ++sit;
822  ++mit;
823  ++fit;
824  }
825  }
826  poly->SetPoints(points);
827  poly->SetLines(Cells);
828 
829  std::cout << "Thread " << threadId << " finished tracking" << std::endl;
830 }
831 
832 template< class TTensorPixelType,
833  class TPDPixelType>
834 vtkSmartPointer< vtkPolyData > StreamlineTrackingFilter< TTensorPixelType,
835 TPDPixelType>
836 ::AddPolyData(FiberPolyDataType poly1, FiberPolyDataType poly2)
837 {
838  vtkSmartPointer<vtkPolyData> vNewPolyData = vtkSmartPointer<vtkPolyData>::New();
839  vtkSmartPointer<vtkCellArray> vNewLines = poly1->GetLines();
840  vtkSmartPointer<vtkPoints> vNewPoints = poly1->GetPoints();
841 
842  for( int i=0; i<poly2->GetNumberOfLines(); i++ )
843  {
844  vtkCell* cell = poly2->GetCell(i);
845  int numPoints = cell->GetNumberOfPoints();
846  vtkPoints* points = cell->GetPoints();
847 
848  vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
849  for (int j=0; j<numPoints; j++)
850  {
851  double p[3];
852  points->GetPoint(j, p);
853 
854  vtkIdType id = vNewPoints->InsertNextPoint(p);
855  container->GetPointIds()->InsertNextId(id);
856  }
857  vNewLines->InsertNextCell(container);
858  }
859 
860  // initialize polydata
861  vNewPolyData->SetPoints(vNewPoints);
862  vNewPolyData->SetLines(vNewLines);
863 
864  return vNewPolyData;
865 }
866 template< class TTensorPixelType,
867  class TPDPixelType>
869 TPDPixelType>
870 ::AfterThreadedGenerateData()
871 {
872  MITK_INFO << "Generating polydata ";
873  m_FiberPolyData = m_PolyDataContainer->GetElement(0);
874  for (unsigned int i=1; i<this->GetNumberOfThreads(); i++)
875  {
876  m_FiberPolyData = AddPolyData(m_FiberPolyData, m_PolyDataContainer->GetElement(i));
877  }
878  MITK_INFO << "done";
879 }
880 
881 template< class TTensorPixelType,
882  class TPDPixelType>
884 TPDPixelType>
885 ::PrintSelf(std::ostream&, Indent) const
886 {
887 }
888 
889 }
890 #endif // __itkDiffusionQballPrincipleDirectionsImageFilter_txx
static char * line
Definition: svm.cpp:2884
itk::SmartPointer< Self > Pointer
Performes deterministic streamline tracking on the input tensor image.
void CalculateNewPosition(itk::ContinuousIndex< double, 3 > &pos, vnl_vector_fixed< double, 3 > &dir, typename InputImageType::IndexType &index)
Calculate next integration step.
#define MITK_INFO
Definition: mitkLogMacros.h:22
double FollowStreamline(itk::ContinuousIndex< double, 3 > pos, int dirSign, vtkPoints *points, std::vector< vtkIdType > &ids, int imageIdx)
Start streamline in one direction.
Superclass::InputImageType InputImageType
double TTensorPixelType
vtkSmartPointer< vtkPolyData > FiberPolyDataType
bool IsValidPosition(itk::ContinuousIndex< double, 3 > &pos, typename InputImageType::IndexType &index, vnl_vector_fixed< double, 8 > &interpWeights, int imageIdx)
Are we outside of the mask image? Is the FA too low?
MITKCORE_EXPORT const ScalarType eps
unsigned short PixelType
Superclass::OutputImageRegionType OutputImageRegionType
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.