Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
itkTensorReconstructionWithEigenvalueCorrectionFilter.txx
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 _itk_TensorReconstructionWithEigenvalueCorrectionFilter_txx_
17 #define _itk_TensorReconstructionWithEigenvalueCorrectionFilter_txx_
18 #endif
19 #include "itkImageRegionConstIterator.h"
20 #include <math.h>
21 #include "itkImageFileWriter.h"
22 #include "itkImage.h"
23 #include "itkImageRegionIterator.h"
24 
25 namespace itk
26 {
27 
28 template <class TDiffusionPixelType, class TTensorPixelType>
29 TensorReconstructionWithEigenvalueCorrectionFilter<TDiffusionPixelType, TTensorPixelType>
30 ::TensorReconstructionWithEigenvalueCorrectionFilter()
31 {
32  m_B0Threshold = 50.0;
33 }
34 
35 template <class TDiffusionPixelType, class TTensorPixelType>
36 void
37 TensorReconstructionWithEigenvalueCorrectionFilter<TDiffusionPixelType, TTensorPixelType>
38 ::GenerateData ()
39 {
40 
41  m_GradientImagePointer = static_cast< GradientImagesType * >( this->ProcessObject::GetInput(0) );
42 
43  typename GradientImagesType::SizeType size = m_GradientImagePointer->GetLargestPossibleRegion().GetSize();
44 
45  // number of volumes
46  int nof = m_GradientDirectionContainer->Size();
47 
48  // determine the number of b-zero values
49  int numberb0=0;
50  for(int i=0; i<nof; i++)
51  {
52  vnl_vector_fixed <double, 3 > vec = m_GradientDirectionContainer->ElementAt(i);
53  // due to roundings, the values are not always exactly zero
54  if(vec[0]<0.0001 && vec[1]<0.0001 && vec[2]<0.0001 && vec[0]>-0.0001&& vec[1]>-0.0001 && vec[2]>-0.0001)
55  {
56  numberb0++;
57  }
58  }
59 
60 
61  // Matrix to store all diffusion encoding gradients
62  vnl_matrix<double> directions(nof-numberb0,3);
63 
64  m_B0Mask.set_size(nof);
65 
66 
67  int cnt=0;
68  for(int i=0; i<nof; i++)
69  {
70  vnl_vector_fixed <double, 3 > vec = m_GradientDirectionContainer->ElementAt(i);
71 
72  if(vec[0]<0.0001 && vec[1]<0.0001 && vec[2]<0.0001 && vec[0]>-0.0001&& vec[1]>-0.0001 && vec[2]>-0.0001)
73  {
74  // the diffusion encoding gradient is approximately zero, wo we are dealing with a non-diffusion weighted volume
75  m_B0Mask[i]=1;
76  }
77  else
78  {
79  // dealing with a diffusion weighted volume
80  m_B0Mask[i]=0;
81 
82  // set the diffusion encoding gradient to the directions matrix
83  directions[cnt][0] = vec[0];
84  directions[cnt][1] = vec[1];
85  directions[cnt][2] = vec[2];
86 
87  cnt++;
88  }
89  }
90 
91  // looking for maximal norm among gradients.
92  // The norm is calculated with use of spectral radius theorem- based on determination of eigenvalue.
93 
94  vnl_matrix<double> dirsTimesDirsTrans = directions*directions.transpose();
95 
96  vnl_vector< double> diagonal(nof-numberb0);
97  vnl_vector< double> b_vec(nof-numberb0);
98  vnl_vector< double> temporary(3);
99 
100 
101  for (int i=0;i<nof-numberb0;i++)
102  {
103  diagonal[i]=dirsTimesDirsTrans[i][i];
104  }
105  // normalization: free-water method assumes that directions matrix norm 1 is equal to b=1000
106  directions=directions*sqrt(m_BValue/1000.0);
107 
108  //calculation of norms and storing them in vector
109 
110  dirsTimesDirsTrans = directions*directions.transpose();
111 
112  for (int i=0;i<nof-numberb0;i++)
113  {
114  b_vec[i]= dirsTimesDirsTrans[i][i];
115  }
116 
117 
118  // Calculation of so called design matrix that is used to obtain expected signal.
119 
120  vnl_matrix<double> H(nof-numberb0, 6);
121  vnl_matrix<double> H_org(nof-numberb0, 6);
122  vnl_vector<double> pre_tensor(9);
123 
124  //H is matrix that contains covariances for directions. It is stored twice because its original value is needed later
125  // while H is changed
126 
127  int etbt[6] = { 0, 4, 8, 1, 5, 2 };// tensor order
128 
129  for (int i = 0; i < nof-numberb0; i++)
130  {
131  for (int j = 0; j < 3; j++)
132  {
133  temporary[j] = -directions[i][j];
134  }
135  for (int j = 0; j < 3; j++)
136  {
137  for (int k = 0; k < 3; k++)
138  {
139  pre_tensor[k + 3 * j] = temporary[k] * directions[i][j];
140  }
141  }
142  for (int j = 0; j < 6; j++)
143  {
144  H[i][j] = pre_tensor[etbt[j]];
145  }
146  for (int j = 0; j < 3; j++)
147  {
148  H[i][3 + j] *= 2.0;
149  }
150  }
151 
152  H_org=H;
153 
154  // calculation of inverse matrix by means of pseudoinverse
155 
156  vnl_matrix<double> inputtopseudoinverse=H.transpose()*H;
157  vnl_symmetric_eigensystem<double> eig( inputtopseudoinverse);
158  vnl_matrix<double> pseudoInverse = eig.pinverse()*H.transpose();
159 
160 
161  typedef itk::Image<short, 3> MaskImageType;
162  MaskImageType::Pointer mask = MaskImageType::New();
163  mask->SetRegions(m_GradientImagePointer->GetLargestPossibleRegion().GetSize());
164  mask->SetSpacing(m_GradientImagePointer->GetSpacing());
165  mask->SetOrigin(m_GradientImagePointer->GetOrigin());
166  mask->SetDirection( m_GradientImagePointer->GetDirection() ); // Set the image direction
167  mask->SetLargestPossibleRegion( m_GradientImagePointer->GetLargestPossibleRegion() );
168  mask->SetBufferedRegion( m_GradientImagePointer->GetLargestPossibleRegion() );
169  mask->SetRequestedRegion( m_GradientImagePointer->GetLargestPossibleRegion() );
170  mask->Allocate();
171 
172  // Image thresholding: For every voxel mean B0 image is calculated and then voxels of mean B0 less than the
173  // treshold on the B0 image proviced by the userare excluded from the dataset with use of defined mask image.
174  // 1 in mask voxel means that B0 > assumed treshold.
175 
176  int mask_cnt=0;
177  for(unsigned int x=0;x<size[0];x++)
178  {
179  for(unsigned int y=0;y<size[1];y++)
180  {
181  for(unsigned int z=0;z<size[2];z++)
182  {
183  double mean_b=0.0;
184  itk::Index<3> ix = {{x,y,z}};
185 
186  GradientVectorType pixel = m_GradientImagePointer->GetPixel(ix);
187  for (int i=0;i<nof;i++)
188  {
189  if(m_B0Mask[i]==1)
190  {
191  mean_b = mean_b + pixel[i];
192  }
193  }
194  mean_b=mean_b/numberb0;
195  if(mean_b > m_B0Threshold)
196  {
197  mask->SetPixel(ix, 1);
198  mask_cnt++;
199  }
200  else
201  mask->SetPixel(ix, 0);
202  }
203  }
204  }
205 
206  double mask_val=0.0;
207  vnl_vector<double> org_vec(nof);
208 
209  int counter_corrected =0;
210 
211  for (unsigned int x=0;x<size[0];x++)
212  {
213  for (unsigned int y=0;y<size[1];y++)
214  {
215  for (unsigned int z=0;z<size[2];z++)
216  {
217  itk::Index<3> ix = {{x,y,z}};
218 
219  mask_val = mask->GetPixel(ix);
220 
221  GradientVectorType pixel2 = m_GradientImagePointer->GetPixel(ix);
222 
223  for (int i=0;i<nof;i++)
224  {
225  org_vec[i]=pixel2[i];
226  }
227 
228  if(mask_val >0)
229  {
230  for( int f=0;f<nof;f++)
231  {
232  if(org_vec[f] <= 0)
233  {
234  org_vec[f] = CheckNeighbours(x,y,z,f,size,mask,m_GradientImagePointer);
235  counter_corrected++;
236  }
237  }
238 
239  for (int i=0;i<nof;i++)
240  pixel2[i]=org_vec[i];
241 
242  m_GradientImagePointer->SetPixel(ix, pixel2);
243 
244  }
245  }
246  }
247  }
248 
249  typename TensorImageType::Pointer tensorImg;
250  tensorImg = TensorImageType::New();
251  tensorImg->SetSpacing( m_GradientImagePointer->GetSpacing() ); // Set the image spacing
252  tensorImg->SetOrigin( m_GradientImagePointer->GetOrigin() ); // Set the image origin
253  tensorImg->SetDirection( m_GradientImagePointer->GetDirection() ); // Set the image direction
254  tensorImg->SetLargestPossibleRegion( m_GradientImagePointer->GetLargestPossibleRegion() );
255  tensorImg->SetBufferedRegion( m_GradientImagePointer->GetLargestPossibleRegion() );
256  tensorImg->SetRequestedRegion( m_GradientImagePointer->GetLargestPossibleRegion() );
257  tensorImg->Allocate();
258 
259  //Declaration of vectors that contains too high or too low atenuation for each gradient. Attenuation is only calculated for
260  //non B0 images so nof-numberb0.
261 
262  vnl_vector< double> pixel_max(nof-numberb0);
263  vnl_vector< double> pixel_min(nof-numberb0);
264 
265  // to high and to low attenuation is calculated with use of highest allowed =5 and lowest allowed =0.01 diffusion coefficient
266 
267  for (int i=0;i<nof-numberb0;i++)
268  {
269  pixel_max[i]=exp(-b_vec[i]*0.01);
270  pixel_min[i]= exp(-b_vec[i]*5);
271  }
272 
273  m_PseudoInverse = pseudoInverse;
274  m_H = H_org;
275  m_BVec=b_vec;
276 
277  // in preprocessing we are dealing with 3 types of voxels: voxels excluded = 0 in mask, voxels correct =1 and voxels under correction
278  //= 2. During pre processing most of voxels should be switched from 2 to 1.
279 
280 
281 
282 
283  // what mask is a variable declared to simplify tensor calculaton. Tensors are obtained only for voxels that have a mask value bigger
284  // than what_mask. Sometimes it is 1 sometimes 2.
285 
286  // initialization of required variables
287  double what_mask=1.0;
288  double set_mask=2.0;
289  double previous_mask=0;
290 
291  double old_number_negative_eigs=0;
292  double new_number_negative_eigs=0;
293 
294  bool stil_correcting = true;
295 
296  TurnMask(size,mask,previous_mask,set_mask);
297  // simply defining all possible tensors as with negative eigenvalues
298 
299 
300  //Preprocessing is performed in multiple iterations as long as the next iteration does not increase the number of bad voxels.
301  //The final DWI should be the one that has a smaller or equal number of bad voxels as in the
302  //previous iteration. To obtain this temporary DWI image must be stored in memory.
303 
304 
305  // ! Initial Calculation of Tensors
306  std::cout << "Initial Tensor" << std::endl;
307  GenerateTensorImage(nof,numberb0,size,m_GradientImagePointer,mask,what_mask,tensorImg);
308 
309 
310  // checking how many tensors have problems, this is working only for mask =2
311  old_number_negative_eigs = CheckNegatives (size,mask,tensorImg);
312 
313 
314  //info for the user printed in the consol-debug information to be removed in the future
315  std::cout << "Number of negative eigenvalues: " << old_number_negative_eigs << std::endl;
316 
317  CorrectDiffusionImage(nof,numberb0,size,m_GradientImagePointer,mask,pixel_max,pixel_min);
318 
319 
320  while (stil_correcting == true)
321  {
322  //info for the user printed in the consol-debug information to be removed in the future
323  std::cout << "Number of negative eigenvalues: " << old_number_negative_eigs << std::endl;
324 
325  GenerateTensorImage(nof,numberb0,size,m_GradientImagePointer,mask,what_mask,tensorImg);
326 
327  new_number_negative_eigs = CheckNegatives (size,mask,tensorImg);
328 
329  if(new_number_negative_eigs<old_number_negative_eigs)
330  {
331  // if the correction does not introduce new negative eigenvalues and corrects some of negative detected n previous iteration
332  // smoothed DWI is used to substitute DWI from previous iteration
333  stil_correcting=true;
334  old_number_negative_eigs=new_number_negative_eigs;
335 
336  }
337 
338  else
339  {
340  stil_correcting=false;
341  }
342 
343  //14.10.2013
344  //CorrectDiffusionImage(nof,numberb0,size,corrected_diffusion_temp,mask,pixel_max,pixel_min);
345  CorrectDiffusionImage(nof,numberb0,size,m_GradientImagePointer,mask,pixel_max,pixel_min);
346  }
347 
348  // Changing the mask value for voxels that are still not corrcted. Original idea is to take them into analysis even though
349  // eigenvalues are still negative
350  TurnMask(size, mask,1,1);
351 
352  // Generation of final pre-processed tensor image that might be used as an input for FWE method
353 
354  // Final Tensor Reconstruction
355  std::cout << "Final tensors " << std::endl;
356  GenerateTensorImage(nof,numberb0,size,m_GradientImagePointer,mask,what_mask,tensorImg);
357 
358  m_MaskImage = mask;
359 
360 
361 
362  // Change diffusivity representation to standard convention
363  itk::ImageRegionIterator<OutputType> outputIterator(tensorImg, tensorImg->GetLargestPossibleRegion());
364  outputIterator.GoToBegin();
365  while(!outputIterator.IsAtEnd())
366  {
367  TensorPixelType tens = outputIterator.Get();
368 
369  tens/= 1000.0;
370 
371  outputIterator.Set(tens);
372  ++outputIterator;
373  }
374 
375  this->SetNthOutput(0, tensorImg);
376 }
377 
378 
379 
380 template <class TDiffusionPixelType, class TTensorPixelType>
381 void
382 TensorReconstructionWithEigenvalueCorrectionFilter<TDiffusionPixelType, TTensorPixelType>
383 ::SetGradientImage( GradientDirectionContainerType *gradientDirection,
384  const GradientImagesType *gradientImage )
385 {
386 
387  if( m_GradientImageTypeEnumeration == GradientIsInManyImages )
388  {
389  itkExceptionMacro( << "Cannot call both methods:"
390  << "AddGradientImage and SetGradientImage. Please call only one of them.");
391  }
392 
393  this->m_GradientDirectionContainer = gradientDirection;
394 
395 
396  unsigned int numImages = gradientDirection->Size();
397  this->m_NumberOfBaselineImages = 0;
398 
399  this->m_NumberOfGradientDirections = numImages - this->m_NumberOfBaselineImages;
400 
401  // ensure that the gradient image we received has as many components as
402  // the number of gradient directions
403  if( gradientImage->GetVectorLength() != this->m_NumberOfBaselineImages + this->m_NumberOfGradientDirections )
404  {
405  itkExceptionMacro( << this->m_NumberOfGradientDirections << " gradients + " << this->m_NumberOfBaselineImages
406  << "baselines = " << this->m_NumberOfGradientDirections + this->m_NumberOfBaselineImages
407  << " directions specified but image has " << gradientImage->GetVectorLength()
408  << " components.");
409  }
410 
411  this->ProcessObject::SetNthInput( 0,
412  const_cast< GradientImagesType* >(gradientImage) );
413  m_GradientImageTypeEnumeration = GradientIsInASingleImage;
414 }
415 
416 template <class TDiffusionPixelType, class TTensorPixelType>
417 double
418 TensorReconstructionWithEigenvalueCorrectionFilter<TDiffusionPixelType, TTensorPixelType>
419 ::CheckNeighbours(int x, int y, int z,int f, itk::Size<3> size, itk::Image<short, 3>::Pointer mask, typename GradientImagesType::Pointer corrected_diffusion_temp)
420 {
421  // method is used for finding a new value for the voxel with use of its 27 neighborhood. To perform such a smoothing correct voxels are
422  // counted an arithmetical mean is calculated and stored as a new value for the voxel. If there is no proper neigborhood voxel is turned
423  // to the value of 0.
424 
425  // Definition of neighbourhood avoiding crossing the image boundaries
426  int x_max=size[0]-1;
427  int y_max=size[1]-1;
428  int z_max=size[2]-1;
429 
430  double back_x=std::max(0,x-1);
431  double back_y=std::max(0,y-1);
432  double back_z=std::max(0,z-1);
433 
434  double forth_x=std::min((x+1),x_max);
435  double forth_y=std::min((y+1),y_max);
436  double forth_z=std::min((z+1),z_max);
437 
438 
439  double tempsum=0;
440  double temp_number=0;
441 
442  for(int i=back_x; i<=forth_x; i++)
443  {
444  for (int j=back_y; j<=forth_y; j++)
445  {
446  for (int k=back_z; k<=forth_z; k++)
447  {
448  itk::Index<3> ix = {{i,j,k}};
449 
450  GradientVectorType p = corrected_diffusion_temp->GetPixel(ix);
451 
452  if (p[f] > 0.0 )// taking only positive values and counting them
453  {
454  if(!(i==x && j==y && k== z))
455  {
456  tempsum=tempsum+p[f];
457  temp_number++;
458  }
459  }
460  }
461  }
462  }
463 
464  //getting back to the original position of the voxel
465 
466  itk::Index<3> ix = {{x,y,z}};
467 
468  if (temp_number <= 0.0)
469  {
470  tempsum=0;
471  mask->SetPixel(ix,0);
472  }
473  else
474  {
475  tempsum=tempsum/temp_number;
476 
477  }
478 
479 
480  return tempsum;// smoothed value of voxel
481 }
482 
483 
484 template <class TDiffusionPixelType, class TTensorPixelType>
485 void
486 TensorReconstructionWithEigenvalueCorrectionFilter<TDiffusionPixelType, TTensorPixelType>
487 ::CalculateAttenuation(vnl_vector<double> org_data,vnl_vector<double> &atten,int nof, int numberb0)
488 {
489  double mean_b=0.0;
490 
491  for (int i=0;i<nof;i++)
492  {
493  if(m_B0Mask[i]>0)
494  {
495  // double o_d=org_data[i];
496  mean_b=mean_b+org_data[i];
497  }
498 
499  }
500  mean_b=mean_b/numberb0;
501  int cnt=0;
502  for (int i=0;i<nof;i++)
503  {
504  if(m_B0Mask[i]==0)
505  {
506  //if(org_data[i]<0.001){org_data[i]=0.01;}
507  atten[cnt]=org_data[i]/mean_b;
508  cnt++;
509  }
510  }
511 }
512 
513 template <class TDiffusionPixelType, class TTensorPixelType>
514 double
515 TensorReconstructionWithEigenvalueCorrectionFilter<TDiffusionPixelType, TTensorPixelType>
516 ::CheckNegatives ( itk::Size<3> size, itk::Image<short, 3>::Pointer mask, typename itk::Image< itk::DiffusionTensor3D<TTensorPixelType>, 3 >::Pointer tensorImg )
517 {
518 
519  // The method was created to simplif the flow of negative eigenvalue correction process. The method itself just return the number
520  // of voxels (tensors) with negative eigenvalues. Then if the voxel was previously bad ( mask=2 ) but it is not bad anymore mask is
521  //changed to 1.
522 
523  // declaration of important structures and variables
524  double badvoxels=0;
525  double pixel=0;
526  itk::DiffusionTensor3D<double> ten;
527  vnl_matrix<double> temp_tensor(3,3);
528  vnl_vector<double> eigen_vals(3);
529  vnl_vector<double> tensor (6);
530 
531  // for every pixel from the image
532  for (unsigned int x=0;x<size[0];x++)
533  {
534 
535  for (unsigned int y=0;y<size[1];y++)
536  {
537 
538  for (unsigned int z=0;z<size[2];z++)
539  {
540 
541 
542  itk::Index<3> ix = {{x,y,z}};
543  pixel = mask->GetPixel(ix);
544 
545  // but only if previously marked as bad one-negative eigen value
546 
547  if(pixel > 1)
548  {
549 
550  ten = tensorImg->GetPixel(ix);
551 
552  // changing order from tensor structure in MITK into vnl structure 3x3 symmetric tensor matrix
553 
554  tensor[0] = ten(0,0);
555  tensor[3] = ten(0,1);
556  tensor[5] = ten(0,2);
557  tensor[1] = ten(1,1);
558  tensor[4] = ten(1,2);
559  tensor[2] = ten(2,2);
560 
561  temp_tensor[0][0]= tensor[0]; temp_tensor[1][0]= tensor[3]; temp_tensor[2][0]= tensor[5];
562  temp_tensor[0][1]= tensor[3]; temp_tensor[1][1]= tensor[1]; temp_tensor[2][1]= tensor[4];
563  temp_tensor[0][2]= tensor[5]; temp_tensor[1][2]= tensor[4]; temp_tensor[2][2]= tensor[2];
564 
565  //checking negativity of tensor eigenvalues
566 
567  vnl_symmetric_eigensystem<double> eigen_tensor(temp_tensor);
568 
569 
570  eigen_vals[0]=eigen_tensor.get_eigenvalue(0);
571  eigen_vals[1]=eigen_tensor.get_eigenvalue(1);
572  eigen_vals[2]=eigen_tensor.get_eigenvalue(2);
573 
574  //comparison to 0.01 instead of 0 was proposed by O.Pasternak
575 
576  if( eigen_vals[0]>0.01 && eigen_vals[1]>0.01 && eigen_vals[2]>0.01)
577  {
578  mask->SetPixel(ix,1);
579 
580  }
581  else
582  {
583  badvoxels++;
584  }
585 
586  }
587 
588  }
589  }
590  }
591 
592  double ret = badvoxels;
593 
594  return ret;
595 
596 }
597 
598 
599 template <class TDiffusionPixelType, class TTensorPixelType>
600 void
601 TensorReconstructionWithEigenvalueCorrectionFilter<TDiffusionPixelType, TTensorPixelType>
602 ::CorrectDiffusionImage(int nof,int numberb0,itk::Size<3> size, typename GradientImagesType::Pointer corrected_diffusion,itk::Image<short, 3>::Pointer mask,vnl_vector< double> pixel_max,vnl_vector< double> pixel_min)
603 {
604  // in this method the voxels that has tensor negative eigenvalues are smoothed. Smoothing is done on DWI image.For the voxel
605  //detected as bad one, B0 image is smoothed obligatory. All other gradient images are smoothed only when value of attenuation
606  //is out of declared bounds for too high or too low attenuation.
607 
608  // declaration of important variables
609  vnl_vector<double> org_data(nof);
610  vnl_vector<double> atten(nof-numberb0);
611  double cnt_atten=0;
612 
613  for (unsigned int z=0;z<size[2];z++)
614  {
615 
616  for (unsigned int x=0;x<size[0];x++)
617  {
618 
619  for (unsigned int y=0;y<size[1];y++)
620  {
621  itk::Index<3> ix = {{x, y, z}};
622 
623 
624  if(mask->GetPixel(ix) > 1.0)
625  {
626  GradientVectorType pt = corrected_diffusion->GetPixel(ix);
627 
628  for (int i=0;i<nof;i++)
629  {
630  org_data[i]=pt[i];
631  }
632 
633 
634  double mean_b=0.0;
635 
636  for (int i=0;i<nof;i++)
637  {
638  if(m_B0Mask[i]>0)
639  {
640  mean_b=mean_b+org_data[i];
641  }
642 
643  }
644  mean_b=mean_b/numberb0;
645  int cnt=0;
646  for (int i=0;i<nof;i++)
647  {
648  if(m_B0Mask[i]==0)
649  {
650 
651  atten[cnt]=org_data[i]/mean_b;
652  cnt++;
653  }
654  }
655 
656  cnt_atten=0;
657 
658  //smoothing certain gradient images that are out of declared constraints
659 
660  for (int f=0;f<nof;f++)
661  {
662  if(m_B0Mask[f]==0)
663  {
664 
665  if(atten[cnt_atten]<pixel_min[cnt_atten] || atten[cnt_atten]> pixel_max[cnt_atten])
666  {
667 
668  int x_max=size[0]-1;
669  int y_max=size[1]-1;
670  int z_max=size[2]-1;
671 
672  double back_x=std::max(0,(int)x-1);
673  double back_y=std::max(0,(int)y-1);
674  double back_z=std::max(0,(int)z-1);
675 
676  double forth_x=std::min(((int)x+1),x_max);
677  double forth_y=std::min(((int)y+1),y_max);
678  double forth_z=std::min(((int)z+1),z_max);
679 
680  double tempsum=0;
681  double temp_number=0;
682 
683  for(unsigned int i=back_x; i<=forth_x; i++)
684  {
685  for (unsigned int j=back_y; j<=forth_y; j++)
686  {
687  for (unsigned int k=back_z; k<=forth_z; k++)
688  {
689  itk::Index<3> ix = {{i,j,k}};
690 
691  GradientVectorType p = corrected_diffusion->GetPixel(ix);
692 
693  //double test= p[f];
694 
695  if (p[f] > 0.0 )// taking only positive values and counting them
696  {
697  if(!(i==x && j==y && k== z))
698  {
699  tempsum=tempsum+p[f];
700  temp_number++;
701  }
702 
703  }
704 
705 
706  }
707  }
708  }
709 
710  //getting back to the original position of the voxel
711 
712  itk::Index<3> ix = {{x,y,z}};
713 
714  if (temp_number <= 0.0)
715  {
716  tempsum=0;
717  mask->SetPixel(ix,0);
718  }
719  else
720  {
721  tempsum=tempsum/temp_number;
722 
723  }
724 
725  org_data[f] = tempsum;
726 
727  }
728 
729 
730  cnt_atten++;
731 
732  }
733  //smoothing B0
734  if(m_B0Mask[f]==1)
735  {
736 
737  int x_max=size[0] - 1;
738  int y_max=size[1] - 1;
739  int z_max=size[2] - 1;
740 
741  double back_x=std::max(0,(int)x-1);
742  double back_y=std::max(0,(int)y-1);
743  double back_z=std::max(0,(int)z-1);
744 
745  double forth_x=std::min(((int)x+1),x_max);
746  double forth_y=std::min(((int)y+1),y_max);
747  double forth_z=std::min(((int)z+1),z_max);
748 
749 
750  double tempsum=0;
751  double temp_number=0;
752 
753  for(unsigned int i=back_x; i<=forth_x; i++)
754  {
755  for (unsigned int j=back_y; j<=forth_y; j++)
756  {
757  for (unsigned int k=back_z; k<=forth_z; k++)
758  {
759  itk::Index<3> ix = {{i,j,k}};
760 
761  GradientVectorType p = corrected_diffusion->GetPixel(ix);
762 
763  //double test= p[f];
764 
765  if (p[f] > 0.0 )// taking only positive values and counting them
766  {
767  if(!(i==x && j==y && k== z))
768  {
769  tempsum=tempsum+p[f];
770  temp_number++;
771  }
772 
773  }
774 
775 
776  }
777  }
778  }
779 
780  //getting back to the original position of the voxel
781 
782  itk::Index<3> ix = {{x,y,z}};
783 
784  if (temp_number <= 0.0)
785  {
786  tempsum=0;
787  mask->SetPixel(ix,0);
788  }
789  else
790  {
791  tempsum=tempsum/temp_number;
792 
793  }
794 
795  org_data[f] = tempsum;
796 
797  }
798 
799 
800  }
801 
802  for (int i=0;i<nof;i++)
803  {
804  pt[i]=org_data[i];
805  }
806 
807  corrected_diffusion->SetPixel(ix, pt);
808 
809  }
810  else
811  {
812  GradientVectorType pt = corrected_diffusion->GetPixel(ix);
813  corrected_diffusion->SetPixel(ix, pt);
814 
815  }
816  }
817  }
818  }
819 
820 
821 
822 }
823 
824 template <class TDiffusionPixelType, class TTensorPixelType>
825 void
826 TensorReconstructionWithEigenvalueCorrectionFilter<TDiffusionPixelType, TTensorPixelType>
827 ::GenerateTensorImage(int nof,int numberb0,itk::Size<3> size,itk::VectorImage<short, 3>::Pointer corrected_diffusion,itk::Image<short, 3>::Pointer mask,double what_mask, typename itk::Image< itk::DiffusionTensor3D<TTensorPixelType>, 3 >::Pointer tensorImg)
828 {
829  // in this method the whole tensor image is updated with a tensors for defined voxels ( defined by a value of mask);
830 
831 
832  itk::Index<3> ix;
833 
834  itk::Index<3> idx;
835  idx.Fill(5);
836 
837  vnl_vector<double> org_data(nof);
838  vnl_vector<double> atten(nof-numberb0);
839  vnl_vector<double> tensor(6);
840  itk::DiffusionTensor3D<double> ten;
841  double mask_val=0;
842 
843 
844  for (unsigned int x=0;x<size[0];x++)
845  {
846 
847  for (unsigned int y=0;y<size[1];y++)
848  {
849 
850  for (unsigned int z=0;z<size[2];z++)
851  {
852 
853 
854  ix[0] = x; ix[1] = y; ix[2] = z;
855 
856  mask_val= mask->GetPixel(ix);
857 
858  //Tensors are calculated only for voxels above theshold for B0 image.
859 
860  if( mask_val > 0.0 )
861  {
862 
863  // calculation of attenuation with use of gradient image and and mean B0 image
864  GradientVectorType pt = corrected_diffusion->GetPixel(ix);
865 
866  for (int i=0;i<nof;i++)
867  {
868  org_data[i]=pt[i];
869  }
870 
871  double mean_b=0.0;
872 
873  for (int i=0;i<nof;i++)
874  {
875  if(m_B0Mask[i]>0)
876  {
877  mean_b=mean_b+org_data[i];
878  }
879 
880  }
881  mean_b=mean_b/numberb0;
882  int cnt=0;
883  for (int i=0;i<nof;i++)
884  {
885  if (org_data[i]<= 0)
886 
887  {
888  org_data[i]=0.1;
889  }
890  if(m_B0Mask[i]==0)
891  {
892  atten[cnt]=org_data[i]/mean_b;
893  cnt++;
894  }
895  }
896 
897 
898 
899 
900  for (int i=0;i<nof-numberb0;i++)
901  {
902 
903  atten[i]=log((double)atten[i]);
904  }
905 
906  // Calculation of tensor with use of previously calculated inverse of design matrix and attenuation
907  tensor = m_PseudoInverse*atten;
908 
909  ten(0,0) = tensor[0];
910  ten(0,1) = tensor[3];
911  ten(0,2) = tensor[5];
912  ten(1,1) = tensor[1];
913  ten(1,2) = tensor[4];
914  ten(2,2) = tensor[2];
915 
916  tensorImg->SetPixel(ix, ten);
917 
918 
919 
920  }
921  // for voxels with mask value 0 - tensor is simply 0 ( outside brain value)
922  else if (mask_val < 1.0)
923  {
924 
925  ten(0,0) = 0;
926  ten(0,1) = 0;
927  ten(0,2) = 0;
928  ten(1,1) = 0;
929  ten(1,2) = 0;
930  ten(2,2) = 0;
931  tensorImg->SetPixel(ix, ten);
932  }
933 
934  if (ix == idx)
935  {
936  for (int ll = 0; ll < 6 ; ll++)
937  std::cout << tensor[ll] << "," << std::endl;
938  }
939 
940 
941 
942 
943  }
944  }
945  }
946 
947 
948 
949 }// end of Generate Tensor
950 
951 
952 template <class TDiffusionPixelType, class TTensorPixelType>
953 void
954 TensorReconstructionWithEigenvalueCorrectionFilter<TDiffusionPixelType, TTensorPixelType>
955 ::TurnMask( itk::Size<3> size, itk::Image<short, 3>::Pointer mask, double previous_mask, double set_mask)
956 {
957  // The method changes voxels in the mask that poses a certain value with other value.
958 
959  itk::Index<3> ix;
960  double temp_mask_value=0;
961 
962  for(unsigned int x=0;x<size[0];x++)
963  {
964  for(unsigned int y=0;y<size[1];y++)
965  {
966  for(unsigned int z=0;z<size[2];z++)
967  {
968  ix[0] = x; ix[1] = y; ix[2] = z;
969  temp_mask_value=mask->GetPixel(ix);
970 
971  if(temp_mask_value>previous_mask)
972  {
973  mask->SetPixel(ix,set_mask);
974  }
975  }
976  }
977  }
978 }
979 
980 } // end of namespace
981 
982 
983 
984 
985 
986 
987