1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkShapedFloodFilledFunctionConditionalConstIterator_hxx
19 #define itkShapedFloodFilledFunctionConditionalConstIterator_hxx
20 
21 #include "itkShapedFloodFilledFunctionConditionalConstIterator.h"
22 #include "itkImageRegionConstIterator.h"
23 
24 namespace itk
25 {
26 template< typename TImage, typename TFunction >
27 ShapedFloodFilledFunctionConditionalConstIterator< TImage, TFunction >
ShapedFloodFilledFunctionConditionalConstIterator(const ImageType * imagePtr,FunctionType * fnPtr,IndexType startIndex)28 ::ShapedFloodFilledFunctionConditionalConstIterator(const ImageType *imagePtr,
29                                                     FunctionType *fnPtr,
30                                                     IndexType startIndex):
31   m_FullyConnected(false)
32 {
33   this->m_Image = imagePtr;
34   m_Function = fnPtr;
35   m_Seeds.push_back (startIndex);
36 
37   // Set up the temporary image
38   this->InitializeIterator();
39 }
40 
41 template< typename TImage, typename TFunction >
42 ShapedFloodFilledFunctionConditionalConstIterator< TImage, TFunction >
ShapedFloodFilledFunctionConditionalConstIterator(const ImageType * imagePtr,FunctionType * fnPtr,std::vector<IndexType> & startIndex)43 ::ShapedFloodFilledFunctionConditionalConstIterator(const ImageType *imagePtr,
44                                                     FunctionType *fnPtr,
45                                                     std::vector< IndexType > & startIndex):
46   m_Function(fnPtr),
47   m_FullyConnected(false)
48 {
49   this->m_Image = imagePtr; // can not be done in the initialization list
50 
51   unsigned int i;
52   for ( i = 0; i < startIndex.size(); i++ )
53     {
54     m_Seeds.push_back (startIndex[i]);
55     }
56 
57   // Set up the temporary image
58   this->InitializeIterator();
59 }
60 
61 template< typename TImage, typename TFunction >
62 ShapedFloodFilledFunctionConditionalConstIterator< TImage, TFunction >
ShapedFloodFilledFunctionConditionalConstIterator(const ImageType * imagePtr,FunctionType * fnPtr)63 ::ShapedFloodFilledFunctionConditionalConstIterator(const ImageType *imagePtr,
64                                                     FunctionType *fnPtr):
65   m_FullyConnected(false)
66 {
67   this->m_Image = imagePtr;
68   m_Function = fnPtr;
69 
70   // Set up the temporary image
71   this->InitializeIterator();
72 }
73 
74 template< typename TImage, typename TFunction >
75 void
76 ShapedFloodFilledFunctionConditionalConstIterator< TImage, TFunction >
InitializeIterator()77 ::InitializeIterator()
78 {
79   // Get the origin and spacing from the image in simple arrays
80   m_ImageOrigin  = this->m_Image->GetOrigin();
81   m_ImageSpacing = this->m_Image->GetSpacing();
82   m_ImageRegion  = this->m_Image->GetBufferedRegion();
83 
84   // Build and setup the neighborhood iterator
85   typename NeighborhoodIteratorType::RadiusType radius; radius.Fill(1);
86 
87   NeighborhoodIteratorType tmp_iter(radius, this->m_Image, m_ImageRegion);
88   m_NeighborhoodIterator = tmp_iter;
89 
90   setConnectivity(&m_NeighborhoodIterator, m_FullyConnected);
91 
92   // Build a temporary image of chars for use in the flood algorithm
93   m_TempPtr = TTempImage::New();
94   typename TTempImage::RegionType tempRegion = this->m_Image->GetBufferedRegion();
95 
96   m_TempPtr->SetLargestPossibleRegion(tempRegion);
97   m_TempPtr->SetBufferedRegion(tempRegion);
98   m_TempPtr->SetRequestedRegion(tempRegion);
99   m_TempPtr->Allocate(true); // initialize buffer to zero
100 
101   // Initialize the queue by adding the start index assuming one of
102   // the m_Seeds is "inside" This might not be true, in which
103   // case it's up to the programmer to specify a correct starting
104   // position later (using FindSeedPixel).  Must make sure that the
105   // seed is inside the buffer before touching pixels.
106   this->m_IsAtEnd = true;
107   for ( unsigned int i = 0; i < m_Seeds.size(); i++ )
108     {
109     if ( m_ImageRegion.IsInside (m_Seeds[i]) )
110       {
111       m_IndexStack.push(m_Seeds[i]);
112       this->m_IsAtEnd = false;
113       }
114     }
115 }
116 
117 template< typename TImage, typename TFunction >
118 void
119 ShapedFloodFilledFunctionConditionalConstIterator< TImage, TFunction >
FindSeedPixel()120 ::FindSeedPixel()
121 {
122   // Create an iterator that will walk the input image
123   using IRIType = typename itk::ImageRegionConstIterator< TImage >;
124   IRIType it = IRIType( this->m_Image, this->m_Image->GetBufferedRegion() );
125 
126   // Now we search the input image for the first pixel which is inside
127   // the function of interest
128   m_Seeds.clear();
129   for ( it.GoToBegin(); !it.IsAtEnd(); ++it )
130     {
131     if ( this->IsPixelIncluded( it.GetIndex() ) )
132       {
133       m_Seeds.push_back ( it.GetIndex() );
134 
135       // We need to reset the "beginning" now that we have a real seed
136       this->GoToBegin();
137 
138       return;
139       }
140     }
141 }
142 
143 template< typename TImage, typename TFunction >
144 void
145 ShapedFloodFilledFunctionConditionalConstIterator< TImage, TFunction >
FindSeedPixels()146 ::FindSeedPixels()
147 {
148   // Create an iterator that will walk the input image
149   using IRIType = typename itk::ImageRegionConstIterator< TImage >;
150   IRIType it = IRIType( this->m_Image, this->m_Image->GetBufferedRegion() );
151 
152   // Now we search the input image for the first pixel which is inside
153   // the function of interest
154   m_Seeds.clear();
155   bool found = false;
156   for ( it.GoToBegin(); !it.IsAtEnd(); ++it )
157     {
158     if ( this->IsPixelIncluded( it.GetIndex() ) )
159       {
160       m_Seeds.push_back ( it.GetIndex() );
161       found = true;
162       }
163     }
164   if ( found )
165     {
166     // We need to reset the "beginning" now that we have a real seed
167     this->GoToBegin();
168     }
169 }
170 
171 template< typename TImage, typename TFunction >
172 void
173 ShapedFloodFilledFunctionConditionalConstIterator< TImage, TFunction >
DoFloodStep()174 ::DoFloodStep()
175 {
176   // The index in the front of the queue should always be
177   // valid and be inside since this is what the iterator
178   // uses in the Set/Get methods. This is ensured by the
179   // GoToBegin() method.
180 
181   // Take the index in the front of the queue
182   const IndexType & topIndex = m_IndexStack.front();
183 
184   // We are explicitly not calling set location since only offsets of
185   // the neighborhood iterator are accessed.
186   typename NeighborhoodIteratorType::ConstIterator neighborIt =
187     m_NeighborhoodIterator.Begin();
188   const typename NeighborhoodIteratorType::ConstIterator neighborEnd =
189     m_NeighborhoodIterator.End();
190 
191   for (; neighborIt != neighborEnd; ++neighborIt )
192     {
193     const OffsetType & offset = neighborIt.GetNeighborhoodOffset();
194     const IndexType    tempIndex = topIndex + offset;
195 
196     // If this is a valid index and have not been tested,
197     // then test it.
198     if ( m_ImageRegion.IsInside(tempIndex) )
199       {
200       if ( m_TempPtr->GetPixel(tempIndex) == 0 )
201         {
202         // if it is inside, push it into the queue
203         if ( this->IsPixelIncluded(tempIndex) )
204           {
205           m_IndexStack.push(tempIndex);
206           m_TempPtr->SetPixel(tempIndex, 2);
207           }
208         else  // If the pixel is outside
209           {
210           // Mark the pixel as outside and remove it from the queue.
211           m_TempPtr->SetPixel(tempIndex, 1);
212           }
213         }
214       }
215     } // Finished traversing neighbors
216 
217   // Now that all the potential neighbors have been
218   // inserted we can get rid of the pixel in the front
219   m_IndexStack.pop();
220 
221   if ( m_IndexStack.empty() )
222     {
223     this->m_IsAtEnd = true;
224     }
225 }
226 
227 template< typename TImage, typename TFunction >
228 void
229 ShapedFloodFilledFunctionConditionalConstIterator< TImage, TFunction >
SetFullyConnected(const bool _arg)230 ::SetFullyConnected(const bool _arg)
231 {
232   if ( this->m_FullyConnected != _arg )
233     {
234     this->m_FullyConnected = _arg;
235     setConnectivity(&m_NeighborhoodIterator, m_FullyConnected);
236     }
237 }
238 
239 template< typename TImage, typename TFunction >
240 bool
241 ShapedFloodFilledFunctionConditionalConstIterator< TImage, TFunction >
GetFullyConnected() const242 ::GetFullyConnected() const
243 {
244   return this->m_FullyConnected;
245 }
246 } // end namespace itk
247 
248 #endif
249