Orfeo Toolbox  3.16
itkBinaryThinningImageFilter.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkBinaryThinningImageFilter.txx,v $
5  Language: C++
6  Date: $Date: 2008-10-20 21:28:20 $
7  Version: $Revision: 1.8 $
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 __itkBinaryThinningImageFilter_txx
18 #define __itkBinaryThinningImageFilter_txx
19 
20 #include <iostream>
21 
24 #include "itkImageRegionIterator.h"
26 #include <vector>
27 
28 namespace itk
29 {
30 
34 template <class TInputImage,class TOutputImage>
37 {
38 
39  this->SetNumberOfRequiredOutputs( 1 );
40 
41  OutputImagePointer thinImage = OutputImageType::New();
42  this->SetNthOutput( 0, thinImage.GetPointer() );
43 
44 }
45 
49 template <class TInputImage,class TOutputImage>
51  TInputImage,TOutputImage>::OutputImageType *
54 {
55  return dynamic_cast< OutputImageType * >(
56  this->ProcessObject::GetOutput(0) );
57 }
58 
59 
65 template <class TInputImage,class TOutputImage>
66 void
69 {
70 
71  itkDebugMacro(<< "PrepareData Start");
72  OutputImagePointer thinImage = GetThinning();
73 
74  InputImagePointer inputImage =
75  dynamic_cast<const TInputImage *>( ProcessObject::GetInput(0) );
76 
77  thinImage->SetBufferedRegion( thinImage->GetRequestedRegion() );
78  thinImage->Allocate();
79 
80  typename OutputImageType::RegionType region = thinImage->GetRequestedRegion();
81 
82 
83  ImageRegionConstIterator< TInputImage > it( inputImage, region );
84  ImageRegionIterator< TOutputImage > ot( thinImage, region );
85 
86  it.GoToBegin();
87  ot.GoToBegin();
88 
89  itkDebugMacro(<< "PrepareData: Copy input to output");
90 
91  // Copy the input to the output, changing all foreground pixels to
92  // have value 1 in the process.
93  while( !ot.IsAtEnd() )
94  {
95  if ( it.Get() )
96  {
98  }
99  else
100  {
102  }
103  ++it;
104  ++ot;
105  }
106  itkDebugMacro(<< "PrepareData End");
107 }
108 
112 template <class TInputImage,class TOutputImage>
113 void
116 {
117  itkDebugMacro( << "ComputeThinImage Start");
118  OutputImagePointer thinImage = GetThinning();
119 
120  typename OutputImageType::RegionType region = thinImage->GetRequestedRegion();
121 
122  typename NeighborhoodIteratorType::RadiusType radius;
123  radius.Fill(1);
124  NeighborhoodIteratorType ot( radius, thinImage, region );
125 
126  // Create a set of offsets from the center.
127  // This numbering follows that of Gonzalez and Woods.
128  typedef typename NeighborhoodIteratorType::OffsetType OffsetType;
129  OffsetType o2 = {{0,-1}};
130  OffsetType o3 = {{1,-1}};
131  OffsetType o4 = {{1,0}};
132  OffsetType o5 = {{1,1}};
133  OffsetType o6 = {{0,1}};
134  OffsetType o7 = {{-1,1 }};
135  OffsetType o8 = {{-1,0}};
136  OffsetType o9 = {{-1,-1}};
137 
138  PixelType p2;
139  PixelType p3;
140  PixelType p4;
141  PixelType p5;
142  PixelType p6;
143  PixelType p7;
144  PixelType p8;
145  PixelType p9;
146 
147  // These tests correspond to the conditions listed in Gonzalez and Woods
148  bool testA;
149  bool testB;
150  bool testC;
151  bool testD;
152 
153  std::vector < IndexType > pixelsToDelete;
154  typename std::vector < IndexType >::iterator pixelsToDeleteIt;
155 
156  // Loop through the image several times until there is no change.
157  bool noChange = false;
158  while(!noChange)
159  {
160  noChange = true;
161  // Loop through the thinning steps.
162  for (int step = 1; step <= 4; step++)
163  {
164  pixelsToDelete.clear();
165  // Loop through the image.
166  for ( ot.GoToBegin(); !ot.IsAtEnd(); ++ot )
167  {
168  // Each iteration over the image, set all tests to false.
169  testA = false;
170  testB = false;
171  testC = false;
172  testD = false;
173 
174  p2 = ot.GetPixel(o2);
175  p3 = ot.GetPixel(o3);
176  p4 = ot.GetPixel(o4);
177  p5 = ot.GetPixel(o5);
178  p6 = ot.GetPixel(o6);
179  p7 = ot.GetPixel(o7);
180  p8 = ot.GetPixel(o8);
181  p9 = ot.GetPixel(o9);
182 
183  // Determine whether the pixel should be deleted in the
184  // following if statements.
185  if ( ot.GetCenterPixel() )
186  {
187 
188  // TestA
189  // Count the number of neighbors that are on.
190  // TestA is violated when contour point p1 has only one or
191  // seven 8-neighbors valued 1. Having only one such
192  // neighbor implies that p1 is the end point of a skeleton
193  // stroke and obviously should not be deleted. Deleting p1
194  // if it has seven such neighbos would cause erosion into a region.
195  PixelType numberOfOnNeighbors = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
196 
197  if ( numberOfOnNeighbors > 1 && numberOfOnNeighbors < 7)
198  {
199  testA = true;
200  }
201 
202  // TestB
203  // Count the number of 0-1 transitions in the ordered
204  // sequence.
205  // TestB is violated when it is applied to points on a
206  // stroke 1 pixel thick. Hence this test prevents
207  // disconnetion of segments of a skeleton during the
208  // thinning operation.
209  // First find the total number of transitions, and then
210  // divide by 2.
211  const PixelType transitions = (
212  vcl_abs(static_cast<int>(p3 - p2)) + vcl_abs(static_cast<int>(p4 - p3)) + vcl_abs(static_cast<int>(p5 - p4)) + vcl_abs(static_cast<int>(p6 - p5)) +
213  vcl_abs(static_cast<int>(p7 - p6)) + vcl_abs(static_cast<int>(p8 - p7)) + vcl_abs(static_cast<int>(p9 - p8)) + vcl_abs(static_cast<int>(p2 - p9))
214  ) /2;
215 
216  if (transitions == 1)
217  {
218  testB = true;
219  }
220 
221  // TestC and TestD
222  // Step 1 in Gonzalez and Woods is broken up here into two
223  // steps; step 1 and step 2.
224  // Steps 1 and 2 are the first two passes over the image for each
225  // iteration of the algorithm.
226  // A point that satisfies these tests as well as TestA
227  // and TestB is an east or south boundary point or a
228  // northwest corner point in the boundary.
229  // Note that northeast and southwest corner points are
230  // satisfied in both the combination of steps 1 and 2 and
231  // the combination of steps 3 and 4.
232  if (step == 1)
233  {
234  if (p4 == 0 || p6 == 0)
235  {
236  testC = true;
237  testD = true;
238  }
239  }
240 
241 
242  else if (step == 2)
243  {
244  if (p2 == 0 && p8 == 0)
245  {
246  testC = true;
247  testD = true;
248  }
249  }
250 
251  // Step 2 in Gonzalez and Woods is broken up here into two
252  // steps; step 3 and step 4.
253  // Steps 3 and 4 are the second passes over the image for each
254  // iteration of the algorithm.
255  // A point that satisfies these tests as well as TestA
256  // and TestB is a west or north boundary point or a
257  // southeast corner point in the boundary.
258  // Note that northeast and southwest corner points are
259  // satisfied in both the combination of steps 1 and 2 and
260  // the combination of steps 3 and 4.
261  else if (step == 3)
262  {
263  if (p2 == 0 || p8 == 0)
264  {
265  testC = true;
266  testD = true;
267  }
268  }
269  else if (step == 4)
270  {
271  if (p4 == 0 && p6 == 0)
272  {
273  testC = true;
274  testD = true;
275  }
276  }
277 
278  // If all tests pass, mark the pixel for removal
279  if (testA && testB && testC && testD)
280  {
281  pixelsToDelete.push_back( ot.GetIndex() );
282  noChange = false;
283  }
284  }
285  } // end image iteration loop
286 
287  //Loop through the vector of pixels to delete and set these pixels to 0 in the image.
288  for (pixelsToDeleteIt=pixelsToDelete.begin();
289  pixelsToDeleteIt != pixelsToDelete.end();
290  pixelsToDeleteIt++)
291  {
292  thinImage->SetPixel(*pixelsToDeleteIt,0);
293  }
294 
295  } // end step loop
296 
297  } // end noChange while loop
298 
299 
300  itkDebugMacro( << "ComputeThinImage End");
301 }
302 
306 template <class TInputImage,class TOutputImage>
307 void
310 {
311 
312  this->PrepareData();
313 
314  itkDebugMacro(<< "GenerateData: Computing Thinning Image");
315  this->ComputeThinImage();
316 
317 
318 
319 } // end GenerateData()
320 } // end namespace itk
321 
322 #endif

Generated at Sat May 18 2013 23:30:34 for Orfeo Toolbox with doxygen 1.8.3.1