DMRITool  v0.1.1-139-g860d86b4
Diffusion MRI Tool
itkMeshFromTensorImageFilter.hxx
Go to the documentation of this file.
1 
13 #ifndef __itkMeshFromTensorImageFilter_hxx
14 #define __itkMeshFromTensorImageFilter_hxx
15 
17 
18 #include <vtkObjectFactory.h>
19 #include <vtkPoints.h>
20 #include <vtkFloatArray.h>
21 #include <vtkDoubleArray.h>
22 #include <vtkPointData.h>
23 #include <vtkStructuredPoints.h>
24 #include <vtkLookupTable.h>
25 #include <vtkFieldData.h>
26 #include <vtkArrowSource.h>
27 #include <vtkCubeSource.h>
28 #include <vtkCylinderSource.h>
29 #include <vtkSphereSource.h>
30 #include <vtkDiskSource.h>
31 #include <vtkLineSource.h>
32 #include <vtkSuperquadricSource.h>
33 #include <vtkProperty.h>
34 
35 #include "itkImageRegionIteratorWithIndex.h"
36 
37 namespace itk
38 {
39 template <class TInputImage, class TOutputMesh>
42 {
43 
44  this->m_Glyph = vtkTensorGlyph::New();
45  this->m_Glyph->ClampScalingOn();
46  this->m_Glyph->ColorGlyphsOn();
47 
48  // default shape is ellipsoid
49  this->SetGlyphShapeToSphere();
50  this->m_Scale = 1000; // scale for ellipsoids.
51  this->m_Glyph->SetScaleFactor(this->m_Scale);
52 
53  // this->m_LUT = 0;
54 }
55 
56 template <class TInputImage, class TOutputMesh>
57 void
60 {
61  switch(i)
62  {
63  case GLYPH_LINE:
64  this->SetGlyphShapeToLine();
65  break;
66 
67  case GLYPH_ARROW:
68  this->SetGlyphShapeToArrow();
69  break;
70 
71  case GLYPH_DISK:
72  this->SetGlyphShapeToDisk();
73  break;
74 
75  case GLYPH_CYLINDER:
76  this->SetGlyphShapeToCylinder();
77  break;
78 
79  case GLYPH_CUBE:
80  this->SetGlyphShapeToCube();
81  break;
82 
83  case GLYPH_SPHERE:
84  this->SetGlyphShapeToSphere();
85  break;
86 
87  case GLYPH_SUPERQUADRIC:
88  this->SetGlyphShapeToSuperquadric();
89  break;
90 
91  default:
92  utlGlobalException(true, "shape type is not recognized.");
93  return;
94  }
95 
96  this->SetGlyphResolution( this->m_GlyphResolution );
97 }
98 
99 
100 template <class TInputImage, class TOutputMesh>
101 void
104 {
105  this->m_ShapeMode = GLYPH_LINE;
106  this->m_Shape = vtkLineSource::New();
107  this->m_Glyph->SetSourceConnection(this->m_Shape->GetOutputPort());
108  this->m_Shape->Delete();
109 }
110 
111 template <class TInputImage, class TOutputMesh>
112 void
115 {
116  this->m_ShapeMode = GLYPH_DISK;
117  vtkDiskSource* source = vtkDiskSource::New();
118  source->SetInnerRadius (0.0);
119  this->m_Shape = source;
120  this->m_Glyph->SetSourceConnection(this->m_Shape->GetOutputPort());
121  this->m_Shape->Delete();
122 }
123 
124 template <class TInputImage, class TOutputMesh>
125 void
128 {
129  this->m_ShapeMode = GLYPH_ARROW;
130  this->m_Shape = vtkArrowSource::New();
131  vtkArrowSource* arrow = vtkArrowSource::SafeDownCast (this->m_Shape);
132  // arrow->SetTipLength (0.0);
133  // arrow->SetTipRadius (0.0);
134  // arrow->SetShaftRadius (0.18);
135 
136  this->m_Glyph->SetSourceConnection(this->m_Shape->GetOutputPort());
137  this->m_Shape->Delete();
138 }
139 
140 template <class TInputImage, class TOutputMesh>
141 void
144 {
145  this->m_ShapeMode = GLYPH_CUBE;
146  this->m_Shape = vtkCubeSource::New();
147  this->m_Glyph->SetSourceConnection(this->m_Shape->GetOutputPort());
148  this->m_Shape->Delete();
149 }
150 
151 template <class TInputImage, class TOutputMesh>
152 void
155 {
156  this->m_ShapeMode = GLYPH_CYLINDER;
157  this->m_Shape = vtkCylinderSource::New();
158  this->m_Glyph->SetSourceConnection(this->m_Shape->GetOutputPort());
159  this->m_Shape->Delete();
160 }
161 
162 template <class TInputImage, class TOutputMesh>
163 void
166 {
167  this->m_ShapeMode = GLYPH_SPHERE;
168  this->m_Shape = vtkSphereSource::New();
169  this->m_Glyph->SetSourceConnection(this->m_Shape->GetOutputPort());
170  this->m_Shape->Delete();
171 }
172 
173 template <class TInputImage, class TOutputMesh>
174 void
177 {
178  this->m_ShapeMode = GLYPH_SUPERQUADRIC;
179  this->m_Shape = vtkSuperquadricSource::New();
180  vtkSuperquadricSource::SafeDownCast (this->m_Shape)->SetPhiRoundness (0.3);
181  vtkSuperquadricSource::SafeDownCast (this->m_Shape)->SetThetaRoundness (0.3);
182  this->m_Glyph->SetSourceConnection(this->m_Shape->GetOutputPort());
183  this->m_Shape->Delete();
184 }
185 
186 template <class TInputImage, class TOutputMesh>
187 void
190 {
191 
192  this->m_GlyphResolution = res;
193 
194  vtkArrowSource* arrowSource = 0;
195  vtkDiskSource* diskSource = 0;
196  vtkCylinderSource* cylinderSource = 0;
197  vtkSphereSource* sphereSource = 0;
198  vtkSuperquadricSource* quadricSource = 0;
199 
200  switch(this->m_ShapeMode)
201  {
202 
203  case GLYPH_LINE:
204  break;
205 
206  case GLYPH_ARROW:
207  arrowSource = vtkArrowSource::SafeDownCast (this->m_Shape);
208  if( arrowSource )
209  arrowSource->SetShaftResolution (res);
210  break;
211 
212  case GLYPH_DISK:
213  diskSource = vtkDiskSource::SafeDownCast (this->m_Shape);
214  if( diskSource )
215  diskSource->SetCircumferentialResolution(res);
216  break;
217 
218  case GLYPH_CYLINDER:
219  cylinderSource = vtkCylinderSource::SafeDownCast (this->m_Shape);
220  if( cylinderSource )
221  cylinderSource->SetResolution (res);
222  break;
223 
224  case GLYPH_CUBE:
225  break;
226 
227  case GLYPH_SPHERE:
228  sphereSource = vtkSphereSource::SafeDownCast (this->m_Shape);
229  if( sphereSource )
230  {
231  sphereSource->SetThetaResolution (res);
232  sphereSource->SetPhiResolution (res);
233  }
234  break;
235 
236  case GLYPH_SUPERQUADRIC:
237  quadricSource = vtkSuperquadricSource::SafeDownCast (this->m_Shape);
238  if( quadricSource )
239  {
240  quadricSource->SetThetaResolution (res);
241  quadricSource->SetPhiResolution (res);
242  }
243  break;
244 
245  default:
246  break;
247 
248  }
249 
250  this->m_Glyph->Modified();
251 }
252 
253 
254 template <class TInputImage, class TOutputMesh>
255 double
258 {
259  if (colorScheme==COLOR_BY_FA)
260  {
261  return tensor.GetFA();
262  }
263  else if (colorScheme==COLOR_BY_MD)
264  {
265  return tensor.GetMD();
266  }
267  else if (colorScheme==COLOR_BY_DIRECTION)
268  {
269  double fa = tensor.GetFA();
270  // if fa is close to 0, then the eigenvector is not reliable. Thus, we set ss=0, if fa=0.
271  if (fa<0.01)
272  return 0;
273 
274  VectorType eigenValues(3), v1(3);
275  MatrixType eigenVectors(3,3);
276 
277  tensor.GetEigenValuesVectorsAnalytic(eigenValues, eigenVectors);
278  for ( int i = 0; i < 3; ++i )
279  v1[i] = eigenVectors(i,2);
280 
281  double ss = 0;
282  utl::RGBToIndex(std::fabs(v1[0]),std::fabs(v1[1]),std::fabs(v1[2]),ss);
283  return ss;
284  }
285  else
286  {
287  utlGlobalException(true, "Logical error! Wrong colorScheme");
288  return 0.0;
289  }
290 }
291 
292 // template <class TInputImage, class TOutputMesh>
293 // std::vector<double>
294 // MeshFromTensorImageFilter<TInputImage, TOutputMesh>
295 // ::GetRGBAFromTensorDirection(const DiffusionTensor<double>& tensor)
296 // {
297 
298 // // std::vector<double> rgba(3);
299 // // double fa = tensor.GetFA();
300 // // // if fa is close to 0, then the eigenvector is not reliable. Thus, we set ss=0, if fa=0.
301 // // if (fa<0.01)
302 // // {
303 // // rgba[0]=0, rgba[1]=0, rgba[2]=0;
304 // // return rgba;
305 // // }
306 
307 // // VectorType eigenValues(3), v1(3);
308 // // MatrixType eigenVectors(3,3);
309 
310 // // tensor.GetEigenValuesVectorsAnalytic(eigenValues, eigenVectors);
311 // // for ( int i = 0; i < 3; ++i )
312 // // v1[i] = eigenVectors(i,2);
313 
314 
315 // // for (unsigned int d=0;d<3;d++)
316 // // {
317 // // rgba[d] = static_cast<VTK_TYPE_NAME_UNSIGNED_CHAR>(std::fabs(v1[d])*255.0);
318 // // }
319 
320 // // double min_val = std::numeric_limits<double>::max();
321 // // double max_val = -std::numeric_limits<double>::max();
322 
323 // // for (unsigned int d=0;d<3;d++)
324 // // {
325 // // if (rgba[d] > max_val)
326 // // max_val = rgba[d];
327 // // if (rgba[d] < min_val)
328 // // min_val = rgba[d];
329 // // }
330 
331 // // // min_val=0;
332 // // for (unsigned int d=0;d<3;d++)
333 // // {
334 // // rgba[d] = static_cast<VTK_TYPE_NAME_UNSIGNED_CHAR>( (rgba[d] - min_val)/(max_val - min_val) * 255.0 );
335 // // }
336 
337 
338 // double ss = GetScalarCodeFromTensor(tensor, COLOR_BY_DIRECTION);
339 
340 // vtkSmartPointer<vtkLookupTable> lut = vtkLookupTable::New();
341 // lut->SetHueRange(0.0,1.0);
342 // lut->SetRampToLinear();
343 // lut->SetTableRange(0,255.0);
344 // lut->Build();
345 
346 // // unsigned char* tmp = lut->MapValue(ss);
347 // std::vector<double> rgba(3);
348 // // rgba[0]=tmp[0], rgba[1]=tmp[1], rgba[2]=tmp[2], rgba[3]=tmp[3];
349 // double tmp[3];
350 // lut->GetColor(ss, tmp);
351 // rgba[0]=tmp[0]*255, rgba[1]=tmp[1]*255, rgba[2]=tmp[2]*255;
352 // utlPrintVar(true, "a1", ss, rgba[0], rgba[1], rgba[2]);
353 
354 // return rgba;
355 // }
356 
357 template <class TInputImage, class TOutputMesh>
358 void
361 {
362  utlShowPosition(this->GetDebug());
363 
364  this->VerifyInputParameters();
365 
366  this->SetGlyphShape(m_ShapeMode);
367 
368  InputImageConstPointer inputPtr = this->GetInput();
369  InputImagePixelType inputPixel, vec9d;
370  inputPixel.SetSize(inputPtr->GetNumberOfComponentsPerPixel());
371  vec9d.SetSize(9);
372 
373  std::vector<int> size3d = itk::GetVectorImage3DVolumeSize(inputPtr);
374  auto spacing = inputPtr->GetSpacing();
375  auto origin = inputPtr->GetOrigin();
376 
377  vtkSmartPointer<vtkPoints> tens_points = vtkPoints::New();
378  vtkSmartPointer<vtkFloatArray> tens_array = vtkFloatArray::New();
379  tens_array->SetNumberOfComponents(9);
380  tens_array->SetNumberOfTuples(size3d[0]*size3d[1]*size3d[2]);
381 
382  vtkSmartPointer<vtkFloatArray> scalars = vtkFloatArray::New();
383  scalars->SetNumberOfComponents(1);
384  scalars->SetName("scalar_color");
385 
386  vtkSmartPointer<vtkUnsignedCharArray> rgbaArray = vtkSmartPointer<vtkUnsignedCharArray>::New();
387  rgbaArray->SetNumberOfComponents(3);
388  rgbaArray->SetName("RGBA_color");
389  double rgba[3]={0,0,0};
390 
391  InputImagePointType inputPhysicalPoint;
392 
393  ImageRegionConstIteratorWithIndex<InputImageType> inputIt(inputPtr, inputPtr->GetLargestPossibleRegion());
394  ImageRegionConstIteratorWithIndex<ScalarImageType> scalarIt;
395  if (!itk::IsImageEmpty(m_ScalarImage))
396  scalarIt = ImageRegionConstIteratorWithIndex<ScalarImageType>(m_ScalarImage, m_ScalarImage->GetLargestPossibleRegion());
397 
399 
400  long off=0;
401  for (inputIt.GoToBegin(), scalarIt.GoToBegin();
402  !inputIt.IsAtEnd();
403  ++inputIt, ++scalarIt)
404  {
405 
406  auto inputIndex = inputIt.GetIndex();
407 
408  if (!this->IsPixelIndexVisible(inputIndex))
409  {
410  continue;
411  }
412 
413  auto inputVec = inputIt.Get();
414  if (inputVec.GetNorm()< 1e-10)
415  {
416  continue;
417  }
418 
419  if (this->GetDebug())
420  {
421  utlPrintVar(true, inputIndex, off);
422  itk::PrintVariableLengthVector(inputVec, "inputVec");
423  }
424 
425  inputPtr->TransformIndexToPhysicalPoint(inputIndex, inputPhysicalPoint);
426 
427  tens_points->InsertPoint(off, inputPhysicalPoint.GetDataPointer());
428 
429  for ( int i = 0; i < 6; ++i )
430  tensor[i] = inputVec[i];
431  tensor.Flip(this->m_Flip[0], this->m_Flip[1], this->m_Flip[2]);
432 
434  tens_array->InsertTuple9(off,vec9d[0],vec9d[1],vec9d[2],vec9d[3],vec9d[4],vec9d[5],vec9d[6],vec9d[7],vec9d[8]);
435 
436  if (m_TensorColorScheme!=COLOR_NONE)
437  {
438  double ss=0;
439  if (m_TensorColorScheme!=COLOR_BY_IMAGE && m_TensorColorScheme!=COLOR_BY_DIRECTION)
440  {
441  ss = GetScalarCodeFromTensor(tensor, m_TensorColorScheme);
442  scalars->InsertTuple1(off, ss);
443  }
444  else if (m_TensorColorScheme==COLOR_BY_IMAGE)
445  {
446  ss = scalarIt.Get();
447  scalars->InsertTuple1(off, ss);
448  }
449  else if (m_TensorColorScheme==COLOR_BY_DIRECTION)
450  {
451  ss = GetScalarCodeFromTensor(tensor, m_TensorColorScheme);
452  scalars->InsertTuple1(off, ss);
453 
454  // auto colorVec = GetRGBAFromTensorDirection(tensor);
455  // utl::PrintVector(colorVec, "colorVec");
456  // for ( int i = 0; i < colorVec.size(); ++i )
457  // rgba[i] = colorVec[i];
458  // rgbaArray->InsertTuple(off, rgba);
459  }
460 
461  if (this->GetDebug())
462  utlPrintVar(true, ss);
463 
464  // if (this->GetDebug())
465  // utlPrintVar(true, ss, rgba[0], rgba[1], rgba[2], rgba[3]);
466  }
467 
468  off++;
469  }
470 
471  this->m_Mesh->SetPoints(tens_points);
472  this->m_Mesh->GetPointData()->SetTensors(tens_array);
473  if (m_TensorColorScheme!=COLOR_NONE)
474  {
475  // if (m_TensorColorScheme==COLOR_BY_DIRECTION)
476  // this->m_Mesh->GetPointData()->SetScalars(rgbaArray);
477  // else
478  // this->m_Mesh->GetPointData()->SetScalars(scalars);
479 
480  this->m_Mesh->GetPointData()->SetScalars(scalars);
481  }
482 
483  m_Glyph->SetInputData(this->m_Mesh);
484  m_Glyph->SetScaleFactor(this->m_Scale);
485 
486  m_Glyph->ColorGlyphsOn();
487  m_Glyph->ClampScalingOn();
488 
489  m_Glyph->Update();
490 
491  this->m_Mesh = m_Glyph->GetOutput();
492 
493 }
494 
495 
496 }
497 
498 
499 #endif
NDArray is a N-Dimensional array class (row-major, c version)
Definition: utlFunctors.h:131
bool IsImageEmpty(const SmartPointer< ImageType > &image)
Definition: utlITK.h:435
InputImageType::PointType InputImagePointType
Created "06-09-2017.
void GetEigenValuesVectorsAnalytic(TArrayType &eigenValues, TMatrixType &eigenVectors) const
analytic way to calculate eigenValues (in ascending order) and eigenVectors. In mathematica, Eigenvectors[( { {a, b, c}, {b, d, e}, {c, e, f} } )]
static double GetScalarCodeFromTensor(const DiffusionTensor< double > &tensor, TensorColorSchemeType colorScheme)
RealValueType GetFA() const
void PrintVariableLengthVector(const VariableLengthVector< T >vec, const std::string &str="", const char *separate=" ", std::ostream &os=std::cout)
Definition: utlITK.h:45
void Flip(const int flipx, const int flipy, const int flipz)
#define utlGlobalException(cond, expout)
Definition: utlCoreMacro.h:372
InputImageType::ConstPointer InputImageConstPointer
#define utlPrintVar(cond,...)
Definition: utlCoreMacro.h:309
std::vector< int > GetVectorImage3DVolumeSize(const SmartPointer< ImageType > &image)
Definition: utlITK.h:331
InputImageType::PixelType InputImagePixelType
void ConvertTensor6DTo9D(const V1Type &v6d, V2Type &v9d, int v6dStoreWay)
Definition: utlDMRI.h:257
RealValueType GetMD() const
void RGBToIndex(double R, double G, double B, double &index)
Definition: utlDMRI.h:617
#define utlShowPosition(cond)
Definition: utlCoreMacro.h:554
tensor with some useful functions