ANIMA  4.0
animaNLinksFilter.hxx
Go to the documentation of this file.
1 #pragma once
2 
3 #include "animaNLinksFilter.h"
4 
5 namespace anima
6 {
7 
8 template <typename TInput, typename TOutput>
10 {
11  this->SetNthInput(0, const_cast<TInput*>(image));
12  m_NbModalities++;
13  m_ListImages.push_back(image);
14 }
15 
16 template <typename TInput, typename TOutput>
18 {
19  this->SetNthInput(1, const_cast<TSeedProba*>(proba));
20 }
21 
22 template <typename TInput, typename TOutput>
24 {
25  this->SetNthInput(2, const_cast<TSeedProba*>(proba));
26 }
27 
28 template <typename TInput, typename TOutput>
30 {
31  this->SetNthInput(3, const_cast<TMask*>(mask));
32 }
33 
34 template <typename TInput, typename TOutput>
36 {
37  this->SetNthInput(m_NbInputs, const_cast<TInput*>(image));
38  m_IndexImage2 = m_NbInputs;
39  m_NbInputs++;
40  m_NbModalities++;
41  m_ListImages.push_back(image);
42 }
43 
44 template <typename TInput, typename TOutput>
46 {
47  this->SetNthInput(m_NbInputs, const_cast<TInput*>(image));
48  m_IndexImage3 = m_NbInputs;
49  m_NbInputs++;
50  m_NbModalities++;
51  m_ListImages.push_back(image);
52 }
53 
54 template <typename TInput, typename TOutput>
56 {
57  this->SetNthInput(m_NbInputs, const_cast<TInput*>(image));
58  m_IndexImage4 = m_NbInputs;
59  m_NbInputs++;
60  m_NbModalities++;
61  m_ListImages.push_back(image);
62 }
63 
64 template <typename TInput, typename TOutput>
66 {
67  this->SetNthInput(m_NbInputs, const_cast<TInput*>(image));
68  m_IndexImage5 = m_NbInputs;
69  m_NbInputs++;
70  m_NbModalities++;
71  m_ListImages.push_back(image);
72 }
73 
74 
75 template <typename TInput, typename TOutput>
76 typename TInput::ConstPointer NLinksFilter<TInput, TOutput>::GetInputImage1()
77 {
78  return static_cast< const TInput * >
79  ( this->itk::ProcessObject::GetInput(0) );
80 }
81 
82 template <typename TInput, typename TOutput>
83 itk::Image <double,3>::ConstPointer NLinksFilter<TInput, TOutput>::GetInputSeedProbaSources()
84 {
85  return static_cast< const TSeedProba * >
86  ( this->itk::ProcessObject::GetInput(1) );
87 }
88 
89 template <typename TInput, typename TOutput>
90 itk::Image <double,3>::ConstPointer NLinksFilter<TInput, TOutput>::GetInputSeedProbaSinks()
91 {
92  return static_cast< const TSeedProba * >
93  ( this->itk::ProcessObject::GetInput(2) );
94 }
95 
96 template <typename TInput, typename TOutput>
97 itk::Image <unsigned char,3>::ConstPointer NLinksFilter<TInput, TOutput>::GetMask()
98 {
99  return static_cast< const TMask * >
100  ( this->itk::ProcessObject::GetInput(3) );
101 }
102 
103 template <typename TInput, typename TOutput>
104 typename TInput::ConstPointer NLinksFilter<TInput, TOutput>::GetInputImage2()
105 {
106  return static_cast< const TInput * >
107  ( this->itk::ProcessObject::GetInput(m_IndexImage2) );
108 }
109 
110 template <typename TInput, typename TOutput>
111 typename TInput::ConstPointer NLinksFilter<TInput, TOutput>::GetInputImage3()
112 {
113  return static_cast< const TInput * >
114  ( this->itk::ProcessObject::GetInput(m_IndexImage3) );
115 }
116 
117 template <typename TInput, typename TOutput>
118 typename TInput::ConstPointer NLinksFilter<TInput, TOutput>::GetInputImage4()
119 {
120  return static_cast< const TInput * >
121  ( this->itk::ProcessObject::GetInput(m_IndexImage4) );
122 }
123 
124 template <typename TInput, typename TOutput>
125 typename TInput::ConstPointer NLinksFilter<TInput, TOutput>::GetInputImage5()
126 {
127  return static_cast< const TInput * >
128  ( this->itk::ProcessObject::GetInput(m_IndexImage5) );
129 }
130 
131 
132 template <typename TInputImage, typename TOutput>
133 itk::DataObject::Pointer NLinksFilter <TInputImage, TOutput>::MakeOutput(unsigned int idx)
134 {
135  itk::DataObject::Pointer output;
136 
137  switch ( idx )
138  {
139  case 0:
140  output = ( TOutput::New() ).GetPointer();
141  break;
142  case 1:
143  output = ( TOutput::New() ).GetPointer();
144  break;
145  default:
146  std::cerr << "No output " << idx << std::endl;
147  output = NULL;
148  break;
149  }
150  return output.GetPointer();
151 }
152 
153 template <typename TInputImage, typename TOutput>
155 {
156  return dynamic_cast< TOutput* >( this->itk::ProcessObject::GetOutput(0) );
157 }
158 template <typename TInputImage, typename TOutput>
160 {
161  return dynamic_cast< TOutput* >( this->itk::ProcessObject::GetOutput(1) );
162 }
163 
164 template <typename TInput, typename TOutput>
166 {
167  // Read and Parse the data
168  typedef itk::CSVArray2DFileReader<double> ReaderType;
169  ReaderType::Pointer reader = ReaderType::New();
170 
171  reader->SetFileName ( m_MatFilename );
172  reader->SetFieldDelimiterCharacter( ';' );
173  reader->SetStringDelimiterCharacter( '"' );
174  reader->HasColumnHeadersOff();
175  reader->HasRowHeadersOff();
176 
177  // Try Non-existent filename
178  try
179  {
180  reader->Parse();
181  }
182  catch( itk::ExceptionObject & exp )
183  {
184  std::cerr << "Expected Exception caught!" << std::endl;
185  std::cerr << exp << std::endl;
186  return false;
187  }
188 
189  reader->Print(std::cout);
190 
191  typedef itk::CSVArray2DDataObject<double> DataFrameObjectType;
192  DataFrameObjectType::Pointer dfo = reader->GetOutput();
193 
194  m_Matrix = dfo->GetMatrix();
195  return true;
196 }
197 
198 template <typename TInput, typename TOutput>
199 void
202 {
203  unsigned int nbInputs = this->GetNumberOfIndexedInputs();
204  if (nbInputs < 4)
205  {
206  std::cerr << "Error: No inputs available... Exiting..." << std::endl;
207  exit(-1);
208  }
209 
210  if((m_MatFilename!="") && m_UseSpectralGradient)
211  {
212  if(m_ListImages.size()<3)
213  {
214  std::cerr << "-- Error in Graph3D: Wrong number of images, must be equal or superior to 3" << std::endl;
215  exit(-1);
216  }
217  if(!readMatrixFile())
218  {
219  std::cerr << "-- Error in Graph3D: error while reading matrix file" << std::endl;
220  exit(-1);
221  }
222  if( (m_Matrix.Rows()!=3) || (m_Matrix.Cols()!=m_ListImages.size()) )
223  {
224  std::cerr << "-- Error in Graph3D: Wrong number of coefficients in matrix after reading matrix csv file" << std::endl;
225  exit(-1);
226  }
227  std::cout << "using matfilename" << std::endl;
228  }
229  else if( (m_Matrix.Rows()!=0) && m_UseSpectralGradient)
230  {
231  if( (m_Matrix.Rows()!=3) || (m_Matrix.Cols()!=m_ListImages.size()) )
232  {
233  std::cerr << "-- Error in NLinksFilter: Wrong number of coefficients in spectral gradient matrix" << std::endl;
234  std::cerr << "-- Matrix.Rows(): " << m_Matrix.Rows() << std::endl;
235  std::cerr << "-- Matrix.Cols(): " << m_Matrix.Cols() << std::endl;
236  std::cerr << "-- ListImages.size(): " << m_ListImages.size()<< std::endl;
237  exit(-1);
238  }
239 
240  std::cout << "using given matrix" << std::endl;
241  std::cout << m_Matrix(0,0) << " "<< m_Matrix(0,1) << " "<< m_Matrix(0,2) << std::endl;
242  std::cout << m_Matrix(1,0) << " "<< m_Matrix(1,1) << " "<< m_Matrix(1,2) << std::endl;
243  std::cout << m_Matrix(2,0) << " "<< m_Matrix(2,1) << " "<< m_Matrix(2,2) << std::endl;
244  }
245  else
246  {
247  // If no matrix is given, set orginal spectral gradient
248  m_Matrix.SetSize(3,3);
249 
250  m_Matrix(0,0) = 0.002358; m_Matrix(0,1) = 0.025174; m_Matrix(0,2) = 0.010821;
251  m_Matrix(1,0) = 0.011943; m_Matrix(1,1) = 0.001715; m_Matrix(1,2) = -0.013994;
252  m_Matrix(2,0) = 0.013743; m_Matrix(2,1) = -0.023965; m_Matrix(2,2) = 0.00657;
253 
254  // Check if possible use of spectral gradient
255  if (m_UseSpectralGradient && (m_ListImages.size() != 3))
256  {
257  std::cerr << "-- Warning in Graph3D: the spectral gradient requires 3 modalities" << std::endl << "Falling back to conventional gradient approach" << std::endl;
258  m_UseSpectralGradient = false;
259  }
260 
261  if (m_UseSpectralGradient)
262  std::cout << "using original grad spec" << std::endl;
263  else
264  std::cout << "NO using grad spec" << std::endl;
265  }
266 
267  m_size = this->GetMask()->GetLargestPossibleRegion().GetSize();
268 
269 }
270 
271 template <typename TInput, typename TOutput>
272 void
275 {
276  typename TOutput::Pointer output = this->GetOutput();
277  output->SetRegions(this->GetMask()->GetLargestPossibleRegion());
278  output->CopyInformation(this->GetMask());
279  output->Allocate();
280  output->FillBuffer(0);
281 
282  typename TOutput::Pointer outputBackground = this->GetOutputBackground();
283  outputBackground->SetRegions(this->GetMask()->GetLargestPossibleRegion());
284  outputBackground->CopyInformation(this->GetMask());
285  outputBackground->Allocate();
286  outputBackground->FillBuffer(0);
287 
288  std::cout << "Computing N-Links..."<< std::endl;
289 
290  this->CheckSpectralGradient();
291  this->CreateGraph();
292  this->SetGraph();
293 
294  m_graph -> maxflow();
295 
296  int cpt=0;
297  MaskRegionConstIteratorType maskIt (this->GetMask(),this->GetMask()->GetLargestPossibleRegion());
298  OutputIteratorType outIt (output,output->GetLargestPossibleRegion() );
299  OutputIteratorType outBackgroundIt (outputBackground,outputBackground->GetLargestPossibleRegion() );
300 
301  while (!maskIt.IsAtEnd())
302  {
303  outIt.Set(0);
304  if (maskIt.Get() != 0)
305  {
306  int v = m_graph->what_segment(cpt);
307  unsigned char buff = 0 | (v == GraphType::SOURCE) ? 1 : 0;
308  outIt.Set(static_cast<OutputPixelType>(buff));
309  outBackgroundIt.Set(1-buff);
310  cpt++;
311  }
312  ++maskIt;
313  ++outBackgroundIt;
314  ++outIt;
315  }
316 
317  m_NbModalities = 0;
318  m_NbInputs = 3;
319  m_ListImages.clear();
320  if (m_graph) delete m_graph;
321 
322 }
323 
324 
325 template <typename TInput, typename TOutput>
326 double NLinksFilter<TInput, TOutput>::computeNLink(int i1, int j1, int k1, int i2, int j2, int k2)
327 {
328  pixelIndexInt index1, index2;
329  index1[0]=i1;
330  index1[1]=j1;
331  index1[2]=k1;
332 
333  index2[0]=i2;
334  index2[1]=j2;
335  index2[2]=k2;
336 
337  if (m_UseSpectralGradient)
338  {
339  double g = m_e1->GetPixel(index1) - m_e1->GetPixel(index2);
340  double w = m_e2->GetPixel(index1) - m_e2->GetPixel(index2);
341  return static_cast<double>((.1+std::exp(-(g * g + w * w) / (2 * m_Sigma * m_Sigma))));
342  }
343  else
344  {
345  int dim = m_ListImages.size();
346  double g;
347  double sum = 0.0;
348  for (int m=0; m<dim; m++)
349  {
350  g = m_ListImages[m]->GetPixel(index1) - m_ListImages[m]->GetPixel(index2);
351  sum += g * g;
352  }
353  return static_cast<double>((.1+std::exp(- sum / (2 * m_Sigma * m_Sigma))));
354  }
355 }
356 
357 template <typename TInput, typename TOutput>
359 {
360  // Compute e, e_l, e_l_l
361  // These quantities are useful to compute the spectral gradient
362  if(m_UseSpectralGradient)
363  {
364  m_e1 = TSeedProba::New();
365  m_e1->SetRegions(this->GetMask()->GetLargestPossibleRegion());
366  m_e1->CopyInformation(this->GetMask());
367  m_e1->Allocate();
368  m_e1->FillBuffer(0);
369 
370  m_e2 = TSeedProba::New();
371  m_e2->SetRegions(this->GetMask()->GetLargestPossibleRegion());
372  m_e2->CopyInformation(this->GetMask());
373  m_e2->Allocate();
374  m_e2->FillBuffer(0);
375 
376  ImageIteratorTypeProba e1It (m_e1, m_e1->GetLargestPossibleRegion() );
377  ImageIteratorTypeProba e2It (m_e2, m_e2->GetLargestPossibleRegion() );
378 
379  std::vector<InRegionConstIteratorType > ListImagesVectorIt;
380  for ( unsigned int i = 0; i < m_ListImages.size(); i++ )
381  {
382  InRegionConstIteratorType It(m_ListImages[i],m_ListImages[i]->GetLargestPossibleRegion() );
383  ListImagesVectorIt.push_back(It);
384  }
385 
386  while((!e1It.IsAtEnd()) && (!e2It.IsAtEnd()))
387  {
388 
389  double e = 0;
390  double e_l = 0;
391  double e_l_l = 0;
392 
393  for(unsigned int m=0; m < m_ListImages.size(); m++)
394  {
395  e += m_Matrix(0,m) * (ListImagesVectorIt[m].Get());
396  e_l += m_Matrix(1,m) * (ListImagesVectorIt[m].Get());
397  e_l_l += m_Matrix(2,m) * (ListImagesVectorIt[m].Get());
398  }
399  e1It.Set(e_l/e);
400  e2It.Set((e*e_l_l-std::pow(e_l, 2.f)) / std::pow(e,2.f) );
401 
402  ++e1It;
403  ++e2It;
404  for ( unsigned int i = 0; i < m_ListImages.size(); i++ )
405  {
406  ++ListImagesVectorIt[i];
407  }
408  }
409 
410  }
411 }
412 
413 template <typename TInput, typename TOutput>
414 bool NLinksFilter<TInput, TOutput>::isInside (unsigned int x, unsigned int y, unsigned int z ) const
415 {
416  return ( x < m_size[0] && y < m_size[1] && z < m_size[2] && x >= 0 && y >= 0 && z >= 0 );
417 }
418 
419 template <typename TInput, typename TOutput>
421 {
422  // allocate only necessary memory
423  int nb_vox = 0;
424 
425  MaskRegionConstIteratorType maskIt (this->GetMask(),this->GetMask()->GetLargestPossibleRegion() );
426  while (!maskIt.IsAtEnd())
427  {
428  if (maskIt.Get() != 0)
429  {
430  nb_vox++;
431  }
432  ++maskIt;
433  }
434 
435  int nb_edges = 7*nb_vox;
436 
437  try
438  {
439  m_graph = new GraphType(nb_vox, nb_edges);
440  }
441  catch (std::bad_alloc& ba)
442  {
443  std::cerr << "-- Error in NLinksFilter: insufficient memory to create the graph: " << ba.what() << '\n';
444  exit(-1);
445  }
446 
447  // Create the nodes of the graph and set the correspondences with the original image
448  int compt = 0;
449  ImageTypeInt::Pointer pix = ImageTypeInt::New();
450  pix->SetRegions(this->GetMask()->GetLargestPossibleRegion());
451  pix->CopyInformation(this->GetMask());
452  pix->Allocate();
453  pix->FillBuffer(-1);
454 
455  ImageIteratorTypeInt pixIt (pix,pix->GetLargestPossibleRegion());
456 
457  maskIt.GoToBegin();
458  while (!maskIt.IsAtEnd())
459  {
460  if (maskIt.Get() != 0)
461  {
462  m_graph -> add_node();
463  pixIt.Set(compt++);
464  }
465  ++maskIt;
466  ++pixIt;
467  }
468 
469 
470  maskIt.GoToBegin();
471  pixIt.GoToBegin();
472 
473 
474  // Create the t-links and n-links
475  while (!maskIt.IsAtEnd())
476  {
477  if(maskIt.Get() != 0)
478  {
479  pixelIndexInt index, index1;
480  index[0]=maskIt.GetIndex()[0];
481  index[1]=maskIt.GetIndex()[1];
482  index[2]=maskIt.GetIndex()[2];
483 
484  int pix_ref = pix->GetPixel(index);
485  int pix_courant;
486  double cap, rcap;
487 
488  // Compute the 6 n-links of each standard node (gradients between the current voxel and its neighbors)
489  index1[0]=index[0]+1;
490  index1[1]=index[1];
491  index1[2]=index[2];
492  if ( (isInside(index[0]+1, index[1] , index[2])) && (this->GetMask()->GetPixel(index1)!=0) )
493  {
494  pix_courant = pix->GetPixel(index1);
495  cap = computeNLink(index[0]+1, index[1], index[2], index[0], index[1], index[2]);
496  rcap = cap;
497  if (!(cap >= 0))
498  cap = rcap = 0;
499  m_graph -> add_edge(pix_ref, pix_courant, cap, rcap);
500  }
501 
502 
503  index1[0]=index[0];
504  index1[1]=index[1]+1;
505  index1[2]=index[2];
506  if ( (isInside(index[0], index[1]+1 , index[2])) && (this->GetMask()->GetPixel(index1)!=0) )
507  {
508  pix_courant = pix->GetPixel(index1);
509  cap = computeNLink(index[0], index[1]+1, index[2], index[0], index[1], index[2]);
510  rcap = cap;
511  if (!(cap >= 0)) // eq cap < 0 ? no ???
512  cap = rcap = 0;
513  m_graph -> add_edge(pix_ref, pix_courant, cap, rcap);
514  }
515 
516  index1[0]=index[0];
517  index1[1]=index[1];
518  index1[2]=index[2]+1;
519  if ( (isInside(index[0], index[1] , index[2]+1)) && (this->GetMask()->GetPixel(index1)!=0) )
520  {
521  pix_courant = pix->GetPixel(index1);
522  cap = computeNLink(index[0], index[1], index[2]+1, index[0], index[1], index[2]);
523  rcap = cap;
524  if (!(cap >= 0))
525  cap = rcap = 0;
526  m_graph -> add_edge(pix_ref, pix_courant, cap, rcap);
527  }
528 
529  // Create the t-links to the source and the sink
530  double t_source = static_cast<double>(this->GetInputSeedProbaSources()->GetPixel(index));
531  double t_sink = static_cast<double>(this->GetInputSeedProbaSinks()->GetPixel(index));
532  m_graph -> add_tweights(pix_ref, t_source, t_sink);
533 
534  }
535 
536  ++pixIt;
537  ++maskIt;
538  }
539 }
540 
541 } //end of namespace anima
TInput::ConstPointer GetInputImage2()
Class creating a 3D graph in a graph cut framework.
itk::ImageRegionIterator< TSeedProba > ImageIteratorTypeProba
TInput::ConstPointer GetInputImage1()
itk::Image< PixelTypeD, 3 > TSeedProba
TSeedProba::ConstPointer GetInputSeedProbaSinks()
void SetInputImage4(const TInput *image)
ImageTypeInt::IndexType pixelIndexInt
void GenerateData() ITK_OVERRIDE
void SetMask(const TMask *mask)
TMask::ConstPointer GetMask()
itk::ImageRegionConstIterator< TInput > InRegionConstIteratorType
void SetInputSeedProbaSinks(const TSeedProba *mask)
TInput::ConstPointer GetInputImage5()
TSeedProba::ConstPointer GetInputSeedProbaSources()
TInput::ConstPointer GetInputImage3()
void SetInputImage5(const TInput *image)
itk::ImageRegionIterator< TOutput > OutputIteratorType
void SetInputImage2(const TInput *image)
itk::ImageRegionIterator< ImageTypeInt > ImageIteratorTypeInt
double computeNLink(int i1, int j1, int k1, int i2, int j2, int k2)
itk::ImageRegionConstIterator< TMask > MaskRegionConstIteratorType
itk::Image< PixelTypeUC, 3 > TMask
TInput::ConstPointer GetInputImage4()
void SetInputImage1(const TInput *image)
bool isInside(unsigned int x, unsigned int y, unsigned int z) const
void SetInputSeedProbaSources(const TSeedProba *mask)
void SetInputImage3(const TInput *image)