DMRITool  v0.1.1-139-g860d86b4
Diffusion MRI Tool
itkMeshFromContinuousSphericalFunctionImageFilter.hxx
Go to the documentation of this file.
1 
18 #ifndef __itkMeshFromContinuousSphericalFunctionImageFilter_hxx
19 #define __itkMeshFromContinuousSphericalFunctionImageFilter_hxx
21 
22 #include "utl.h"
23 
24 #include "itkImageRegionIterator.h"
25 #include "itkImageRegionIteratorWithIndex.h"
26 #include "vtkColorTransferFunction.h"
27 
28 #include <vtkFloatArray.h>
29 #include <itkProgressReporter.h>
30 
31 namespace itk
32 {
33 
37 template<class TInputImage, class TOutputMesh>
40  m_BasisMatrix(new MatrixType())
41 {
42  m_TessellationOrder = 3;
43  m_BasicShape = SphereTessellatorType::ICOSAHEDRON;
44  m_SphereTessellator = SphereTessellatorType::New();
45 }
46 
50 template<class TInputImage, class TOutputMesh>
51 void
53 ::PrintSelf(std::ostream& os, Indent indent) const
54 {
55  Superclass::PrintSelf(os, indent);
56  os << indent << "m_BasicShape: " << m_BasicShape << std::endl;
57  os << indent << "m_TessellationOrder: " << m_TessellationOrder << std::endl;
58  os << indent << "m_Stretch: " << m_Stretch << std::endl;
59  utl::PrintUtlMatrix(*m_BasisMatrix, "m_BasisMatrix", " ", os<<indent);
60 }
61 
62 template <class TInputImage, class TOutputMesh>
63 typename LightObject::Pointer
66 {
67  typename LightObject::Pointer loPtr = Superclass::InternalClone();
68 
69  typename Self::Pointer rval = dynamic_cast<Self *>(loPtr.GetPointer());
70  if(rval.IsNull())
71  {
72  itkExceptionMacro(<< "downcast to type " << this->GetNameOfClass()<< " failed.");
73  }
74 
75  rval->m_SphereTessellator = m_SphereTessellator;
76  rval->m_BasicShape = m_BasicShape;
77  rval->m_TessellationOrder = m_TessellationOrder;
78 
79  rval->m_Stretch = m_Stretch;
80 
81  rval->m_BasisMatrix = m_BasisMatrix;
82 
83  return loPtr;
84 }
85 
86 template <class TInputImage, class TOutputMesh>
87 void
90 {
91  utlShowPosition(this->GetDebug());
92  InputImageConstPointer inputPtr = this->GetInput();
93 
94  this->VerifyInputParameters();
95 
96  this->m_SphereTessellator->SetBasicShape(this->m_BasicShape);
97  this->m_SphereTessellator->SetOrder(this->m_TessellationOrder);
98  this->m_SphereTessellator->TessellateSphere();
99  *this->m_Orientations = utl::VnlMatrixToUtlMatrix(this->m_SphereTessellator->GetPointsMatrix());
100  // utl::PrintUtlMatrix(*this->m_Orientations, "m_Orientations 0");
101 
102  // this->Print(std::cout<<"this");
103  this->ComputeBasisMatrix();
104 
105  if (this->GetDebug())
106  utl::PrintUtlMatrix(*this->m_BasisMatrix, "this->m_BasisMatrix");
107  utlGlobalException(this->m_BasisMatrix->Columns()<=0, "no m_BasisMatrix after run ComputeBasisMatrix()");
108 }
109 
111 template <class TInputImage, class TOutputMesh>
112 void
114 ::ThreadedGenerateData(const typename TInputImage::RegionType& regionForThread,ThreadIdType threadId )
115 {
116  utlShowPosition(this->GetDebug());
117  ProgressReporter progress(this, threadId, regionForThread.GetNumberOfPixels());
118 
119  // Pointers
120  InputImageConstPointer inputPtr = this->GetInput();
121  InputImagePixelType inputPixel;
122  inputPixel.SetSize(inputPtr->GetNumberOfComponentsPerPixel());
123 
124  // Compute Number Of Basis Functions
125  unsigned int numberOfBasis = this->m_BasisMatrix->Columns();
126 
127  // Input Image Parameters
128  InputImageIndexType inputIndex;
129  InputImagePointType inputPhysicalPoint;
130 
131  // iterator for the input image
132  ImageRegionConstIteratorWithIndex<InputImageType> inputIt(inputPtr, regionForThread);
133  // ImageRegionConstIteratorWithIndex<InputImageType> inputIt(inputPtr, inputPtr->GetLargestPossibleRegion());
134 
135  // Preparation work for vertices and cells
136  unsigned int numberOfPoints = 0;
137  unsigned int numberOfCells = 0;
138  vnl_matrix<unsigned long> cellMatrix;
139 
140  unsigned long offset = 0;
141 
142  numberOfPoints = this->m_SphereTessellator->GetNumberOfVertices();
143  numberOfCells = this->m_SphereTessellator->GetNumberOfFaces();
144  cellMatrix = this->m_SphereTessellator->GetCellsMatrix();
145 
146  // Matrices
147 
148  VectorType sf;
149  VectorType x(numberOfBasis);
150 
151  // Output Mesh
152  vtkSmartPointer<OutputMeshPointsType> outputMeshPoints = vtkSmartPointer<OutputMeshPointsType>::New();
153  vtkSmartPointer<OutputMeshCellArrayType> outputMeshCellArray = vtkSmartPointer<OutputMeshCellArrayType>::New();
154  vtkSmartPointer<OutputMeshRGBType> outputMeshRGB = vtkSmartPointer<OutputMeshRGBType>::New();
155  outputMeshRGB->SetNumberOfComponents(4);
156  outputMeshRGB->SetName("RGBA_scalars");
157 
158  double outputMeshPoint[3];
159  unsigned int numberOfCellPoints = 3;
160 
161  vtkSmartPointer<vtkColorTransferFunction> colorTransferFunction =
162  vtkSmartPointer<vtkColorTransferFunction>::New();
163  //double colorId = 0;
164  double rgb[3];
165  colorTransferFunction->SetColorSpaceToHSV();
166  colorTransferFunction->AddRGBPoint(0.0, 0, 0, 1);
167  colorTransferFunction->AddRGBPoint(0.5, 0, 1, 0);
168  colorTransferFunction->AddRGBPoint(1.0, 1, 0, 0);
169 
170  // Populate output mesh
171  offset = 0;
172  unsigned char RGB[4];
173 
174  // vtkSmartPointer<vtkFloatArray> newScalars= vtkSmartPointer<vtkFloatArray>::New();
175  // newScalars->SetNumberOfComponents(1);
176 
177  // sfMax and sfMin are used to scale spherical function samples into [0,1]
178  double sfMax= -std::numeric_limits<double>::max();
179  double sfMin= std::numeric_limits<double>::max();
180  if ( this->m_ColorScheme == Superclass::MAGNITUDE )
181  {
182  inputIt.GoToBegin();
183  while( !inputIt.IsAtEnd() )
184  {
185  inputIndex = inputIt.GetIndex();
186  if (!this->IsPixelIndexVisible(inputIndex))
187  {
188  ++inputIt;
189  continue;
190  }
191 
192  inputPixel = inputIt.Get();
193 
194  for (unsigned int k=0;k<numberOfBasis;k++)
195  x(k) = inputPixel[k];
196 
197  if (x.GetRootMeanSquares() == 0)
198  {
199  ++inputIt;
200  continue;
201  }
202 
203  // if (this->GetDebug())
204  // {
205  // std::cout << "index = " << inputIndex << std::endl << std::flush;
206  // utl::PrintUtlVector(x, "x");
207  // }
208 
209  if (this->m_Normalization==Superclass::UNIT_INTEGRAL)
210  {
211  x = this->NormalizeUnitIntegral(x);
212  }
213 
214  sf = (*this->m_BasisMatrix) * x;
215  // if (this->GetDebug())
216  // utl::PrintUtlVector(sf, "sf");
217 
218  ScaleSamples(sf);
219 
220  double maxVal = sf.MaxValue();
221  double minVal = sf.MinValue();
222  if (maxVal>sfMax)
223  sfMax = maxVal;
224  if (minVal<sfMin)
225  sfMin = minVal;
226 
227  ++inputIt;
228  }
229 
230  utlPrintVar(this->GetDebug(), sfMin, sfMax);
231 
232  // If sfMin == sfMax, set sfMin=0.
233  if (sfMax-sfMin<1e-2*std::fabs(sfMin))
234  {
235  sfMin=0.0;
236  if (sfMax==sfMin || sfMax<0)
237  sfMax=1.0;
238  }
239  }
240 
241  inputIt.GoToBegin();
242  while( !inputIt.IsAtEnd() )
243  {
244  inputIndex = inputIt.GetIndex();
245  if (!this->IsPixelIndexVisible(inputIndex))
246  {
247  ++inputIt;
248  progress.CompletedPixel();
249  continue;
250  }
251 
252  inputPtr->TransformIndexToPhysicalPoint(inputIndex, inputPhysicalPoint);
253  inputPixel = inputIt.Get();
254 
255  for (unsigned int k=0;k<numberOfBasis;k++)
256  x(k) = inputPixel[k];
257 
258  if (x.GetRootMeanSquares() == 0)
259  {
260  ++inputIt;
261  progress.CompletedPixel();
262  continue;
263  }
264 
265  if (this->GetDebug())
266  {
267  std::cout << "index = " << inputIndex << std::endl << std::flush;
268  utl::PrintUtlVector(x, "x");
269  }
270 
271  if (this->m_Normalization==Superclass::UNIT_INTEGRAL)
272  {
273  x = this->NormalizeUnitIntegral(x);
274  }
275 
276  sf = (*this->m_BasisMatrix) * x;
277  if (this->GetDebug())
278  utl::PrintUtlVector(sf, "sf");
279 
280  ScaleSamples(sf);
281 
282  for (unsigned int k=0;k<numberOfPoints;k++)
283  {
284  if ( this->m_ColorScheme == Superclass::MAGNITUDE )
285  {
286  colorTransferFunction->GetColor((sf(k)-sfMin)/(sfMax-sfMin), rgb);
287  for (unsigned int d=0;d<3;d++)
288  {
289  if (m_Stretch)
290  outputMeshPoint[d] = sf(k) * (*this->m_Orientations)(k,d) + inputPhysicalPoint[d];
291  else
292  outputMeshPoint[d] = this->m_Scale * (*this->m_Orientations)(k,d) + inputPhysicalPoint[d];
293  RGB[d] = static_cast<VTK_TYPE_NAME_UNSIGNED_CHAR>(rgb[d]*255.0);
294  }
295  }
296  else if ( this->m_ColorScheme == Superclass::DIRECTION )
297  {
298  for (unsigned int d=0;d<3;d++)
299  {
300  if (m_Stretch)
301  outputMeshPoint[d] = sf(k) * (*this->m_Orientations)(k,d) + inputPhysicalPoint[d];
302  else
303  outputMeshPoint[d] = this->m_Scale * (*this->m_Orientations)(k,d) + inputPhysicalPoint[d];
304  RGB[d] = static_cast<VTK_TYPE_NAME_UNSIGNED_CHAR>(std::fabs( (*this->m_Orientations)(k,d))*255.0);
305  }
306 
307  double min_val = std::numeric_limits<double>::max();
308  double max_val = -std::numeric_limits<double>::max();
309 
310  for (unsigned int d=0;d<3;d++)
311  {
312  if (RGB[d] > max_val)
313  max_val = RGB[d];
314  if (RGB[d] < min_val)
315  min_val = RGB[d];
316  }
317 
318  // min_val=0;
319  for (unsigned int d=0;d<3;d++)
320  {
321  RGB[d] = static_cast<VTK_TYPE_NAME_UNSIGNED_CHAR>( (RGB[d] - min_val)/(max_val - min_val) * 255.0 );
322  }
323 
324  // double ss;
325  // utl::RGBToIndex(std::fabs((*this->m_Orientations)(k,0)),std::fabs((*this->m_Orientations)(k,1)),std::fabs((*this->m_Orientations)(k,2)),ss);
326  // newScalars->InsertNextTuple(&ss);
327  // newScalars->SetName("rgb");
328  }
329 
330  RGB[3] = 255.0;
331 
332  outputMeshPoints->InsertNextPoint( outputMeshPoint );
333  outputMeshRGB->InsertNextTupleValue(RGB);
334  }
335 
336  for (vtkIdType c=0;c<numberOfCells;c++)
337  {
338  outputMeshCellArray->InsertNextCell(numberOfCellPoints);
339 
340  for( vtkIdType p = 0; p < numberOfCellPoints; p++ )
341  {
342  outputMeshCellArray->InsertCellPoint( offset + cellMatrix(c,p) );
343  }
344  }
345 
346  offset += numberOfPoints;
347 
348  ++inputIt;
349  progress.CompletedPixel();
350 
351  }
352 
353 
354  this->m_Mesh->SetPoints( outputMeshPoints );
355  this->m_Mesh->SetPolys( outputMeshCellArray );
356  this->m_Mesh->GetPointData()->SetScalars( outputMeshRGB );
357  // int idx = this->m_Mesh->GetPointData()->SetScalars( newScalars );
358  // this->m_Mesh->GetPointData()->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS);
359 }
360 
361 
362 template<class TInputImage, class TOutputMesh>
363 void
366 {
367  if (this->m_RemoveNegativeValues)
368  {
369  for (unsigned int k=0; k<sf.Size(); k++ )
370  {
371  if ( sf(k) < 0 )
372  sf(k) = 0;
373  }
374  }
375 
376  if (std::fabs(this->m_Pow-1.0)>1e-8)
377  {
378  for ( int k = 0; k < sf.Size(); k += 1 )
379  sf(k) = std::pow(sf(k), this->m_Pow);
380  }
381 
382 
383  if ( this->m_Normalization == Superclass::UNIT_MAX )
384  {
385  sf = sf/( sf.MaxValue() + vnl_math::eps );
386  }
387 
388  // perform min-max normalization
389  if ( this->m_Normalization==Superclass::MIN_MAX && sf.MaxValue()-sf.MinValue()>1e-8)
390  {
391  sf = (sf - sf.MinValue())/( sf.MaxValue() - sf.MinValue() + vnl_math::eps );
392  }
393 
394  sf %= this->m_Scale;
395 }
396 
397 } // end namespace itk
398 
399 #endif
400 
401 
402 
helper functions specifically used in dmritool
void PrintUtlMatrix(const NDArray< T, 2 > &mat, const std::string &str="", const char *separate=" ", std::ostream &os=std::cout)
const T & max(const T &a, const T &b)
Return the maximum between a and b.
Definition: utlCore.h:263
void ThreadedGenerateData(const typename TInputImage::RegionType &regionForThread, ThreadIdType threadId) ITK_OVERRIDE
#define utlGlobalException(cond, expout)
Definition: utlCoreMacro.h:372
void VnlMatrixToUtlMatrix(const vnl_matrix< T > &mat, utl::NDArray< T, 2 > &matUtl)
Definition: utlVNLIO.h:34
#define utlPrintVar(cond,...)
Definition: utlCoreMacro.h:309
Compute mesh from general spherical function.
Compute mesh from continuous spherical function linearly represented by a set of bases.
#define utlShowPosition(cond)
Definition: utlCoreMacro.h:554
void PrintUtlVector(const NDArray< T, 1 > &vec, const std::string &str="", const char *separate=" ", std::ostream &os=std::cout, bool showStats=true)