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
itkTractsToVectorImageFilter.cpp
Go to the documentation of this file.
2 
3 // VTK
4 #include <vtkPolyLine.h>
5 #include <vtkCellArray.h>
6 #include <vtkCellData.h>
7 
8 // ITK
9 #include <itkTimeProbe.h>
10 #include <itkImageRegionIterator.h>
11 
12 // misc
13 #define _USE_MATH_DEFINES
14 #include <math.h>
15 #include <boost/progress.hpp>
16 
17 
18 namespace itk{
19 
20 static bool CompareVectorLengths(const vnl_vector_fixed< double, 3 >& v1, const vnl_vector_fixed< double, 3 >& v2)
21 {
22  return (v1.magnitude()>v2.magnitude());
23 }
24 
25 template< class PixelType >
27  m_AngularThreshold(0.7),
28  m_Epsilon(0.999),
29  m_MaskImage(NULL),
30  m_NormalizeVectors(false),
31  m_UseWorkingCopy(true),
32  m_MaxNumDirections(3),
33  m_SizeThreshold(0.3),
34  m_NumDirectionsImage(NULL),
35  m_CreateDirectionImages(true)
36 {
37  this->SetNumberOfRequiredOutputs(1);
38 }
39 
40 
41 template< class PixelType >
43 {
44 }
45 
46 
47 template< class PixelType >
48 vnl_vector_fixed<double, 3> TractsToVectorImageFilter< PixelType >::GetVnlVector(double point[])
49 {
50  vnl_vector_fixed<double, 3> vnlVector;
51  vnlVector[0] = point[0];
52  vnlVector[1] = point[1];
53  vnlVector[2] = point[2];
54  return vnlVector;
55 }
56 
57 
58 template< class PixelType >
59 itk::Point<double, 3> TractsToVectorImageFilter< PixelType >::GetItkPoint(double point[])
60 {
61  itk::Point<double, 3> itkPoint;
62  itkPoint[0] = point[0];
63  itkPoint[1] = point[1];
64  itkPoint[2] = point[2];
65  return itkPoint;
66 }
67 
68 template< class PixelType >
70 {
71  mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry();
72 
73  // calculate new image parameters
74  itk::Vector<double> spacing;
75  itk::Point<double> origin;
76  itk::Matrix<double, 3, 3> direction;
77  ImageRegion<3> imageRegion;
78  if (!m_MaskImage.IsNull())
79  {
80  spacing = m_MaskImage->GetSpacing();
81  imageRegion = m_MaskImage->GetLargestPossibleRegion();
82  origin = m_MaskImage->GetOrigin();
83  direction = m_MaskImage->GetDirection();
84  }
85  else
86  {
87  spacing = geometry->GetSpacing();
88  origin = geometry->GetOrigin();
89  mitk::BaseGeometry::BoundsArrayType bounds = geometry->GetBounds();
90  origin[0] += bounds.GetElement(0);
91  origin[1] += bounds.GetElement(2);
92  origin[2] += bounds.GetElement(4);
93 
94  for (int i=0; i<3; i++)
95  for (int j=0; j<3; j++)
96  direction[j][i] = geometry->GetMatrixColumn(i)[j];
97  imageRegion.SetSize(0, geometry->GetExtent(0));
98  imageRegion.SetSize(1, geometry->GetExtent(1));
99  imageRegion.SetSize(2, geometry->GetExtent(2));
100 
101 
102  m_MaskImage = ItkUcharImgType::New();
103  m_MaskImage->SetSpacing( spacing );
104  m_MaskImage->SetOrigin( origin );
105  m_MaskImage->SetDirection( direction );
106  m_MaskImage->SetRegions( imageRegion );
107  m_MaskImage->Allocate();
108  m_MaskImage->FillBuffer(1);
109  }
110  OutputImageType::RegionType::SizeType outImageSize = imageRegion.GetSize();
111  m_OutImageSpacing = m_MaskImage->GetSpacing();
112  m_ClusteredDirectionsContainer = ContainerType::New();
113 
114  // initialize num directions image
115  m_NumDirectionsImage = ItkUcharImgType::New();
116  m_NumDirectionsImage->SetSpacing( spacing );
117  m_NumDirectionsImage->SetOrigin( origin );
118  m_NumDirectionsImage->SetDirection( direction );
119  m_NumDirectionsImage->SetRegions( imageRegion );
120  m_NumDirectionsImage->Allocate();
121  m_NumDirectionsImage->FillBuffer(0);
122 
123  // initialize direction images
124  m_DirectionImageContainer = DirectionImageContainerType::New();
125 
126  // resample fiber bundle
127  double minSpacing = 1;
128  if(m_OutImageSpacing[0]<m_OutImageSpacing[1] && m_OutImageSpacing[0]<m_OutImageSpacing[2])
129  minSpacing = m_OutImageSpacing[0];
130  else if (m_OutImageSpacing[1] < m_OutImageSpacing[2])
131  minSpacing = m_OutImageSpacing[1];
132  else
133  minSpacing = m_OutImageSpacing[2];
134 
135  if (m_UseWorkingCopy)
136  m_FiberBundle = m_FiberBundle->GetDeepCopy();
137 
138  // resample fiber bundle for sufficient voxel coverage
139  m_FiberBundle->ResampleSpline(minSpacing/10);
140 
141  // iterate over all fibers
142  vtkSmartPointer<vtkPolyData> fiberPolyData = m_FiberBundle->GetFiberPolyData();
143  int numFibers = m_FiberBundle->GetNumFibers();
144  m_DirectionsContainer = ContainerType::New();
145 
146  VectorContainer< unsigned int, std::vector< double > >::Pointer peakLengths = VectorContainer< unsigned int, std::vector< double > >::New();
147 
148  MITK_INFO << "Generating directions from tractogram";
149  boost::progress_display disp(numFibers);
150  for( int i=0; i<numFibers; i++ )
151  {
152  ++disp;
153  vtkCell* cell = fiberPolyData->GetCell(i);
154  int numPoints = cell->GetNumberOfPoints();
155  vtkPoints* points = cell->GetPoints();
156  if (numPoints<2)
157  continue;
158 
159  vnl_vector_fixed<double, 3> dir;
160  itk::Point<double, 3> worldPos;
161  vnl_vector<double> v;
162 
163 
164  float fiberWeight = m_FiberBundle->GetFiberWeight(i);
165 
166  for( int j=0; j<numPoints-1; j++)
167  {
168  // get current position along fiber in world coordinates
169  double* temp = points->GetPoint(j);
170  worldPos = GetItkPoint(temp);
171  itk::Index<3> index;
172  m_MaskImage->TransformPhysicalPointToIndex(worldPos, index);
173  if (!m_MaskImage->GetLargestPossibleRegion().IsInside(index) || m_MaskImage->GetPixel(index)==0)
174  continue;
175 
176  // get fiber tangent direction at this position
177  v = GetVnlVector(temp);
178  dir = GetVnlVector(points->GetPoint(j+1))-v;
179  if (dir.is_zero())
180  continue;
181  dir.normalize();
182 
183  // add direction to container
184  unsigned int idx = index[0] + outImageSize[0]*(index[1] + outImageSize[1]*index[2]);
186  if (m_DirectionsContainer->IndexExists(idx))
187  {
188  peakLengths->ElementAt(idx).push_back(fiberWeight);
189 
190  dirCont = m_DirectionsContainer->GetElement(idx);
191  if (dirCont.IsNull())
192  {
193  dirCont = DirectionContainerType::New();
194  dirCont->push_back(dir);
195  m_DirectionsContainer->InsertElement(idx, dirCont);
196  }
197  else
198  dirCont->push_back(dir);
199  }
200  else
201  {
202  dirCont = DirectionContainerType::New();
203  dirCont->push_back(dir);
204  m_DirectionsContainer->InsertElement(idx, dirCont);
205 
206  std::vector< double > lengths; lengths.push_back(fiberWeight);
207  peakLengths->InsertElement(idx, lengths);
208  }
209  }
210  }
211 
212  vtkSmartPointer<vtkCellArray> m_VtkCellArray = vtkSmartPointer<vtkCellArray>::New();
213  vtkSmartPointer<vtkPoints> m_VtkPoints = vtkSmartPointer<vtkPoints>::New();
214 
215  itk::ImageRegionIterator<ItkUcharImgType> dirIt(m_NumDirectionsImage, m_NumDirectionsImage->GetLargestPossibleRegion());
216 
217  MITK_INFO << "Clustering directions";
218  boost::progress_display disp2(outImageSize[0]*outImageSize[1]*outImageSize[2]);
219  while(!dirIt.IsAtEnd())
220  {
221  ++disp2;
222  OutputImageType::IndexType index = dirIt.GetIndex();
223  int idx = index[0]+(index[1]+index[2]*outImageSize[1])*outImageSize[0];
224 
225  if (!m_DirectionsContainer->IndexExists(idx))
226  {
227  ++dirIt;
228  continue;
229  }
230  DirectionContainerType::Pointer dirCont = m_DirectionsContainer->GetElement(idx);
231  if (dirCont.IsNull() || dirCont->empty())
232  {
233  ++dirIt;
234  continue;
235  }
236 
237 // std::vector< double > lengths; lengths.resize(dirCont->size(), 1); // all peaks have size 1
239  if (m_MaxNumDirections>0)
240  {
241  directions = FastClustering(dirCont, peakLengths->GetElement(idx));
242  std::sort( directions->begin(), directions->end(), CompareVectorLengths );
243  }
244  else
245  directions = dirCont;
246 
247  unsigned int numDir = directions->size();
248  if (m_MaxNumDirections>0 && numDir>m_MaxNumDirections)
249  numDir = m_MaxNumDirections;
250 
251  int count = 0;
252  for (unsigned int i=0; i<numDir; i++)
253  {
254  vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
255  itk::ContinuousIndex<double, 3> center;
256  center[0] = index[0];
257  center[1] = index[1];
258  center[2] = index[2];
259  itk::Point<double> worldCenter;
260  m_MaskImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter );
261  DirectionType dir = directions->at(i);
262 
263  if (dir.magnitude()<m_SizeThreshold)
264  continue;
265  if (m_NormalizeVectors)
266  dir.normalize();
267  count++;
268 
269  if (m_CreateDirectionImages && i<10)
270  {
271  if (i==m_DirectionImageContainer->size())
272  {
274  directionImage->SetSpacing( spacing );
275  directionImage->SetOrigin( origin );
276  directionImage->SetDirection( direction );
277  directionImage->SetRegions( imageRegion );
278  directionImage->Allocate();
279  Vector< float, 3 > nullVec; nullVec.Fill(0.0);
280  directionImage->FillBuffer(nullVec);
281  m_DirectionImageContainer->InsertElement(i, directionImage);
282  }
283 
284  // set direction image pixel
285  ItkDirectionImageType::Pointer directionImage = m_DirectionImageContainer->GetElement(i);
286  Vector< float, 3 > pixel;
287  pixel.SetElement(0, dir[0]);
288  pixel.SetElement(1, dir[1]);
289  pixel.SetElement(2, dir[2]);
290  directionImage->SetPixel(index, pixel);
291  }
292 
293  // add direction to vector field (with spacing compensation)
294  itk::Point<double> worldStart;
295  worldStart[0] = worldCenter[0]-dir[0]/2*minSpacing;
296  worldStart[1] = worldCenter[1]-dir[1]/2*minSpacing;
297  worldStart[2] = worldCenter[2]-dir[2]/2*minSpacing;
298  vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer());
299  container->GetPointIds()->InsertNextId(id);
300  itk::Point<double> worldEnd;
301  worldEnd[0] = worldCenter[0]+dir[0]/2*minSpacing;
302  worldEnd[1] = worldCenter[1]+dir[1]/2*minSpacing;
303  worldEnd[2] = worldCenter[2]+dir[2]/2*minSpacing;
304  id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer());
305  container->GetPointIds()->InsertNextId(id);
306  m_VtkCellArray->InsertNextCell(container);
307  }
308  dirIt.Set(count);
309  ++dirIt;
310  }
311 
312  vtkSmartPointer<vtkPolyData> directionsPolyData = vtkSmartPointer<vtkPolyData>::New();
313  directionsPolyData->SetPoints(m_VtkPoints);
314  directionsPolyData->SetLines(m_VtkCellArray);
315  m_OutputFiberBundle = mitk::FiberBundle::New(directionsPolyData);
316 }
317 
318 
319 template< class PixelType >
321 {
323  if (inDirs->size()<2)
324  return inDirs;
325 
326  DirectionType oldMean, currentMean;
327  std::vector< int > touched;
328 
329  // initialize
330  touched.resize(inDirs->size(), 0);
331  bool free = true;
332  currentMean = inDirs->at(0); // initialize first seed
333  currentMean.normalize();
334  double length = lengths.at(0);
335  touched[0] = 1;
336  std::vector< double > newLengths;
337  bool meanChanged = false;
338 
339  double max = 0;
340  while (free)
341  {
342  oldMean.fill(0.0);
343 
344  // start mean-shift clustering
345  double angle = 0;
346 
347  while (fabs(dot_product(currentMean, oldMean))<0.99)
348  {
349  oldMean = currentMean;
350  currentMean.fill(0.0);
351  for (unsigned int i=0; i<inDirs->size(); i++)
352  {
353  angle = dot_product(oldMean, inDirs->at(i));
354  if (angle>=m_AngularThreshold)
355  {
356  currentMean += inDirs->at(i);
357  if (meanChanged)
358  length += lengths.at(i);
359  touched[i] = 1;
360  meanChanged = true;
361  }
362  else if (-angle>=m_AngularThreshold)
363  {
364  currentMean -= inDirs->at(i);
365  if (meanChanged)
366  length += lengths.at(i);
367  touched[i] = 1;
368  meanChanged = true;
369  }
370  }
371  if(!meanChanged)
372  currentMean = oldMean;
373  else
374  currentMean.normalize();
375  }
376 
377  // found stable mean
378  outDirs->push_back(currentMean);
379  newLengths.push_back(length);
380  if (length>max)
381  max = length;
382 
383  // find next unused seed
384  free = false;
385  for (unsigned int i=0; i<touched.size(); i++)
386  if (touched[i]==0)
387  {
388  currentMean = inDirs->at(i);
389  free = true;
390  meanChanged = false;
391  length = lengths.at(i);
392  touched[i] = 1;
393  break;
394  }
395  }
396 
397  if (inDirs->size()==outDirs->size())
398  {
399  if (max>0)
400  for (unsigned int i=0; i<outDirs->size(); i++)
401  outDirs->SetElement(i, outDirs->at(i)*newLengths.at(i)/max);
402  return outDirs;
403  }
404  else
405  return FastClustering(outDirs, newLengths);
406 }
407 
408 
409 //template< class PixelType >
410 //std::vector< DirectionType > TractsToVectorImageFilter< PixelType >::Clustering(std::vector< DirectionType >& inDirs)
411 //{
412 // std::vector< DirectionType > outDirs;
413 // if (inDirs.empty())
414 // return outDirs;
415 // DirectionType oldMean, currentMean, workingMean;
416 
417 // std::vector< DirectionType > normalizedDirs;
418 // std::vector< int > touched;
419 // for (std::size_t i=0; i<inDirs.size(); i++)
420 // {
421 // normalizedDirs.push_back(inDirs[i]);
422 // normalizedDirs.back().normalize();
423 // }
424 
425 // // initialize
426 // double max = 0.0;
427 // touched.resize(inDirs.size(), 0);
428 // for (std::size_t j=0; j<inDirs.size(); j++)
429 // {
430 // currentMean = inDirs[j];
431 // oldMean.fill(0.0);
432 
433 // // start mean-shift clustering
434 // double angle = 0.0;
435 // int counter = 0;
436 // while ((currentMean-oldMean).magnitude()>0.0001)
437 // {
438 // counter = 0;
439 // oldMean = currentMean;
440 // workingMean = oldMean;
441 // workingMean.normalize();
442 // currentMean.fill(0.0);
443 // for (std::size_t i=0; i<normalizedDirs.size(); i++)
444 // {
445 // angle = dot_product(workingMean, normalizedDirs[i]);
446 // if (angle>=m_AngularThreshold)
447 // {
448 // currentMean += inDirs[i];
449 // counter++;
450 // }
451 // else if (-angle>=m_AngularThreshold)
452 // {
453 // currentMean -= inDirs[i];
454 // counter++;
455 // }
456 // }
457 // }
458 
459 // // found stable mean
460 // if (counter>0)
461 // {
462 // bool add = true;
463 // DirectionType normMean = currentMean;
464 // normMean.normalize();
465 // for (std::size_t i=0; i<outDirs.size(); i++)
466 // {
467 // DirectionType dir = outDirs[i];
468 // dir.normalize();
469 // if ((normMean-dir).magnitude()<=0.0001)
470 // {
471 // add = false;
472 // break;
473 // }
474 // }
475 
476 // currentMean /= counter;
477 // if (add)
478 // {
479 // double mag = currentMean.magnitude();
480 // if (mag>0)
481 // {
482 // if (mag>max)
483 // max = mag;
484 
485 // outDirs.push_back(currentMean);
486 // }
487 // }
488 // }
489 // }
490 
491 // if (m_NormalizeVectors)
492 // for (std::size_t i=0; i<outDirs.size(); i++)
493 // outDirs[i].normalize();
494 // else if (max>0)
495 // for (std::size_t i=0; i<outDirs.size(); i++)
496 // outDirs[i] /= max;
497 
498 // if (inDirs.size()==outDirs.size())
499 // return outDirs;
500 // else
501 // return FastClustering(outDirs);
502 //}
503 
504 
505 //template< class PixelType >
506 //TractsToVectorImageFilter< PixelType >::DirectionContainerType::Pointer TractsToVectorImageFilter< PixelType >::MeanShiftClustering(DirectionContainerType::Pointer dirCont)
507 //{
508 // DirectionContainerType::Pointer container = DirectionContainerType::New();
509 
510 // double max = 0;
511 // for (DirectionContainerType::ConstIterator it = dirCont->Begin(); it!=dirCont->End(); ++it)
512 // {
513 // vnl_vector_fixed<double, 3> mean = ClusterStep(dirCont, it.Value());
514 
515 // if (mean.is_zero())
516 // continue;
517 // bool addMean = true;
518 
519 // for (DirectionContainerType::ConstIterator it2 = container->Begin(); it2!=container->End(); ++it2)
520 // {
521 // vnl_vector_fixed<double, 3> dir = it2.Value();
522 // double angle = fabs(dot_product(mean, dir)/(mean.magnitude()*dir.magnitude()));
523 // if (angle>=m_Epsilon)
524 // {
525 // addMean = false;
526 // break;
527 // }
528 // }
529 
530 // if (addMean)
531 // {
532 // if (m_NormalizeVectors)
533 // mean.normalize();
534 // else if (mean.magnitude()>max)
535 // max = mean.magnitude();
536 // container->InsertElement(container->Size(), mean);
537 // }
538 // }
539 
540 // // max normalize voxel directions
541 // if (max>0 && !m_NormalizeVectors)
542 // for (std::size_t i=0; i<container->Size(); i++)
543 // container->ElementAt(i) /= max;
544 
545 // if (container->Size()<dirCont->Size())
546 // return MeanShiftClustering(container);
547 // else
548 // return container;
549 //}
550 
551 
552 //template< class PixelType >
553 //vnl_vector_fixed<double, 3> TractsToVectorImageFilter< PixelType >::ClusterStep(DirectionContainerType::Pointer dirCont, vnl_vector_fixed<double, 3> currentMean)
554 //{
555 // vnl_vector_fixed<double, 3> newMean; newMean.fill(0);
556 
557 // for (DirectionContainerType::ConstIterator it = dirCont->Begin(); it!=dirCont->End(); ++it)
558 // {
559 // vnl_vector_fixed<double, 3> dir = it.Value();
560 // double angle = dot_product(currentMean, dir)/(currentMean.magnitude()*dir.magnitude());
561 // if (angle>=m_AngularThreshold)
562 // newMean += dir;
563 // else if (-angle>=m_AngularThreshold)
564 // newMean -= dir;
565 // }
566 
567 // if (fabs(dot_product(currentMean, newMean)/(currentMean.magnitude()*newMean.magnitude()))>=m_Epsilon || newMean.is_zero())
568 // return newMean;
569 // else
570 // return ClusterStep(dirCont, newMean);
571 //}
572 }
573 
574 
575 
itk::SmartPointer< Self > Pointer
BoundingBoxType::BoundsArrayType BoundsArrayType
#define MITK_INFO
Definition: mitkLogMacros.h:22
vnl_vector_fixed< double, 3 > GetVnlVector(double point[3])
vnl_vector_fixed< double, 3 > DirectionType
itk::Point< double, 3 > GetItkPoint(double point[3])
static T max(T x, T y)
Definition: svm.cpp:70
void GenerateData() override
A version of GenerateData() specific for image processing filters.
static bool CompareVectorLengths(const vnl_vector_fixed< double, 3 > &v1, const vnl_vector_fixed< double, 3 > &v2)
Extracts the voxel-wise main directions of the input fiber bundle.
DirectionContainerType::Pointer FastClustering(DirectionContainerType::Pointer inDirs, std::vector< double > lengths)
cluster fiber directions
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.