Orfeo Toolbox  3.16
itkGrayscaleGeodesicErodeImageFilter.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkGrayscaleGeodesicErodeImageFilter.txx,v $
5  Language: C++
6  Date: $Date: 2008-10-16 16:45:09 $
7  Version: $Revision: 1.16 $
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 __itkGrayscaleGeodesicErodeImageFilter_txx
18 #define __itkGrayscaleGeodesicErodeImageFilter_txx
19 
20 #include <limits.h>
21 
23 #include "itkNumericTraits.h"
26 #include "itkProgressReporter.h"
27 #include "itkProgressAccumulator.h"
28 #include "itkIterationReporter.h"
29 #include "itkImageRegionIterator.h"
32 
33 
34 namespace itk {
35 
36 template <class TInputImage, class TOutputImage>
39 {
40  m_RunOneIteration = false;
41  m_NumberOfIterationsUsed = 0; // run to convergence
42  this->SetNumberOfRequiredInputs(2);
43  m_FullyConnected = false;
44 }
45 
46 
47 template <class TInputImage, class TOutputImage>
48 void
50 ::SetMarkerImage(const MarkerImageType* markerImage)
51 {
52  // Process object is not const-correct so the const casting is required.
53  this->SetNthInput(0, const_cast<MarkerImageType *>( markerImage ));
54 }
55 
56 
57 template <class TInputImage, class TOutputImage>
61 {
62  return this->GetInput(0);
63 }
64 
65 
66 template <class TInputImage, class TOutputImage>
67 void
69 ::SetMaskImage(const MaskImageType* maskImage)
70 {
71  // Process object is not const-correct so the const casting is required.
72  this->SetNthInput(1, const_cast<MaskImageType *>( maskImage ));
73 }
74 
75 
76 template <class TInputImage, class TOutputImage>
80 {
81  return this->GetInput(1);
82 }
83 
84 
85 template <class TInputImage, class TOutputImage>
86 void
89 {
90  // call the superclass' implementation of this method
91  Superclass::GenerateInputRequestedRegion();
92 
93  // get pointers to the inputs
94  MarkerImagePointer markerPtr =
95  const_cast< MarkerImageType * >( this->GetInput(0) );
96 
97  MaskImagePointer maskPtr =
98  const_cast< MaskImageType * >( this->GetInput(1) );
99 
100  if ( !markerPtr || !maskPtr )
101  {
102  return;
103  }
104 
105  // If configured to run one iteration, the marker image must be
106  // padded by one pixel while the mask image can match the size of
107  // the output. If configured to run until convergence, the entire
108  // marker and mask image will be required.
109  //
110  if (m_RunOneIteration)
111  {
112  // by calling the superclass' implementation above, the mask image
113  // is already configured to have its requested input match the
114  // output requested region. so nothing needs to be done for the
115  // mask image.
116 
117  // the marker image needs to be padded by one pixel and cropped to
118  // the LargestPossibleRegion.
119  //
120 
121  // get a copy of the marker image requested region (should equal
122  // the output requested region)
123  MarkerImageRegionType markerRequestedRegion;
124  markerRequestedRegion = markerPtr->GetRequestedRegion();
125 
126  // pad the marker requested region by the elementary operator radius
127  markerRequestedRegion.PadByRadius( 1 );
128 
129  // crop the marker requested region at the marker's largest possible region
130  if ( markerRequestedRegion.Crop(markerPtr->GetLargestPossibleRegion()) )
131  {
132  markerPtr->SetRequestedRegion( markerRequestedRegion );
133  return;
134  }
135  else
136  {
137  // Couldn't crop the region (requested region is outside the largest
138  // possible region). Throw an exception.
139 
140  // store what we tried to request (prior to trying to crop)
141  markerPtr->SetRequestedRegion( markerRequestedRegion );
142 
143  // build an exception
144  InvalidRequestedRegionError e(__FILE__, __LINE__);
145  e.SetLocation(ITK_LOCATION);
146  e.SetDescription("Requested region for the marker image is (at least partially) outside the largest possible region.");
147  e.SetDataObject(markerPtr);
148  throw e;
149  }
150  }
151  else
152  {
153  // The filter was configured to run to convergence. We need to
154  // configure the inputs such that all the data is available.
155  //
156  markerPtr->SetRequestedRegion(markerPtr->GetLargestPossibleRegion());
157  maskPtr->SetRequestedRegion(maskPtr->GetLargestPossibleRegion());
158  }
159 }
160 
161 
162 template <class TInputImage, class TOutputImage>
163 void
166 {
167  // if running to convergence, then all the output will be produced
168  if ( !m_RunOneIteration)
169  {
170  this->GetOutput()
171  ->SetRequestedRegion( this->GetOutput()->GetLargestPossibleRegion() );
172  }
173 }
174 
175 
176 template<class TInputImage, class TOutputImage>
177 void
180 {
181  IterationReporter iterate(this, 0, 1);
182 
183  // If the filter is configured to run a single iteration, then
184  // delegate to the superclass' version of GenerateData. This will
185  // engage the multithreaded version of the GenerateData.
186  //
187  if (m_RunOneIteration)
188  {
189  Superclass::GenerateData();
190  m_NumberOfIterationsUsed = 1;
191  iterate.CompletedStep();
192  return;
193  }
194 
195 
196  // Filter was configured to run until convergence. We need to
197  // delegate to an instance of the filter to run each iteration
198  // separately. For efficiency, we will delegate to an instance that
199  // is templated over <TInputImage, TInputImage> to avoid any
200  // pixelwise casting until the final output image is configured.
202  singleIteration
204  bool done = false;
205 
206  // set up the singleIteration filter. we are not using the grafting
207  // mechanism because we only need the requested regioN to be set up
208  singleIteration->RunOneIterationOn();
209  singleIteration->SetMarkerImage( this->GetMarkerImage() );
210  singleIteration->SetMaskImage( this->GetMaskImage() );
211  singleIteration->GetOutput()
212  ->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() );
213 
214  // Create a process accumulator for tracking the progress of this minipipeline
216  progress->SetMiniPipelineFilter(this);
217  progress->RegisterInternalFilter(singleIteration,1.0f);
218 
219  // run until convergence
220  while (!done)
221  {
222  // run one iteration
223  singleIteration->Update();
224  iterate.CompletedStep();
225 
226  // Check for convergence. Compare the output of the single
227  // iteration of the algorithm with the current marker image.
229  singleIteration->GetMarkerImage(),
230  singleIteration->GetOutput()->GetRequestedRegion() );
232  singleIteration->GetOutput(),
233  singleIteration->GetOutput()->GetRequestedRegion() );
234 
235  done = true;
236  while ( !singleOutIt.IsAtEnd() )
237  {
238  // exit early from check on first pixel that is different
239  if (singleInIt.Get() != singleOutIt.Get())
240  {
241  done = false;
242  break; // exit early from check
243  }
244  ++singleInIt;
245  ++singleOutIt;
246  }
247 
248  // If we have not converged, then setup the singleIteration filter
249  // for the next iteration.
250  //
251  if (!done)
252  {
253  // disconnect the current output from the singleIteration object
254  MarkerImagePointer marker = singleIteration->GetOutput();
255  marker->DisconnectPipeline();
256  // assign the old output as the input
257  singleIteration->SetMarkerImage( marker );
258  // since DisconnectPipeline() creates a new output object, we need
259  // to regraft the information onto the output
260  singleIteration->GetOutput()
261  ->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() );
262 
263  // Keep track of how many iterations have be done
264  m_NumberOfIterationsUsed++;
265  }
266  }
267 
268  // Convert the output of singleIteration to an TOutputImage type
269  // (could use a CastImageFilter here to thread the copy)
270  typename OutputImageType::Pointer outputPtr = this->GetOutput();
271  outputPtr->SetBufferedRegion( outputPtr->GetRequestedRegion() );
272  outputPtr->Allocate();
273 
274  // walk the output of the singleIteration
275  ImageRegionIterator<TInputImage> singleIt(singleIteration->GetOutput(),
276  outputPtr->GetRequestedRegion() );
277  // walk the real output of the filter
278  ImageRegionIterator<TOutputImage> outIt(outputPtr,
279  outputPtr->GetRequestedRegion());
280 
281  // cast and copy
282  while( !outIt.IsAtEnd() )
283  {
284  outIt.Set( static_cast<OutputImagePixelType>( singleIt.Get() ) );
285  ++outIt;
286  ++singleIt;
287  }
288 }
289 
290 template<class TInputImage, class TOutputImage>
291 void
293 ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread,
294  int threadId)
295 {
296 
297  // Set up the progress reporter
298  ProgressReporter progress(this, threadId,
299  outputRegionForThread.GetNumberOfPixels(),
300  10);
301 
302  // Set up the boundary condition to have no upwind derivatives
304 
305  // Neighborhood iterator. Let's use a shaped neighborhood so we can
306  // restrict the access to face connected neighbors. This iterator
307  // will be applied to the marker image.
308  typedef ConstShapedNeighborhoodIterator<TInputImage> NeighborhoodIteratorType;
309 
310  // iterator for the marker image
311  // NeighborhoodIteratorType markerIt;
312 
313  // Find the boundary "faces". Structuring element is elementary
314  // (face connected neighbors within a radius of 1).
318  kernelRadius.Fill(1);
319  faceList = fC(this->GetMarkerImage(), outputRegionForThread, kernelRadius);
320 
322 
323  unsigned int d;
324  typename NeighborhoodIteratorType::OffsetValueType i;
325  typename NeighborhoodIteratorType::OffsetType offset;
326 
327  MarkerImagePixelType value, erodeValue, maskValue;
328 
329  // Iterate over the faces
330  //
331  for (fit = faceList.begin(); fit != faceList.end(); ++fit)
332  {
333  NeighborhoodIteratorType markerIt(kernelRadius, this->GetMarkerImage(), *fit);
334  ImageRegionConstIterator<TInputImage> maskIt(this->GetMaskImage(), *fit);
335  ImageRegionIterator<TOutputImage> oIt(this->GetOutput(), *fit);
336 
337  markerIt.OverrideBoundaryCondition(&BC);
338  markerIt.GoToBegin();
339 
340  if ( !m_FullyConnected )
341  {
342  // setup the marker iterator to only visit face connected
343  // neighbors and the center pixel
344  offset.Fill(0);
345  markerIt.ActivateOffset(offset); // center pixel
346  for (d=0; d < TInputImage::ImageDimension; ++d)
347  {
348  for (i=-1; i<=1; i+=2)
349  {
350  offset[d] = i;
351  markerIt.ActivateOffset(offset); // a neighbor pixel in dimension d
352  }
353  offset[d] = 0;
354  }
355  }
356  else
357  {
358  // activate all pixels excepted center pixel
359  for (d=0; d < markerIt.GetCenterNeighborhoodIndex()*2+1; ++d)
360  {
361  markerIt.ActivateOffset(markerIt.GetOffset(d));
362  }
363  offset.Fill(0);
364  markerIt.DeactivateOffset(offset);
365  }
366 
367  // iterate over image region
368  while ( ! oIt.IsAtEnd() )
369  {
371 
372  // Erode by checking the face connected neighbors (and center pixel)
373  typename NeighborhoodIteratorType::ConstIterator sIt;
374  for (sIt = markerIt.Begin(); !sIt.IsAtEnd(); sIt++)
375  {
376  // a pixel in the neighborhood
377  value = sIt.Get();
378 
379  // erosion is a min operation
380  if (value < erodeValue)
381  {
382  erodeValue = value;
383  }
384  }
385 
386  // Mask operation. For geodesic erosion, the mask operation is
387  // a pixelwise max operator with the elementary eroded image and
388  // the mask image
389  maskValue = maskIt.Get();
390 
391  if (maskValue > erodeValue)
392  {
393  erodeValue = maskValue;
394  }
395 
396  // set the output pixel value
397  oIt.Set( static_cast<OutputImagePixelType>( erodeValue ) );
398 
399  // move to next pixel
400  ++oIt;
401  ++markerIt;
402  ++maskIt;
403 
404  progress.CompletedPixel();
405  }
406  }
407 }
408 
409 template<class TInputImage, class TOutputImage>
410 void
412 ::PrintSelf(std::ostream &os, Indent indent) const
413 {
414  Superclass::PrintSelf(os, indent);
415 
416  os << indent << "Run one iteration: " << (m_RunOneIteration ? "on" : "off")
417  << std::endl;
418  os << indent << "Number of iterations used to produce current output: "
419  << m_NumberOfIterationsUsed << std::endl;
420  os << indent << "FullyConnected: " << m_FullyConnected << std::endl;
421 }
422 
423 }// end namespace itk
424 #endif

Generated at Sat May 18 2013 23:41:22 for Orfeo Toolbox with doxygen 1.8.3.1