Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
itkOdfMaximaExtractionFilter.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 #ifndef __itkOdfMaximaExtractionFilter_cpp
17 #define __itkOdfMaximaExtractionFilter_cpp
18 
19 
21 #include <itkImageRegionIterator.h>
22 #include <itkContinuousIndex.h>
23 
24 #include <vtkSmartPointer.h>
25 #include <vtkPolyData.h>
26 #include <vtkCellArray.h>
27 #include <vtkPoints.h>
28 #include <vtkPolyLine.h>
29 
30 #include <boost/progress.hpp>
31 #include <boost/math/special_functions.hpp>
32 #include <vnl/vnl_det.h>
33 #include <vnl/vnl_trace.h>
34 
35 using namespace boost::math;
36 using namespace std;
37 
38 namespace itk {
39 
40 template< class TOdfPixelType >
42  m_NormalizationMethod(MAX_VEC_NORM),
43  m_PeakThreshold(0.2),
44  m_MaxNumPeaks(10),
45  m_ShCoeffImage(NULL),
46  m_OutputFiberBundle(NULL),
47  m_NumDirectionsImage(NULL),
48  m_DirectionImageContainer(NULL)
49 {
50 
51 }
52 
53 // solve ax? + bx? + cx + d = 0 using cardanos method
54 template< class TOdfPixelType >
56 {
57  if (m_ShCoeffImage.IsNotNull())
58  {
59  cout << "Using preset coefficient image\n";
60  return true;
61  }
62 
63  cout << "Starting qball reconstruction\n";
64  try {
66  filter->SetGradientImage( m_DiffusionGradients, m_DiffusionImage );
67  filter->SetBValue(m_Bvalue);
68  filter->SetLambda(0.006);
69  filter->SetNormalizationMethod(QballReconstructionFilterType::QBAR_SOLID_ANGLE);
70  filter->Update();
71  m_ShCoeffImage = filter->GetCoefficientImage();
72  if (m_ShCoeffImage.IsNull())
73  return false;
74  return true;
75  }
76  catch (...)
77  {
78  return false;
79  }
80 }
81 
82 // solve ax³ + bx² + cx + d = 0 using cardanos method
83 template< class TOdfPixelType >
85 ::SolveCubic(const double& a, const double& b, const double& c, const double& d)
86 {
87  double A, B, p, q, r, D, offset, ee, tmp, root;
88  vector<double> roots;
89  double inv3 = 1.0/3.0;
90 
91  if (a!=0) // solve ax³ + bx² + cx + d = 0
92  {
93  p = b/a; q = c/a; r = d/a; // x³ + px² + qx + r = 0
94  A = q-p*p*inv3;
95  B = (2.0*p*p*p-9.0*p*q+27.0*r)/27.0;
96  A = A*inv3;
97  B = B*0.5;
98  D = B*B+A*A*A;
99  offset = p*inv3;
100 
101  if (D>0.0) // one real root
102  {
103  ee = sqrt(D);
104  tmp = -B+ee; root = cbrt(tmp);
105  tmp = -B-ee; root += cbrt(tmp);
106  root -= offset; roots.push_back(root);
107  }
108  else if (D<0.0) // three real roots
109  {
110  ee = sqrt(-D);
111  double tmp2 = -B;
112  double angle = 2.0*inv3*atan(ee/(sqrt(tmp2*tmp2+ee*ee)+tmp2));
113  double sqrt3 = sqrt(3.0);
114  tmp = cos(angle);
115  tmp2 = sin(angle);
116  ee = sqrt(-A);
117  root = 2*ee*tmp-offset; roots.push_back(root);
118  root = -ee*(tmp+sqrt3*tmp2)-offset; roots.push_back(root);
119  root = -ee*(tmp-sqrt3*tmp2)-offset; roots.push_back(root);
120  }
121  else // one or two real roots
122  {
123  tmp=-B;
124  tmp=cbrt(tmp);
125  root=2*tmp-offset; roots.push_back(root);
126  if (A!=0 || B!=0)
127  root=-tmp-offset; roots.push_back(root);
128  }
129  }
130  else if (b!=0) // solve bx² + cx + d = 0
131  {
132  D = c*c-4*b*d;
133  if (D>0)
134  {
135  tmp = sqrt(D);
136  root = (-c+tmp)/(2.0*b); roots.push_back(root);
137  root = (-c-tmp)/(2.0*b); roots.push_back(root);
138  }
139  else if (D==0)
140  root = -c/(2.0*b); roots.push_back(root);
141  }
142  else if (c!=0) // solve cx + d = 0
143  root = -d/c; roots.push_back(root);
144 
145  return roots;
146 }
147 
148 template< class TOdfPixelType >
150 ::ODF_dtheta(const double& sn, const double& cs, const double& A, const double& B, const double& C, const double& D, const double& E, const double& F, const double& G, const double& H)
151 {
152  double dtheta=(G-7*E)*sn*sn + (7*F-35*D-H)*sn*cs + (H+C-F-3*A-5*D)*sn + (0.5*E+B+0.5*G)*cs -0.5*G+3.5*E;
153  return dtheta;
154 }
155 
156 template< class TOdfPixelType >
158 ::ODF_dtheta2(const double& sn, const double& cs, const double& A, const double& B, const double& C, const double& D, const double& E, const double& F, const double& G, const double& H)
159 {
160  double dtheta2=4*(G-7*E)*sn*cs + 2*(7*F-35*D-H)*(2*cs*cs-1) + 2*(H+C-F-3*A-5*D)*cs -(E+2*B+G)*sn;
161  return dtheta2;
162 }
163 
164 template< class TOdfPixelType >
166 ::ODF_dphi2(const double& sn, const double& cs, const double& A, const double& B, const double& C, const double& D, const double& E, const double& F, const double& G, const double& H)
167 {
168  double dphi2=35*D*((1+cs)*(1+cs)/4)+(3*A-30*D)*(1+cs)/2.0+3*D-A + 0.5*(7*E*(1+cs)/2.0-3*E+B)*sn + (7*F*(1+cs)/2+C-F)*(1-cs)/2.0 + G*sn*(1-cs)/4.0 + H*((1-cs)*(1-cs)/4);
169  return dphi2;
170 }
171 
172 template< class TOdfPixelType >
175 {
176  const double thr = 0.03; // threshold on the derivative of the ODF with respect to theta
177  const double phi_step = 0.005; // step size for 1D exhaustive search on phi
178  bool highRes; // when close to maxima increase resolution
179  double mag, Y, Yp, sn, cs;
180  double phi, dPhi;
181  double A, B, C, D, E, F, G, H, Bp, Cp, Ep, Fp, Gp, Hp, Bs, Cs, Es, Fs, Gs, Hs;
182  CoefficientPixelType a, ap;
183  a = SHcoeff; ap = SHcoeff;
184 
185  m_CandidatePeaks.clear(); // clear peaks of last voxel
186 
187  for (int adaptiveStepwidth=0; adaptiveStepwidth<=1; adaptiveStepwidth++)
188  {
189  phi=0;
190  while (phi<(2*M_PI)) // phi exhaustive search 0..pi
191  {
192  // calculate 4th order SH representtaion of ODF and according derivative
193  for (int l=0; l<=4; l=l+2)
194  {
195  for (int m=-l; m<=l; m++)
196  {
197  int j=l*(l+1)/2+m;
198  if (m<0)
199  {
200  mag = sqrt(((2*l+1)/(2*M_PI))*factorial<double>(l+m)/factorial<double>(l-m));
201  Y = mag*cos(m*phi);
202  Yp = -m*mag*sin(m*phi);
203  }
204  else if (m==0)
205  {
206  Y = sqrt((2*l+1)/(4*M_PI));
207  Yp = 0;
208  }
209  else
210  {
211  mag = pow(-1.0,m)*sqrt(((2*l+1)/(2*M_PI))*factorial<double>(l-m)/factorial<double>(l+m));
212  Y = mag*sin(m*phi);
213  Yp = m*mag*cos(m*phi);
214  }
215  a[j] = SHcoeff[j]*Y;
216  ap[j] = SHcoeff[j]*Yp;
217  }
218  }
219 
220  // ODF
221  A=0.5*a[3]; B=-3*(a[2]+a[4]); C=3*(a[1]+a[5]); D=0.125*a[10]; E=-2.5*(a[9]+a[11]);
222  F=7.5*(a[8]+a[12]); G=-105*(a[7]+a[13]); H=105*(a[6]+a[14]);
223 
224  // phi derivative
225  Bp=-3*(ap[2]+ap[4]); Cp=3*(ap[1]+ap[5]); Ep=-2.5*(ap[9]+ap[11]);
226  Fp=7.5*(ap[8]+ap[12]); Gp=-105*(ap[7]+ap[13]); Hp=105*(ap[6]+ap[14]);
227 
228  // 2phi derivative
229  Bs=-B; Cs=-4*C; Es=-E;
230  Fs=-4*F; Gs=-9*G; Hs=-16*H;
231 
232  // solve cubic for tan(theta)
233  std::vector<double> tanTheta = SolveCubic(Hp+Cp-Fp, Gp+Bp-3*Ep, 6*Fp+Cp, Bp+4*Ep);
234 
235  highRes = false;
236  dPhi = phi_step;
237 
238  //for each real cubic solution for tan(theta)
239  for (int n=0; n<tanTheta.size(); n++)
240  {
241  double tmp = atan(tanTheta[n]); // arcus tangens of root (theta -pi/2..pi/2)
242  double theta = floor(tmp/M_PI); // project theta to 0..pi ...
243  theta = tmp - theta*M_PI; // ... as the modulo of the division atan(tth[n])/M_PI
244 
245  sn = sin(2*theta); cs = cos(2*theta);
246  tmp = ODF_dtheta(sn, cs, A, B, C, D, E, F, G, H);
247 
248  if (fabs(tmp) < thr) // second condition for maximum is true (theta derivative < eps)
249  {
250  //Compute the Hessian
251  vnl_matrix_fixed< double, 2, 2 > hessian;
252  hessian(0,0) = ODF_dtheta2(sn, cs, A, B, C, D, E, F, G, H);
253  hessian(0,1) = ODF_dtheta(sn, cs, 0, Bp, Cp, 0, Ep, Fp, Gp, Hp);
254  hessian(1,0) = hessian(0,1);
255  hessian(1,1) = ODF_dphi2(sn, cs, 0, Bs, Cs, 0, Es, Fs, Gs, Hs);
256 
257  double det = vnl_det(hessian); // determinant
258  double tr = vnl_trace(hessian); // trace
259 
260  highRes = true; // we are close to a maximum, so turn on high resolution 1D exhaustive search
261  if (det>=0 && tr<=0) // check if we really have a local maximum
262  {
263  vnl_vector_fixed< double, 2 > peak;
264  peak[0] = theta;
265  peak[1] = phi;
266  m_CandidatePeaks.push_back(peak);
267  }
268  }
269 
270  if (adaptiveStepwidth) // calculate adaptive step width
271  {
272  double t2=tanTheta[n]*tanTheta[n]; double t3=t2*tanTheta[n]; double t4=t3*tanTheta[n];
273  double const_step=phi_step*(1+t2)/sqrt(t2+t4+pow((((Hs+Cs-Fs)*t3+(Gs+Bs-3*Es)*t2+(6*Fs+Cs)*tanTheta[n]+(Bs+4*Es))/(3*(Hp+Cp-Fp)*t2+2*(Gp+Bp-3*Ep)*tanTheta[n]+(6*Fp+Cp))),2.0));
274  if (const_step<dPhi)
275  dPhi=const_step;
276  }
277  }
278 
279  // update phi
280  if (highRes)
281  phi=phi+dPhi*0.5;
282  else
283  phi=phi+dPhi;
284  }
285  }
286 }
287 
288 template< class TOdfPixelType >
289 std::vector< vnl_vector_fixed< double, 3 > > OdfMaximaExtractionFilter< TOdfPixelType >
291 {
292  const double distThres = 0.4;
293  int npeaks = 0, nMin = 0;
294  double dMin, dPos, dNeg, d;
295  Vector3D u;
296  vector< Vector3D > v;
297 
298  // initialize container for vector clusters
299  std::vector < std::vector< Vector3D > > clusters;
300  clusters.resize(m_CandidatePeaks.size());
301 
302  for (int i=0; i<m_CandidatePeaks.size(); i++)
303  {
304  // calculate cartesian representation of peak
305  u[0] = sin(m_CandidatePeaks[i](0))*cos(m_CandidatePeaks[i](1));
306  u[1] = sin(m_CandidatePeaks[i](0))*sin(m_CandidatePeaks[i](1));
307  u[2] = cos(m_CandidatePeaks[i](0));
308 
310  for (int n=0; n<npeaks; n++) //for each other maximum v already visited
311  {
312  // euclidean distance from u/-u to other clusters
313  dPos = vnl_vector_ssd(v[n],u);
314  dNeg = vnl_vector_ssd(v[n],-u);
315  d = std::min(dPos,dNeg);
316 
317  if ( d<dMin )
318  {
319  dMin = d; // adjust minimum
320  nMin = n; // store its index
321  if ( dNeg<dPos ) // flip u if neccesary
322  u=-u;
323  }
324  }
325  if ( dMin<distThres ) // if u is very close to any other maximum v
326  {
327  clusters[nMin].push_back(u); //store it with all other vectors that are close to v vector (with index nMin)
328  }
329  else // otherwise store u as output peak
330  {
331  v.push_back(u);
332  npeaks++;
333  }
334  }
335 
336  // calculate mean vector of each cluster
337  for (int i=0; i<m_CandidatePeaks.size(); i++)
338  if ( !clusters[i].empty() )
339  {
340  v[i].fill(0.0);
341  for (int vc=0; vc<clusters[i].size(); vc++)
342  v[i]=v[i]+clusters[i][vc];
343  v[i].normalize();
344  }
345 
346 
347  if (npeaks!=0)
348  {
349  // check the ODF amplitudes at each candidate peak
350  vnl_matrix< double > shBasis, sphCoords;
351 
352  Cart2Sph(v, sphCoords); // convert candidate peaks to spherical angles
353  shBasis = CalcShBasis(sphCoords, 4); // evaluate spherical harmonics at each peak
354  vnl_vector<double> odfVals(npeaks);
355  odfVals.fill(0.0);
356  double maxVal = itk::NumericTraits<double>::NonpositiveMin();
357  int maxPos;
358  for (int i=0; i<npeaks; i++) //compute the ODF value at each peak
359  {
360  for (int j=0; j<15; j++)
361  odfVals(i) += shCoeff[j]*shBasis(i,j);
362 
363  if ( odfVals(i)>maxVal )
364  {
365  maxVal = odfVals(i);
366  maxPos = i;
367  }
368  }
369  v.clear();
370  vector< double > restVals;
371  for (int i=0; i<npeaks; i++) // keep only peaks with high enough amplitude and convert back to cartesian coordinates
372  if ( odfVals(i)>=m_PeakThreshold*maxVal )
373  {
374  u[0] = odfVals(i)*cos(sphCoords(i,1))*sin(sphCoords(i,0));
375  u[1] = odfVals(i)*sin(sphCoords(i,1))*sin(sphCoords(i,0));
376  u[2] = odfVals(i)*cos(sphCoords(i,0));
377  restVals.push_back(odfVals(i));
378  v.push_back(u);
379  }
380  npeaks = v.size();
381 
382  if (npeaks>m_MaxNumPeaks) // if still too many peaks, keep only the m_MaxNumPeaks with maximum value
383  {
384  vector< Vector3D > v2;
385  for (int i=0; i<m_MaxNumPeaks; i++)
386  {
387  maxVal = itk::NumericTraits<double>::NonpositiveMin(); //Get the maximum ODF peak value and the corresponding peak index
388  for (int i=0; i<npeaks; i++)
389  if ( restVals[i]>maxVal )
390  {
391  maxVal = restVals[i];
392  maxPos = i;
393  }
394 
395  v2.push_back(v[maxPos]);
396  restVals[maxPos] = 0; //zero that entry in order to find the next maximum
397  }
398  return v2;
399  }
400  }
401  return v;
402 }
403 
404 // convert cartesian to spherical coordinates
405 template< class TOdfPixelType >
407 ::Cart2Sph(const std::vector< Vector3D >& dir, vnl_matrix<double>& sphCoords)
408 {
409  sphCoords.set_size(dir.size(), 2);
410 
411  for (int i=0; i<dir.size(); i++)
412  {
413  double mag = dir[i].magnitude();
414 
415  if( mag<mitk::eps )
416  {
417  sphCoords(i,0) = M_PI/2; // theta
418  sphCoords(i,1) = M_PI/2; // phi
419  }
420  else
421  {
422  sphCoords(i,0) = acos(dir[i](2)/mag); // theta
423  sphCoords(i,1) = atan2(dir[i](1), dir[i](0)); // phi
424  }
425  }
426 }
427 
428 // generate spherical harmonic values of the desired order for each input direction
429 template< class TOdfPixelType >
431 ::CalcShBasis(vnl_matrix<double>& sphCoords, const int& shOrder)
432 {
433  int R = (shOrder+1)*(shOrder+2)/2;
434  int M = sphCoords.rows();
435  int j, m; double mag, plm;
436  vnl_matrix<double> shBasis;
437  shBasis.set_size(M,R);
438 
439  for (int p=0; p<M; p++)
440  {
441  j=0;
442  for (int l=0; l<=shOrder; l=l+2)
443  for (m=-l; m<=l; m++)
444  {
445  plm = legendre_p<double>(l,abs(m),cos(sphCoords(p,0)));
446  mag = sqrt((double)(2*l+1)/(4.0*M_PI)*factorial<double>(l-abs(m))/factorial<double>(l+abs(m)))*plm;
447 
448  if (m<0)
449  shBasis(p,j) = sqrt(2.0)*mag*cos(fabs((double)m)*sphCoords(p,1));
450  else if (m==0)
451  shBasis(p,j) = mag;
452  else
453  shBasis(p,j) = pow(-1.0, m)*sqrt(2.0)*mag*sin(m*sphCoords(p,1));
454  j++;
455  }
456  }
457  return shBasis;
458 }
459 
460 template< class TOdfPixelType >
463 {
464  if (!ReconstructQballImage())
465  return;
466 
467  std::cout << "Starting maxima extraction\n";
468 
469  switch (m_NormalizationMethod)
470  {
471  case NO_NORM:
472  std::cout << "NO_NORM\n";
473  break;
474  case SINGLE_VEC_NORM:
475  std::cout << "SINGLE_VEC_NORM\n";
476  break;
477  case MAX_VEC_NORM:
478  std::cout << "MAX_VEC_NORM\n";
479  break;
480  }
481 
482  typedef ImageRegionConstIterator< CoefficientImageType > InputIteratorType;
483 
484 
485  InputIteratorType git(m_ShCoeffImage, m_ShCoeffImage->GetLargestPossibleRegion() );
486 
487  itk::Vector<double,3> spacing = m_ShCoeffImage->GetSpacing();
488  double minSpacing = spacing[0];
489  if (spacing[1]<minSpacing)
490  minSpacing = spacing[1];
491  if (spacing[2]<minSpacing)
492  minSpacing = spacing[2];
493 
494  mitk::Point3D origin = m_ShCoeffImage->GetOrigin();
495  itk::Matrix<double, 3, 3> direction = m_ShCoeffImage->GetDirection();
496  ImageRegion<3> imageRegion = m_ShCoeffImage->GetLargestPossibleRegion();
497 
498  // initialize num directions image
499  m_NumDirectionsImage = ItkUcharImgType::New();
500  m_NumDirectionsImage->SetSpacing( spacing );
501  m_NumDirectionsImage->SetOrigin( origin );
502  m_NumDirectionsImage->SetDirection( direction );
503  m_NumDirectionsImage->SetRegions( imageRegion );
504  m_NumDirectionsImage->Allocate();
505  m_NumDirectionsImage->FillBuffer(0);
506 
507  vtkSmartPointer<vtkCellArray> m_VtkCellArray = vtkSmartPointer<vtkCellArray>::New();
508  vtkSmartPointer<vtkPoints> m_VtkPoints = vtkSmartPointer<vtkPoints>::New();
509 
510  m_DirectionImageContainer = ItkDirectionImageContainer::New();
511  for (int i=0; i<m_MaxNumPeaks; i++)
512  {
513  itk::Vector< float, 3 > nullVec; nullVec.Fill(0.0);
515  img->SetSpacing( spacing );
516  img->SetOrigin( origin );
517  img->SetDirection( direction );
518  img->SetRegions( imageRegion );
519  img->Allocate();
520  img->FillBuffer(nullVec);
521  m_DirectionImageContainer->InsertElement(m_DirectionImageContainer->Size(), img);
522  }
523 
524  if (m_MaskImage.IsNull())
525  {
526  m_MaskImage = ItkUcharImgType::New();
527  m_MaskImage->SetSpacing( spacing );
528  m_MaskImage->SetOrigin( origin );
529  m_MaskImage->SetDirection( direction );
530  m_MaskImage->SetRegions( imageRegion );
531  m_MaskImage->Allocate();
532  m_MaskImage->FillBuffer(1);
533  }
534 
535  itk::ImageRegionIterator<ItkUcharImgType> dirIt(m_NumDirectionsImage, m_NumDirectionsImage->GetLargestPossibleRegion());
536  itk::ImageRegionIterator<ItkUcharImgType> maskIt(m_MaskImage, m_MaskImage->GetLargestPossibleRegion());
537 
538  int maxProgress = m_MaskImage->GetLargestPossibleRegion().GetSize()[0]*m_MaskImage->GetLargestPossibleRegion().GetSize()[1]*m_MaskImage->GetLargestPossibleRegion().GetSize()[2];
539 
540  boost::progress_display disp(maxProgress);
541 
542  git.GoToBegin();
543  while( !git.IsAtEnd() )
544  {
545  ++disp;
546  if (maskIt.Value()<=0)
547  {
548  ++git;
549  ++dirIt;
550  ++maskIt;
551  continue;
552  }
553 
554  CoefficientPixelType c = git.Get();
555  FindCandidatePeaks(c);
556  std::vector< Vector3D > directions = ClusterPeaks(c);
557 
558  typename CoefficientImageType::IndexType index = git.GetIndex();
559 
560  float max = 0.0;
561  for (int i=0; i<directions.size(); i++)
562  if (directions.at(i).magnitude()>max)
563  max = directions.at(i).magnitude();
564  if (max<0.0001)
565  max = 1.0;
566 
567  for (int i=0; i<directions.size(); i++)
568  {
569  ItkDirectionImage::Pointer img = m_DirectionImageContainer->GetElement(i);
570  itk::Vector< float, 3 > pixel;
571  vnl_vector<double> dir = directions.at(i);
572 
573  vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
574  itk::ContinuousIndex<double, 3> center;
575  center[0] = index[0];
576  center[1] = index[1];
577  center[2] = index[2];
578  itk::Point<double> worldCenter;
579  m_ShCoeffImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter );
580 
581  switch (m_NormalizationMethod)
582  {
583  case NO_NORM:
584  break;
585  case SINGLE_VEC_NORM:
586  dir.normalize();
587  break;
588  case MAX_VEC_NORM:
589  dir /= max;
590  break;
591  }
592 
593  dir = m_MaskImage->GetDirection()*dir;
594  pixel.SetElement(0, dir[0]);
595  pixel.SetElement(1, dir[1]);
596  pixel.SetElement(2, dir[2]);
597  img->SetPixel(index, pixel);
598 
599  itk::Point<double> worldStart;
600  worldStart[0] = worldCenter[0]-dir[0]/2 * minSpacing;
601  worldStart[1] = worldCenter[1]-dir[1]/2 * minSpacing;
602  worldStart[2] = worldCenter[2]-dir[2]/2 * minSpacing;
603  vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer());
604  container->GetPointIds()->InsertNextId(id);
605  itk::Point<double> worldEnd;
606  worldEnd[0] = worldCenter[0]+dir[0]/2 * minSpacing;
607  worldEnd[1] = worldCenter[1]+dir[1]/2 * minSpacing;
608  worldEnd[2] = worldCenter[2]+dir[2]/2 * minSpacing;
609  id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer());
610  container->GetPointIds()->InsertNextId(id);
611  m_VtkCellArray->InsertNextCell(container);
612  }
613 
614  dirIt.Set(directions.size());
615 
616  ++git;
617  ++dirIt;
618  ++maskIt;
619  }
620 
621  vtkSmartPointer<vtkPolyData> directionsPolyData = vtkSmartPointer<vtkPolyData>::New();
622  directionsPolyData->SetPoints(m_VtkPoints);
623  directionsPolyData->SetLines(m_VtkCellArray);
624  m_OutputFiberBundle = mitk::FiberBundle::New(directionsPolyData);
625  std::cout << "Maxima extraction finished\n";
626 }
627 }
628 
629 #endif // __itkOdfMaximaExtractionFilter_cpp
itk::SmartPointer< Self > Pointer
double ODF_dtheta(const double &sn, const double &cs, const double &A, const double &B, const double &C, const double &D, const double &E, const double &F, const double &G, const double &H)
std::string tmp2
double ODF_dphi2(const double &sn, const double &cs, const double &A, const double &B, const double &C, const double &D, const double &E, const double &F, const double &G, const double &H)
STL namespace.
CoefficientImageType::PixelType CoefficientPixelType
void FindCandidatePeaks(const CoefficientPixelType &SHcoeff)
vnl_vector_fixed< double, 3 > Vector3D
std::vector< double > SolveCubic(const double &a, const double &b, const double &c, const double &d)
vnl_matrix< double > CalcShBasis(vnl_matrix< double > &sphCoords, const int &shOrder)
static Vector3D offset
double ODF_dtheta2(const double &sn, const double &cs, const double &A, const double &B, const double &C, const double &D, const double &E, const double &F, const double &G, const double &H)
void Cart2Sph(const std::vector< Vector3D > &dir, vnl_matrix< double > &sphCoords)
static T max(T x, T y)
Definition: svm.cpp:70
static T min(T x, T y)
Definition: svm.cpp:67
std::vector< Vector3D > ClusterPeaks(const CoefficientPixelType &shCoeff)
MITKCORE_EXPORT const ScalarType eps
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.