CBICA Toolkit  1.0.0
cbicaITKDtiRecon.h
Go to the documentation of this file.
1 /**
2 \file cbicaITKDtiRecon.h
3 
4 \brief Declaration of DtiRecon
5 
6 https://www.cbica.upenn.edu/sbia/software/ <br>
7 software@cbica.upenn.edu
8 
9 Copyright (c) 2015 University of Pennsylvania. All rights reserved. <br>
10 See COPYING file or https://www.cbica.upenn.edu/sbia/software/license.html
11 
12 */
13 
14 #pragma once
15 
16 #include <iostream>
17 #include <fstream>
18 #include <string>
19 #include <sstream>
20 #include <sys/stat.h>
21 
22 #include "itkTensorFractionalAnisotropyImageFilter.h"
23 #include "itkDiscreteGaussianImageFilter.h"
24 #include "itkImageFileReader.h"
25 #include "itkImageFileWriter.h"
26 #include "itkMetaDataDictionary.h"
27 #include "itkImageSeriesReader.h"
28 #include "itkDisplacementFieldJacobianDeterminantFilter.h"
29 #include "itkImageRegionIteratorWithIndex.h"
30 #include "itkNiftiImageIO.h"
31 #include "itkNrrdImageIO.h"
32 #include "itkImageMaskSpatialObject.h"
33 #include "itkBinaryThresholdImageFilter.h"
34 #include "itkNumericTraits.h"
35 #include "itkCommand.h"
37 
38 #include "cbicaITKCommonHolder.h"
39 #include "cbicaLogging.h"
40 
41 /*
42 \namespace cbica
43 \brief Namespace for differentiating functions written for internal use
44 */
45 namespace cbica
46 {
47 
48  template< typename TOutputImageType, typename TTensorImageType >
49  inline void allocateImage(typename TOutputImageType::Pointer scIm, const typename TTensorImageType::Pointer tenIm)
50  {
51  scIm->SetOrigin(tenIm->GetOrigin());
52  scIm->SetSpacing(tenIm->GetSpacing());
53  scIm->SetDirection(tenIm->GetDirection());
54  scIm->SetLargestPossibleRegion(tenIm->GetLargestPossibleRegion());
55  scIm->SetRequestedRegion(tenIm->GetRequestedRegion());
56  scIm->SetBufferedRegion(tenIm->GetBufferedRegion());
57  scIm->Allocate();
58  }
59 
60  /**
61 
62  */
63  template < typename TVectorImageType, typename TScalarImageType, typename TMaskImageType, typename TOutputTensorCompType>
64  std::vector< typename TScalarImageType::Pointer > dtiRecon(typename TVectorImageType::Pointer inputImage, const typename TMaskImageType::Pointer maskImage, const std::vector< std::vector< float > >& gradValues, const float &bValue, std::string outputBasename, bool verbose, bool inputIsVectorImage)
65  {
66  const unsigned int Dimensions = 3;
67  bool readb0 = false;
68  double b0 = 0;
69  typedef itk::VectorImage< typename TScalarImageType::PixelType, Dimensions > GradientImageType;
70  //Set up the gradient image size
71  GradientImageType::Pointer gradIm = inputImage; // why is this happening
72 
73  std::cout << "Converting DWI to vector image\n";
74 
75  typedef itk::DiffusionTensor3DReconstructionImageFilter< typename TScalarImageType::PixelType,
76  typename TScalarImageType::PixelType, TOutputTensorCompType > TensorReconstructionImageFilterType;
77  // -------------------------------------------------------------------------
78 
79  TensorReconstructionImageFilterType::GradientDirectionType vect3d;
80  TensorReconstructionImageFilterType::GradientDirectionContainerType::Pointer DiffusionVectors = TensorReconstructionImageFilterType::GradientDirectionContainerType::New();
81 
82  for (size_t i = 0; i < gradValues.size(); i++)
83  {
84  vec3d = gradValues[i];
85  //vect3d[0] = gradValues[i][0];
86  //vect3d[1] = gradValues[i][1];
87  //vect3d[2] = gradValues[i][2];
88  DiffusionVectors->InsertElement(i, vect3d);
89  }
90  // -------------------------------------------------------------------------
91 
92  TensorReconstructionImageFilterType::Pointer tensorReconstructionFilter = TensorReconstructionImageFilterType::New();
93 
94  typedef itk::ImageMaskSpatialObject< Dimensions > MaskType;
95  MaskType::Pointer spatialObjectMask = MaskType::New();
96  typedef itk::BinaryThresholdImageFilter<TMaskImageType, MaskType::ImageType> ThresholderType;
97  ThresholderType::Pointer thresholder = ThresholderType::New();
98  thresholder->SetOutsideValue(itk::NumericTraits< MaskType::ImageType::PixelType>::Zero);
99  thresholder->SetInsideValue(itk::NumericTraits< MaskType::ImageType::PixelType>::One);
100  thresholder->SetLowerThreshold(itk::NumericTraits<unsigned short>::One);
101  thresholder->InPlaceOn();
102 
103  thresholder->SetInput(maskImage);
104  thresholder->Update();
105  spatialObjectMask->SetImage(thresholder->GetOutput());
106  //tensorReconstructionFilter->SetMaskSpatialObject(spatialObjectMask);
107 
108  //---------------------------------------------------------------------------------
109  tensorReconstructionFilter->SetGradientImage(DiffusionVectors, gradIm);
110  tensorReconstructionFilter->SetNumberOfThreads(1);
111  tensorReconstructionFilter->SetBValue(static_cast<TensorReconstructionImageFilterType::TTensorPixelType>(bValue));
112  //CommandProgressUpdate::Pointer observer = CommandProgressUpdate::New();
113  //tensorReconstructionFilter->AddObserver(itk::ProgressEvent(), observer);
114  tensorReconstructionFilter->Update();
115 
116  //----------------------------------------------------------------
117 
118  //typedef itk::ImageFileWriter<TensorReconstructionImageFilterType::OutputImageType > TensorWriterType;
119  //TensorWriterType::Pointer tensorWriter = TensorWriterType::New();
120  //tensorWriter->SetFileName("C:/Projects/SampleData/DTI/AALZOutput/tensorFile.nii.gz");
121  //tensorWriter->SetInput(tensorReconstructionFilter->GetOutput());
122  //tensorWriter->Update();
123 
124  //--------------------------computing scalars----------------------------
125  std::string default_ext = ".nii.gz";
126  static int writeFA = 1;
127  static int writeTR = 1;
128  static int writeEign = 0;
129  static int writeGeo = 0;
130  static int writeGordR = 0;
131  static int writeGordK = 0;
132  static int writeRadAx = 1;
133  static int writeSkew = 0;
134  static int writeKurt = 0;
135 
136  typedef itk::DiffusionTensor3D< typename TScalarImageType::PixelType > TensorPixelType;
137  typedef itk::Image< TensorPixelType, Dimensions > TensorImageType;
138 
139  std::vector< TScalarImageType::Pointer > vectorOfDTIScalars;
140 
141  typedef itk::ImageRegionConstIteratorWithIndex < TensorImageType > ConstIterType;
142 
143  try
144  {
145  typename TensorImageType::Pointer tensorIm = TensorImageType::New();
146  tensorIm = tensorReconstructionFilter->GetOutput();
147  // Allocate each image that we will want to make..
148  //FA
149  typename TScalarImageType::Pointer faIm = ScalarImageType::New();
150 
151  //TR
152  typename TScalarImageType::Pointer trIm = ScalarImageType::New();
153 
154  //Eigensys
155  typename TScalarImageType::Pointer l1Im = ScalarImageType::New();
156  typename TScalarImageType::Pointer l2Im = ScalarImageType::New();
157  typename TScalarImageType::Pointer l3Im = ScalarImageType::New();
158  typename TVectorImageType::Pointer v1Im = VectorImageType::New();
159  typename TVectorImageType::Pointer v2Im = VectorImageType::New();
160  typename TVectorImageType::Pointer v3Im = VectorImageType::New();
161 
162  //Skewness & Kurtosis
163  typename TScalarImageType::Pointer skIm = ScalarImageType::New();
164  typename TScalarImageType::Pointer kuIm = ScalarImageType::New();
165 
166  //Geometric Features
167  typename TScalarImageType::Pointer clIm = ScalarImageType::New();
168  typename TScalarImageType::Pointer cpIm = ScalarImageType::New();
169  typename TScalarImageType::Pointer csIm = ScalarImageType::New();
170 
171  //Radial Axial
172  typename TScalarImageType::Pointer rdIm = ScalarImageType::New();
173  typename TScalarImageType::Pointer adIm = ScalarImageType::New();
174 
175  //Gordons R features
176  typename TScalarImageType::Pointer r1Im = ScalarImageType::New();
177  typename TScalarImageType::Pointer r2Im = ScalarImageType::New();
178  typename TScalarImageType::Pointer r3Im = ScalarImageType::New();
179 
180  //Gordons K features
181  typename TScalarImageType::Pointer k1Im = ScalarImageType::New();
182  typename TScalarImageType::Pointer k2Im = ScalarImageType::New();
183  typename TScalarImageType::Pointer k3Im = ScalarImageType::New();
184 
185  //Allocate all the images...
186  if (writeFA)
187  allocateImage<TScalarImageType, TensorImageType>(faIm, tensorIm);
188 
189  if (writeTR)
190  allocateImage<TScalarImageType, TensorImageType>(trIm, tensorIm);
191 
192  if (writeEign)
193  {
194  allocateImage<TScalarImageType, TensorImageType>(l1Im, tensorIm);
195  allocateImage<TScalarImageType, TensorImageType>(l2Im, tensorIm);
196  allocateImage<TScalarImageType, TensorImageType>(l3Im, tensorIm);
197  v1Im->SetVectorLength(3);
198  v2Im->SetVectorLength(3);
199  v3Im->SetVectorLength(3);
200  allocateImage<TVectorImageType, TensorImageType>(v1Im, tensorIm);
201  allocateImage<TVectorImageType, TensorImageType>(v2Im, tensorIm);
202  allocateImage<TVectorImageType, TensorImageType>(v3Im, tensorIm);
203 
204  }
205 
206  if (writeSkew)
207  {
208  allocateImage<TScalarImageType, TensorImageType>(skIm, tensorIm);
209  }
210 
211  if (writeKurt)
212  {
213  allocateImage<TScalarImageType, TensorImageType>(kuIm, tensorIm);
214  }
215 
216  if (writeGeo)
217  {
218  allocateImage<TScalarImageType, TensorImageType>(clIm, tensorIm);
219  allocateImage<TScalarImageType, TensorImageType>(cpIm, tensorIm);
220  allocateImage<TScalarImageType, TensorImageType>(csIm, tensorIm);
221  }
222  if (writeRadAx)
223  {
224  allocateImage<TScalarImageType, TensorImageType>(rdIm, tensorIm);
225  allocateImage<TScalarImageType, TensorImageType>(adIm, tensorIm);
226  }
227  if (writeGordR)
228  {
229  allocateImage<TScalarImageType, TensorImageType>(r1Im, tensorIm);
230  allocateImage<TScalarImageType, TensorImageType>(r2Im, tensorIm);
231  allocateImage<TScalarImageType, TensorImageType>(r3Im, tensorIm);
232  }
233  if (writeGordK)
234  {
235  allocateImage<TScalarImageType, TensorImageType>(k1Im, tensorIm);
236  allocateImage<TScalarImageType, TensorImageType>(k2Im, tensorIm);
237  allocateImage<TScalarImageType, TensorImageType>(k3Im, tensorIm);
238  }
239  //Loop though all the voxels and if compute the needed measures!
240  ConstIterType iter(tensorIm, tensorIm->GetLargestPossibleRegion());
241  for (iter.GoToBegin(); !iter.IsAtEnd(); ++iter)
242  {
243  TensorPixelType tmp = iter.Get();
244  typename TensorPixelType::EigenValuesArrayType lambda;
245  typename TensorPixelType::EigenVectorsMatrixType vMat;
246  tmp.ComputeEigenAnalysis(lambda, vMat);
247 
248  typename ScalarImageType::IndexType index = iter.GetIndex();
249 
250  if (writeTR)
251  trIm->SetPixel(index, lambda[0] + lambda[1] + lambda[2]);
252 
253  if (writeFA)
254  {
255  faIm->SetPixel(index, tmp.GetFractionalAnisotropy());
256  }
257 
258  if (writeEign)
259  {
260  l1Im->SetPixel(index, lambda[2]);
261  l2Im->SetPixel(index, lambda[1]);
262  l3Im->SetPixel(index, lambda[0]);
263 
264  typename TVectorImageType::PixelType vec1(Dimensions);
265  typename TVectorImageType::PixelType vec2(Dimensions);
266  typename TVectorImageType::PixelType vec3(Dimensions);
267 
268  vec1[0] = vMat[2][0];
269  vec1[1] = vMat[2][1];
270  vec1[2] = vMat[2][2];
271 
272  vec2[0] = vMat[1][0];
273  vec2[1] = vMat[1][1];
274  vec2[2] = vMat[1][2];
275 
276  vec3[0] = vMat[0][0];
277  vec3[1] = vMat[0][1];
278  vec3[2] = vMat[0][2];
279 
280  v1Im->SetPixel(index, vec1);
281  v2Im->SetPixel(index, vec2);
282  v3Im->SetPixel(index, vec3);
283 
284  }
285 
286  if (writeSkew)
287  {
288  typename TScalarImageType::PixelType m1, m3, l1, l2, l3;
289  l1 = abs(lambda[0]);
290  l2 = abs(lambda[1]);
291  l3 = abs(lambda[2]);
292  m1 = (l1 + l2 + l3) / 3.0;
293 
294  if (m1 > 0)
295  {
296  m3 = (vcl_pow(l1 - m1, 3) + vcl_pow(l2 - m1, 3) + vcl_pow(l3 - m1, 3)) / (vcl_pow(l1, 3) + vcl_pow(l2, 3) + vcl_pow(l3, 3));
297  if (m3 > 0)
298  {
299  skIm->SetPixel(index, vcl_pow(m3, static_cast<ScalarPixelType>(1.0 / 3.0)));
300  }
301  else
302  {
303  skIm->SetPixel(index, -1 * vcl_pow((-1 * m3), static_cast<ScalarPixelType>(1.0 / 3.0)));
304  }
305  }
306  else
307  {
308  skIm->SetPixel(index, static_cast<ScalarPixelType>(0));
309  }
310  }
311 
312  if (writeKurt)
313  {
314  typename TScalarImageType::PixelType m1, m4, l1, l2, l3;
315  l1 = abs(lambda[0]);
316  l2 = abs(lambda[1]);
317  l3 = abs(lambda[2]);
318  m1 = (l1 + l2 + l3) / 3.0;
319  if (m1 > 0)
320  {
321  m4 = (vcl_pow(l1 - m1, 4) + vcl_pow(l2 - m1, 4) + vcl_pow(l3 - m1, 4)) / (vcl_pow(l1, 4) + vcl_pow(l2, 4) + vcl_pow(l3, 4));
322  kuIm->SetPixel(index, vcl_pow(m4, static_cast<ScalarPixelType>(1.0 / 4.0)));
323  }
324  else
325  {
326  kuIm->SetPixel(index, static_cast<ScalarPixelType>(0));
327  }
328  }
329 
330  if (writeGeo)
331  {
332  if (lambda[2] > 0)
333  {
334  clIm->SetPixel(index, (lambda[2] - lambda[1]) / lambda[2]);
335  cpIm->SetPixel(index, (lambda[1] - lambda[0]) / lambda[2]);
336  csIm->SetPixel(index, lambda[0] / lambda[2]);
337  }
338  else
339  {
340  clIm->SetPixel(index, 0);
341  cpIm->SetPixel(index, 0);
342  csIm->SetPixel(index, 0);
343  }
344  }
345 
346  if (writeRadAx)
347  {
348  rdIm->SetPixel(index, (lambda[1] + lambda[0]) / 2);
349  adIm->SetPixel(index, lambda[2]);
350  }
351 
352  if (writeGordR)
353  {
354  //Compute the moments...
355  typename TScalarImageType::PixelType m1, m2, m3, r1, r2, r3;
356  m1 = (lambda[0] + lambda[1] + lambda[2]) / 3.0;
357  m2 = (vcl_pow(lambda[0] - m1, 2) + vcl_pow(lambda[1] - m1, 2)
358  + vcl_pow(lambda[2] - m1, 2)) / 3.0;
359  m3 = (vcl_pow(lambda[0] - m1, 3) + vcl_pow(lambda[1] - m1, 3)
360  + vcl_pow(lambda[2] - m1, 3)) / 3.0;
361 
362  r1 = sqrt(3 * (vcl_pow(m1, 2) + m2));
363  r2 = sqrt(3 * m2 / 2 / (vcl_pow(m1, 2) + m2));
364  // r3 = sqrt(2) * m3 / vcl_pow(static_cast<double>(m2), static_cast<double>(1.5));
365  r3 = (lambda[0] * lambda[1] * lambda[2]) / vcl_pow(static_cast<double>(sqrt(3 * m2)), 3);
366 
367  r1Im->SetPixel(index, r1);
368  r2Im->SetPixel(index, r2);
369  r3Im->SetPixel(index, r3);
370  }
371 
372  if (writeGordK)
373  {
374  //Compute the moments...
375  typename TScalarImageType::PixelType m1, m2, m3, k1, k2, k3;
376 
377  m1 = (lambda[0] + lambda[1] + lambda[2]) / 3.0;
378  m2 = (vcl_pow(lambda[0] - m1, 2) + vcl_pow(lambda[1] - m1, 2)
379  + vcl_pow(lambda[2] - m1, 2)) / 3.0;
380  m3 = (vcl_pow(lambda[0] - m1, 3) + vcl_pow(lambda[1] - m1, 3)
381  + vcl_pow(lambda[2] - m1, 3)) / 3.0;
382 
383  k1 = 3 * m1;
384  k2 = sqrt(3 * m2);
385  // k3 = sqrt(2) * m3 / vcl_pow(static_cast<double>(m2), static_cast<double>(1.5));
386  k3 = (lambda[0] * lambda[1] * lambda[2]) / vcl_pow(static_cast<double>(sqrt(3 * m2)), 3);
387 
388 
389  k1Im->SetPixel(index, k1);
390  k2Im->SetPixel(index, k2);
391  k3Im->SetPixel(index, k3);
392  }
393  }
394 
395  std::cout << "Done Computing Scalars\n";
396 
397  typedef itk::ImageFileWriter< TScalarImageType > ScalarWriterType;
398  typedef itk::ImageFileWriter< TVectorImageType > VectorWriterType;
399 
400  if (writeFA)
401  vectorOfDTIScalars.push_back(faIm);
402 
403  if (writeTR)
404  vectorOfDTIScalars.push_back(trIm);
405 
406  if (writeRadAx)
407  {
408  vectorOfDTIScalars.push_back(rdIm);
409  vectorOfDTIScalars.push_back(adIm);
410  }
411  }
412  catch (itk::ExceptionObject & excp)
413  {
414  }
415  return vectorOfDTIScalars;
416  }
417 
418 }
Declaration of the Logging class.
Declaration of DiffusionTensor3DReconstructionImageFilter.
Declaration of the CommonHolder class.
This class takes as input one or more reference image (acquired in the absence of diffusion sensitizi...
Definition: itkDiffusionTensor3DReconstructionImageFilter.h:133