Orfeo Toolbox  3.16
itkFastMarchingImageFilter.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkFastMarchingImageFilter.txx,v $
5  Language: C++
6  Date: $Date: 2010-07-02 13:28:09 $
7  Version: $Revision: 1.54 $
8 
9  Copyright (c) Insight Software Consortium. All rights reserved.
10  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
11 
12  This software is distributed WITHOUT ANY WARRANTY; without even
13  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  PURPOSE. See the above copyright notices for more information.
15 
16 =========================================================================*/
17 #ifndef __itkFastMarchingImageFilter_txx
18 #define __itkFastMarchingImageFilter_txx
19 
21 #include "itkImageRegionIterator.h"
22 #include "itkNumericTraits.h"
23 #include "vnl/vnl_math.h"
24 #include <algorithm>
25 
26 namespace itk
27 {
28 
29 template <class TLevelSet, class TSpeedImage>
32  : m_TrialHeap( )
33 {
34 
36 
37  OutputSizeType outputSize;
38  outputSize.Fill( 16 );
39  typename LevelSetImageType::IndexType outputIndex;
40  outputIndex.Fill( 0 );
41 
42  m_OutputRegion.SetSize( outputSize );
43  m_OutputRegion.SetIndex( outputIndex );
44 
45  m_OutputOrigin.Fill( 0.0 );
46  m_OutputSpacing.Fill( 1.0 );
47  m_OutputDirection.SetIdentity();
48  m_OverrideOutputInformation = false;
49 
50  m_AlivePoints = NULL;
51  m_TrialPoints = NULL;
52  m_ProcessedPoints = NULL;
53 
54  m_SpeedConstant = 1.0;
55  m_InverseSpeed = -1.0;
56  m_LabelImage = LabelImageType::New();
57 
58  m_LargeValue = static_cast<PixelType>( NumericTraits<PixelType>::max() / 2.0 );
59  m_StoppingValue = static_cast<double>( m_LargeValue );
60  m_CollectPoints = false;
61 
62  m_NormalizationFactor = 1.0;
63 }
64 
65 template <class TLevelSet, class TSpeedImage>
66 void
68 ::PrintSelf(std::ostream& os, Indent indent) const
69 {
70  Superclass::PrintSelf(os,indent);
71  os << indent << "Alive points: " << m_AlivePoints.GetPointer() << std::endl;
72  os << indent << "Trial points: " << m_TrialPoints.GetPointer() << std::endl;
73  os << indent << "Speed constant: " << m_SpeedConstant << std::endl;
74  os << indent << "Stopping value: " << m_StoppingValue << std::endl;
75  os << indent << "Large Value: "
76  << static_cast<typename NumericTraits<PixelType>::PrintType>(m_LargeValue)
77  << std::endl;
78  os << indent << "Normalization Factor: " << m_NormalizationFactor << std::endl;
79  os << indent << "Collect points: " << m_CollectPoints << std::endl;
80  os << indent << "OverrideOutputInformation: ";
81  os << m_OverrideOutputInformation << std::endl;
82  os << indent << "OutputRegion: " << m_OutputRegion << std::endl;
83  os << indent << "OutputOrigin: " << m_OutputOrigin << std::endl;
84  os << indent << "OutputSpacing: " << m_OutputSpacing << std::endl;
85  os << indent << "OutputDirection: " << m_OutputDirection << std::endl;
86 }
87 
88 template <class TLevelSet, class TSpeedImage>
89 void
92 {
93 
94  // copy output information from input image
95  Superclass::GenerateOutputInformation();
96 
97  // use user-specified output information
98  if ( this->GetInput() == NULL || m_OverrideOutputInformation )
99  {
100  LevelSetPointer output = this->GetOutput();
101  output->SetLargestPossibleRegion( m_OutputRegion );
102  output->SetOrigin( m_OutputOrigin );
103  output->SetSpacing( m_OutputSpacing );
104  output->SetDirection( m_OutputDirection );
105  }
106 }
107 
108 template <class TLevelSet, class TSpeedImage>
109 void
112  DataObject *output )
113 {
114  // enlarge the requested region of the output
115  // to the whole data set
116  TLevelSet * imgData;
117 
118  imgData = dynamic_cast<TLevelSet*>( output );
119  if ( imgData )
120  {
121  imgData->SetRequestedRegionToLargestPossibleRegion();
122  }
123  else
124  {
125  // Pointer could not be cast to TLevelSet *
126  itkWarningMacro(<< "itk::FastMarchingImageFilter" <<
127  "::EnlargeOutputRequestedRegion cannot cast "
128  << typeid(output).name() << " to "
129  << typeid(TLevelSet*).name() );
130  }
131 
132 }
133 
134 template <class TLevelSet, class TSpeedImage>
135 void
138 {
139 
140  // allocate memory for the output buffer
141  output->SetBufferedRegion( output->GetRequestedRegion() );
142  output->Allocate();
143 
144  // cache some buffered region information
145  m_BufferedRegion = output->GetBufferedRegion();
146  m_StartIndex = m_BufferedRegion.GetIndex();
147  m_LastIndex = m_StartIndex + m_BufferedRegion.GetSize();
148  typename LevelSetImageType::OffsetType offset;
149  offset.Fill( 1 );
150  m_LastIndex -= offset;
151 
152  // allocate memory for the PointTypeImage
153  m_LabelImage->CopyInformation( output );
154  m_LabelImage->SetBufferedRegion(
155  output->GetBufferedRegion() );
156  m_LabelImage->Allocate();
157 
158  // set all output value to infinity
160  OutputIterator;
161 
162  OutputIterator outIt ( output, output->GetBufferedRegion() );
163 
164  PixelType outputPixel;
165  outputPixel = m_LargeValue;
166 
167  for ( outIt.GoToBegin(); !outIt.IsAtEnd(); ++outIt )
168  {
169  outIt.Set( outputPixel );
170  }
171 
172 
173  // set all points type to FarPoint
174  typedef ImageRegionIterator< LabelImageType > LabelIterator;
175 
176  LabelIterator typeIt( m_LabelImage,
177  m_LabelImage->GetBufferedRegion() );
178 
179  for ( typeIt.GoToBegin(); !typeIt.IsAtEnd(); ++typeIt )
180  {
181  typeIt.Set( FarPoint );
182  }
183 
184 
185  // process input alive points
186  AxisNodeType node;
187 
188  if ( m_AlivePoints )
189  {
190  typename NodeContainer::ConstIterator pointsIter = m_AlivePoints->Begin();
191  typename NodeContainer::ConstIterator pointsEnd = m_AlivePoints->End();
192 
193  for (; pointsIter != pointsEnd; ++pointsIter )
194  {
195 
196  // get node from alive points container
197  node = pointsIter.Value();
198 
199  // check if node index is within the output level set
200  if ( !m_BufferedRegion.IsInside( node.GetIndex() ) )
201  {
202  continue;
203  }
204 
205  // make this an alive point
206  m_LabelImage->SetPixel( node.GetIndex(), AlivePoint );
207 
208  outputPixel = node.GetValue();
209  output->SetPixel( node.GetIndex(), outputPixel );
210 
211  }
212  }
213 
214 
215  // make sure the heap is empty
216  while ( !m_TrialHeap.empty() )
217  {
218  m_TrialHeap.pop();
219  }
220 
221 
222  // process the input trial points
223  if ( m_TrialPoints )
224  {
225  typename NodeContainer::ConstIterator pointsIter = m_TrialPoints->Begin();
226  typename NodeContainer::ConstIterator pointsEnd = m_TrialPoints->End();
227 
228  for (; pointsIter != pointsEnd; ++pointsIter )
229  {
230 
231  // get node from trial points container
232  node = pointsIter.Value();
233 
234  // check if node index is within the output level set
235  if ( !m_BufferedRegion.IsInside( node.GetIndex() ) )
236  {
237  continue;
238  }
239 
240 #ifdef ITK_USE_DEPRECATED_FAST_MARCHING
241  // make this a trial point
242  m_LabelImage->SetPixel( node.GetIndex(), TrialPoint );
243 #else
244  // make this an initial trial point
245  m_LabelImage->SetPixel( node.GetIndex(), InitialTrialPoint );
246 #endif
247 
248  outputPixel = node.GetValue();
249  output->SetPixel( node.GetIndex(), outputPixel );
250 
251  m_TrialHeap.push( node );
252 
253  }
254  }
255 
256 }
257 
258 template <class TLevelSet, class TSpeedImage>
259 void
262 {
263 
264  LevelSetPointer output = this->GetOutput();
265  SpeedImageConstPointer speedImage = this->GetInput();
266 
267  this->Initialize( output );
268 
269  if ( m_CollectPoints )
270  {
271  m_ProcessedPoints = NodeContainer::New();
272  }
273 
274  // process points on the heap
275  AxisNodeType node;
276  double currentValue;
277  double oldProgress = 0;
278 
279  this->UpdateProgress( 0.0 ); // Send first progress event
280 
281  while ( !m_TrialHeap.empty() )
282  {
283  // get the node with the smallest value
284  node = m_TrialHeap.top();
285  m_TrialHeap.pop();
286 
287  // does this node contain the current value ?
288  currentValue = (double) output->GetPixel( node.GetIndex() );
289 
290  if ( node.GetValue() != currentValue )
291  {
292  continue;
293  }
294 
295  // is this node already alive ?
296 #ifdef ITK_USE_DEPRECATED_FAST_MARCHING
297  if ( m_LabelImage->GetPixel( node.GetIndex() ) != TrialPoint )
298 #else
299  if ( m_LabelImage->GetPixel( node.GetIndex() ) == AlivePoint )
300 #endif
301  {
302  continue;
303  }
304 
305  if ( currentValue > m_StoppingValue )
306  {
307  this->UpdateProgress( 1.0 );
308  break;
309  }
310 
311  if ( m_CollectPoints )
312  {
313  m_ProcessedPoints->InsertElement( m_ProcessedPoints->Size(), node );
314  }
315 
316  // set this node as alive
317  m_LabelImage->SetPixel( node.GetIndex(), AlivePoint );
318 
319  // update its neighbors
320  this->UpdateNeighbors( node.GetIndex(), speedImage, output );
321 
322 
323  // Send events every certain number of points.
324  const double newProgress = currentValue / m_StoppingValue;
325  if( newProgress - oldProgress > 0.01 ) // update every 1%
326  {
327  this->UpdateProgress( newProgress );
328  oldProgress = newProgress;
329  if( this->GetAbortGenerateData() )
330  {
331  this->InvokeEvent( AbortEvent() );
332  this->ResetPipeline();
333  ProcessAborted e(__FILE__,__LINE__);
334  e.SetDescription("Process aborted.");
335  e.SetLocation(ITK_LOCATION);
336  throw e;
337  }
338  }
339 
340  }
341 
342 }
343 
344 template <class TLevelSet, class TSpeedImage>
345 void
348  const IndexType& index,
349  const SpeedImageType * speedImage,
350  LevelSetImageType * output )
351 {
352  IndexType neighIndex = index;
353 
354  for ( unsigned int j = 0; j < SetDimension; j++ )
355  {
356  // update left neighbor
357  if( index[j] > m_StartIndex[j] )
358  {
359  neighIndex[j] = index[j] - 1;
360  }
361 #ifdef ITK_USE_DEPRECATED_FAST_MARCHING
362  if ( m_LabelImage->GetPixel( neighIndex ) != AlivePoint )
363 #else
364  unsigned char label = m_LabelImage->GetPixel( neighIndex );
365  if ( label != AlivePoint && label != InitialTrialPoint )
366 #endif
367  {
368  this->UpdateValue( neighIndex, speedImage, output );
369  }
370 
371  // update right neighbor
372  if ( index[j] < m_LastIndex[j] )
373  {
374  neighIndex[j] = index[j] + 1;
375  }
376 #ifdef ITK_USE_DEPRECATED_FAST_MARCHING
377  if ( m_LabelImage->GetPixel( neighIndex ) != AlivePoint )
378 #else
379  label = m_LabelImage->GetPixel( neighIndex );
380  if ( label != AlivePoint && label != InitialTrialPoint )
381 #endif
382  {
383  this->UpdateValue( neighIndex, speedImage, output );
384  }
385 
386  //reset neighIndex
387  neighIndex[j] = index[j];
388 
389  }
390 
391 }
392 
393 template <class TLevelSet, class TSpeedImage>
394 double
397  const IndexType& index,
398  const SpeedImageType * speedImage,
399  LevelSetImageType * output )
400 {
401 
402  IndexType neighIndex = index;
403  typename TLevelSet::PixelType neighValue;
404  PixelType outputPixel;
405  AxisNodeType node;
406 
407  for ( unsigned int j = 0; j < SetDimension; j++ )
408  {
409  node.SetValue( m_LargeValue );
410 
411  // find smallest valued neighbor in this dimension
412  for( int s = -1; s < 2; s = s + 2 )
413  {
414  neighIndex[j] = index[j] + s;
415 
416  if( neighIndex[j] > m_LastIndex[j] ||
417  neighIndex[j] < m_StartIndex[j] )
418  {
419  continue;
420  }
421 
422  if ( m_LabelImage->GetPixel( neighIndex ) == AlivePoint )
423  {
424  outputPixel = output->GetPixel( neighIndex );
425  neighValue = outputPixel;
426 
427  if( node.GetValue() > neighValue )
428  {
429  node.SetValue( neighValue );
430  node.SetIndex( neighIndex );
431  }
432  }
433 
434  }
435 
436  // put the minimum neighbor onto the heap
437  m_NodesUsed[j] = node;
438  m_NodesUsed[j].SetAxis(j);
439 
440  // reset neighIndex
441  neighIndex[j] = index[j];
442  }
443 
444  // sort the local list
445  std::sort( m_NodesUsed, m_NodesUsed + SetDimension );
446 
447  // solve quadratic equation
448  double aa, bb, cc;
449  double solution = m_LargeValue;
450 
451  aa = 0.0;
452  bb = 0.0;
453  if ( speedImage )
454  {
455  typedef typename SpeedImageType::PixelType SpeedPixelType;
456  cc = (double) speedImage->GetPixel( index ) / m_NormalizationFactor;
457  cc = -1.0 * vnl_math_sqr( 1.0 / cc );
458  }
459  else
460  {
461  cc = m_InverseSpeed;
462  }
463 
464  OutputSpacingType spacing = this->GetOutput()->GetSpacing();
465 
466  double discrim;
467 
468  for ( unsigned int j = 0; j < SetDimension; j++ )
469  {
470  node = m_NodesUsed[j];
471 
472  if ( solution >= node.GetValue() )
473  {
474  const int axis = node.GetAxis();
475  const double spaceFactor = vnl_math_sqr( 1.0 / spacing[axis] );
476  const double value = double(node.GetValue());
477  aa += spaceFactor;
478  bb += value * spaceFactor;
479  cc += vnl_math_sqr( value ) * spaceFactor;
480 
481  discrim = vnl_math_sqr( bb ) - aa * cc;
482  if ( discrim < 0.0 )
483  {
484  // Discriminant of quadratic eqn. is negative
485  ExceptionObject err(__FILE__, __LINE__);
486  err.SetLocation( ITK_LOCATION );
487  err.SetDescription( "Discriminant of quadratic equation is negative" );
488  throw err;
489  }
490 
491  solution = ( vcl_sqrt( discrim ) + bb ) / aa;
492  }
493  else
494  {
495  break;
496  }
497  }
498 
499  if ( solution < m_LargeValue )
500  {
501  // write solution to m_OutputLevelSet
502  outputPixel = static_cast<PixelType>( solution );
503  output->SetPixel( index, outputPixel );
504 
505  // insert point into trial heap
506  m_LabelImage->SetPixel( index, TrialPoint );
507  node.SetValue( static_cast<PixelType>( solution ) );
508  node.SetIndex( index );
509  m_TrialHeap.push( node );
510  }
511 
512  return solution;
513 
514 }
515 
516 } // namespace itk
517 
518 
519 #endif

Generated at Sat May 18 2013 23:37:43 for Orfeo Toolbox with doxygen 1.8.3.1