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
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.