Orfeo Toolbox  3.16
itkBinaryMorphologyImageFilter.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkBinaryMorphologyImageFilter.txx,v $
5  Language: C++
6  Date: $Date: 2008-10-09 15:31:36 $
7  Version: $Revision: 1.13 $
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 __itkBinaryMorphologyImageFilter_txx
18 #define __itkBinaryMorphologyImageFilter_txx
19 
20 
21 // First make sure that the configuration is available.
22 // This line can be removed once the optimized versions
23 // gets integrated into the main directories.
24 #include "itkConfigure.h"
25 
26 #ifdef ITK_USE_CONSOLIDATED_MORPHOLOGY
28 #else
29 
34 #include "itkImageRegionIterator.h"
38 #include "itkOffset.h"
39 #include "itkProgressReporter.h"
41 
42 namespace itk
43 {
44 
45 template <class TInputImage, class TOutputImage, class TKernel>
48  : m_Kernel()
49 {
50  m_Radius.Fill(1);
51  m_ForegroundValue = NumericTraits<InputPixelType>::max();
53  //this->SetNumberOfThreads(1);
54 }
55 
56 template <class TInputImage, class TOutputImage, class TKernel>
57 void
60 {
61  // call the superclass' implementation of this method
62  Superclass::GenerateInputRequestedRegion();
63 
64  // get pointers to the input and output
65  typename Superclass::InputImagePointer inputPtr =
66  const_cast< TInputImage * >( this->GetInput() );
67 
68  if ( !inputPtr )
69  {
70  return;
71  }
72 
73  // get a copy of the input requested region (should equal the output
74  // requested region)
75  typename TInputImage::RegionType inputRequestedRegion;
76  inputRequestedRegion = inputPtr->GetRequestedRegion();
77 
78  // The input image needs to be large enough to support:
79  // 1. The size of the structuring element
80  // 2. The size of the connectivity element (typically one)
81  InputSizeType padBy = m_Radius;
82  for (unsigned int i=0; i < KernelDimension; ++i)
83  {
84  padBy[i] =
85  (padBy[i]>m_Kernel.GetRadius(i) ? padBy[i] : m_Kernel.GetRadius(i));
86  }
87  inputRequestedRegion.PadByRadius( padBy );
88 
89  // crop the input requested region at the input's largest possible region
90  if ( inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion()) )
91  {
92  inputPtr->SetRequestedRegion( inputRequestedRegion );
93  return;
94  }
95  else
96  {
97  // Couldn't crop the region (requested region is outside the largest
98  // possible region). Throw an exception.
99 
100  // store what we tried to request (prior to trying to crop)
101  inputPtr->SetRequestedRegion( inputRequestedRegion );
102 
103  // build an exception
104  InvalidRequestedRegionError e(__FILE__, __LINE__);
105  /*e.SetLocation(ITK_LOCATION);*/
106  e.SetDescription("Requested region is (at least partially) outside the largest possible region.");
107  e.SetDataObject(inputPtr);
108  throw e;
109  }
110 }
111 
112 
113 template< class TInputImage, class TOutputImage, class TKernel>
114 void
116 ::SetKernel( const KernelType& kernel )
117 {
118  // Set Kernel
119  m_Kernel = kernel;
120 
121  // Analyse it: the following process depends only on kernel
122  this->AnalyzeKernel();
123 }
124 
125 
126 template< class TInputImage, class TOutputImage, class TKernel>
127 void
130 {
131  // Sure clearing
132  m_KernelDifferenceSets.clear();
133  m_KernelCCVector.clear();
134 
135  std::vector<unsigned int> kernelOnElements;
136 
137  unsigned long i,k;
138 
139  // **************************
140  // Structuring element ( SE ) coding
141  // **************************
142 
143  // Get symmetrical structuring element in order to satisfy
144  // our definition of binary dilation
145  unsigned long kernelSize = m_Kernel.Size();
146  unsigned long kernelCenter = kernelSize / 2;
147 
148  for( i = kernelCenter + 1, k = kernelCenter - 1; i < kernelSize; ++i, --k )
149  {
150  typename TKernel::PixelType px = m_Kernel.GetBufferReference()[i];
151  m_Kernel.GetBufferReference()[i] = m_Kernel.GetBufferReference()[k];
152  m_Kernel.GetBufferReference()[k] = px;
153  }
154 
155  // Store index of SE of ON elements
156  // It allows us to have a fastest access to ON elements
157  // of SE Kernel
158  KernelIteratorType KernelBegin = m_Kernel.Begin();
159  KernelIteratorType KernelEnd = m_Kernel.End();
160  KernelIteratorType kernel_it;
161 
162  for ( i=0, kernel_it=KernelBegin; kernel_it != KernelEnd; ++kernel_it, ++i)
163  {
164  if (*kernel_it)
165  {
166  kernelOnElements.push_back(i);
167  }
168  }
169 
170  // Compute the Nd vector ( called index in case of images...do not
171  // mistake with index in case of neighbourhood which is only a
172  // position in a 1 dimensional buffer...! ) of the center element in
173  // the SE neighbourhood
174  IndexType centerElementPosition;
175  for( i = 0; i < TInputImage::ImageDimension; ++i )
176  {
177  // position of center in a given direction is the middle of the direction
178  centerElementPosition[i] = m_Kernel.GetSize(i) / 2;
179  }
180 
181  // We have to detect the connected component of the structuring
182  // element and compute the difference sets in each direction ( 26
183  // connectivity in 3D for instance )
184 
185  // Detect all the connected components of the SE.
186  // ----------------------------------------------
187  // To do this we convert the SE into a temp image
188  typedef Image< bool, TInputImage::ImageDimension > BoolImageType;
189  typename BoolImageType::Pointer tmpSEImage = BoolImageType::New();
190  tmpSEImage->SetRegions( m_Kernel.GetSize() );
191 
192  // allocation
193  tmpSEImage->Allocate();
194 
195  // copy
196  ImageRegionIterator<BoolImageType> kernelImageIt;// iterator on image
197  kernelImageIt = ImageRegionIterator<BoolImageType>(tmpSEImage,
198  tmpSEImage->GetRequestedRegion());
199 
200  kernelImageIt.GoToBegin();
201  kernel_it = KernelBegin;
202 
203  while( !kernelImageIt.IsAtEnd() )
204  {
205  kernelImageIt.Set( *kernel_it ? true : false);
206  ++kernelImageIt;
207  ++kernel_it;
208  }
209 
210 
211  // boundary conditions
212  // Out boundary pixels are set to false
214  cbc.SetConstant( false );
215 
216  // Now look for connected component and record one SE element
217  // position for each CC.
219  kernelImageItIndex(tmpSEImage, tmpSEImage->GetRequestedRegion());
220 
221  // Neighborhood iterator on SE element temp image
223  SEoNeighbIt( m_Radius, tmpSEImage, tmpSEImage->GetRequestedRegion());
224  SEoNeighbIt.OverrideBoundaryCondition(&cbc);
225  unsigned int neighborhoodSize = SEoNeighbIt.Size();
226 
227  // Use a FIFO queue in order to perform the burning process
228  // which allows to identify the connected components of SE
229  std::queue<IndexType> propagQueue;
230 
231  // Clear vector of recorded CCs
232  m_KernelCCVector.clear();
233 
234  // walk both the "image" of the kernel iterator and the kernel
235  // iterator. use the "image" iterator to keep track of
236  // components. use the kernel iterator for quick access of offsets
237  kernel_it = KernelBegin;
238  kernelImageItIndex.GoToBegin();
239  while( !kernelImageItIndex.IsAtEnd() )
240  {
241  // If a ON element is found track the CC
242  if( kernelImageItIndex.Get() )
243  {
244  // Mark current element
245  kernelImageItIndex.Set( false );
246 
247  // add it to queue
248  propagQueue.push( kernelImageItIndex.GetIndex() );
249 
250  // We know also that we start a new CC, so we store the position of this
251  // element relatively to center of kernel ( i.e a vector ).
252  OffsetType offset = m_Kernel.GetOffset(kernel_it - KernelBegin);
253  m_KernelCCVector.push_back( offset );
254 
255  // Process while FIFO queue is not empty
256  while ( !propagQueue.empty() )
257  {
258  // Extract pixel index from queue
259  IndexType currentIndex = propagQueue.front();
260  propagQueue.pop();
261 
262  // Now look for neighbours that are also ON pixels
263  SEoNeighbIt.GoToBegin();
264  SEoNeighbIt.SetLocation( currentIndex );
265 
266  for (i = 0; i < neighborhoodSize; ++i)
267  {
268  // If current neighb pixel is ON, mark it and push it into queue
269  if( SEoNeighbIt.GetPixel(i) )
270  {
271  // Mark it
272  bool bIsBounds;
273  SEoNeighbIt.SetPixel(i, false, bIsBounds);
274 
275  // Push
276  propagQueue.push( SEoNeighbIt.GetIndex(i) );
277  }
278  }
279  } // while ( !propagQueue.empty() )
280 
281  } // if( kernelImageItIndex.Get() )
282 
283  ++kernelImageItIndex;
284  ++kernel_it;
285  }
286 
287  // Free memory of tmp image
288  tmpSEImage->Initialize();
289 
290  // Now look for difference sets
291  // ----------------------------
292  // Create a neighbourhood of radius m_Radius This neighbourhood is
293  // called adj neighbourhood and is used in order to get the offset
294  // in each direction.
296  adjNeigh.SetRadius(m_Radius);
297 
298  // now we look for the difference sets in each directions: If you
299  // take a structuring element (SE) and you translate it in one of
300  // the direction of the adjacency ( (-1,0,0), (-1,1,0), etc. ) you
301  // get SE(dir). Now the difference set is SE(dir) - SE. So when you
302  // want to paint SE union SE(dir) you just need to paint SE and the
303  // difference set.
304 
305  // Allocate difference sets container
306  m_KernelDifferenceSets.resize( adjNeigh.Size() );
307 
308  // For each direction of the connectivity, look for difference set
309  // in this direction
310  for( i = 0; i < adjNeigh.Size(); ++i )
311  {
312  m_KernelDifferenceSets[i].clear();
313  // For each element of the kernel wich index is k, see if they
314  // belong to this difference set treat only "ON" elements of SE
315  std::vector<unsigned int>::const_iterator kernelOnElementsIt;
316  for( kernelOnElementsIt = kernelOnElements.begin();
317  kernelOnElementsIt != kernelOnElements.end(); ++kernelOnElementsIt )
318  {
319  // Get the index in the SE neighb
320  k = *kernelOnElementsIt;
321 
322  // Get the Nd position of current SE element. In order to do
323  // that, we have not a "GetIndex" function. So first we get the
324  // offset relatively to the center SE element and add it to the
325  // index of this center SE element:
326  OffsetType currentOffset = m_Kernel.GetOffset(k);
327  IndexType currentShiftedPosition = centerElementPosition + currentOffset;
328 
329  // Add to current element position the offset corresponding the
330  // current adj direction
331  currentShiftedPosition += adjNeigh.GetOffset(i);
332 
333  // now currentShiftedPosition is the position of the current
334  // "pixel" ( SE element ) shifted in the direction i. Check if it
335  // is outside the structuring element. If it is the case, we
336  // know that the current SE element is in the difference set of
337  // the current direction i (this works only for boundary pixels!).
338  bool bIsOutside = false;
339  for( unsigned int dimCount = 0;
340  dimCount < TInputImage::ImageDimension; ++dimCount )
341  {
342  if( currentShiftedPosition[dimCount] < 0
343  || currentShiftedPosition[dimCount] >=
344  (int)m_Kernel.GetSize(dimCount) )
345  {
346  bIsOutside = true;
347  break;
348  }
349  }
350 
351  if( bIsOutside )
352  {
353  // The current SE element, which index is hence k, belongs to
354  // the difference set in the direction i. Add it to
355  // difference set in dir i
356  m_KernelDifferenceSets[i].push_back(currentOffset);
357  }
358  else
359  {
360  // The current shifted SE element doesn't belong to SE
361  // boundaries. In order to see if it belongs to difference set
362  // in direction i, the value of kernel at the position of the
363  // current SE element SHIFTED in direction i must be OFF ( i.e
364  // = 0 ) In order to access to shifted value we must compute a
365  // neighbourhood index
366 
367  // retrieve the index offset relatively to the current NOT
368  // shifted SE element
369  unsigned int currentRelativeIndexOffset
370  = m_Kernel.GetNeighborhoodIndex( adjNeigh.GetOffset(i) )
371  - m_Kernel.GetCenterNeighborhoodIndex();
372 
373  // Now thanks to this relative offset, we can get the absolute
374  // neigh index of the current shifted SE element.
375  unsigned int currentShiftedIndex
376  = k /*NOT shifted position*/ + currentRelativeIndexOffset;
377 
378  // Test if shifted element is OFF: in fact diff(dir) = all the
379  // elements of SE + dir where elements of SE is ON and
380  // elements of SE + dir is OFF.
381  if( m_Kernel[currentShiftedIndex] <= 0 )
382  {
383  // Add it to difference set in dir i
384  m_KernelDifferenceSets[i].push_back(currentOffset);
385  }
386  }
387 
388  } // for( kernelOnElementsIt = kernelOnElements.begin(); ...
389  } // for( i = 0; i < adjNeigh.Size(); ++i )
390 
391  // For the particular case of the m_KernelDifferenceSets at the
392  // center of the kernel ( the difference set is theoretically empty
393  // in this case because there is no shift ) we put the kernel set
394  // itself, useful for the rest of the process.
395  unsigned int centerKernelIndex = adjNeigh.Size() / 2;
396  for ( k=0, kernel_it=KernelBegin; kernel_it != KernelEnd; ++kernel_it, ++k)
397  {
398  if (*kernel_it)
399  {
400  OffsetType currentOffset = m_Kernel.GetOffset(k);
401  m_KernelDifferenceSets[centerKernelIndex].push_back(currentOffset);
402  }
403  }
404 }
405 
406 
410 template <class TInputImage, class TOutput, class TKernel>
411 void
413 ::PrintSelf( std::ostream& os, Indent indent) const
414 {
415  Superclass::PrintSelf( os, indent );
416  os << indent << "Radius: " << m_Radius << std::endl;
417  os << indent << "Kernel: " << m_Kernel << std::endl;
418  os << indent << "Foreground Value: " << static_cast<typename NumericTraits<InputPixelType>::PrintType>(m_ForegroundValue) << std::endl;
419  os << indent << "Background Value: " << static_cast<typename NumericTraits<OutputPixelType>::PrintType>(m_BackgroundValue) << std::endl;
420  os << indent << "BoundaryToForeground: " << m_BoundaryToForeground << std::endl;
421 }
422 
423 } // end namespace itk
424 
425 #endif
426 
427 #endif

Generated at Sat Jun 15 2013 23:29:03 for Orfeo Toolbox with doxygen 1.8.3.1