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 itkFloodFilledFunctionConditionalConstIterator_hxx
19 #define itkFloodFilledFunctionConditionalConstIterator_hxx
20 
21 #include "itkFloodFilledFunctionConditionalConstIterator.h"
22 #include "itkImageRegionConstIterator.h"
23 
24 namespace itk
25 {
26 template< typename TImage, typename TFunction >
27 FloodFilledFunctionConditionalConstIterator< TImage, TFunction >
FloodFilledFunctionConditionalConstIterator(const ImageType * imagePtr,FunctionType * fnPtr,IndexType startIndex)28 ::FloodFilledFunctionConditionalConstIterator(const ImageType *imagePtr,
29                                               FunctionType *fnPtr,
30                                               IndexType startIndex)
31 {
32   this->m_Image = imagePtr;
33   m_Function = fnPtr;
34   m_Seeds.push_back (startIndex);
35 
36   // Set up the temporary image
37   this->InitializeIterator();
38 }
39 
40 template< typename TImage, typename TFunction >
41 FloodFilledFunctionConditionalConstIterator< TImage, TFunction >
FloodFilledFunctionConditionalConstIterator(const ImageType * imagePtr,FunctionType * fnPtr,std::vector<IndexType> & startIndex)42 ::FloodFilledFunctionConditionalConstIterator(const ImageType *imagePtr,
43                                               FunctionType *fnPtr,
44                                               std::vector< IndexType > & startIndex)
45 {
46   this->m_Image = imagePtr;
47   m_Function = fnPtr;
48   unsigned int i;
49   for ( i = 0; i < startIndex.size(); i++ )
50     {
51     m_Seeds.push_back (startIndex[i]);
52     }
53 
54   // Set up the temporary image
55   this->InitializeIterator();
56 }
57 
58 template< typename TImage, typename TFunction >
59 FloodFilledFunctionConditionalConstIterator< TImage, TFunction >
FloodFilledFunctionConditionalConstIterator(const ImageType * imagePtr,FunctionType * fnPtr)60 ::FloodFilledFunctionConditionalConstIterator(const ImageType *imagePtr,
61                                               FunctionType *fnPtr)
62 {
63   this->m_Image = imagePtr;
64   m_Function = fnPtr;
65 
66   // Set up the temporary image
67   this->InitializeIterator();
68 
69 }
70 
71 template< typename TImage, typename TFunction >
72 void
73 FloodFilledFunctionConditionalConstIterator< TImage, TFunction >
InitializeIterator()74 ::InitializeIterator()
75 {
76   m_FoundUncheckedNeighbor = false;
77   m_IsValidIndex = false;
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 a temporary image of chars for use in the flood algorithm
85   m_TemporaryPointer = TTempImage::New();
86   typename TTempImage::RegionType tempRegion = this->m_Image->GetBufferedRegion();
87 
88   m_TemporaryPointer->SetLargestPossibleRegion(tempRegion);
89   m_TemporaryPointer->SetBufferedRegion(tempRegion);
90   m_TemporaryPointer->SetRequestedRegion(tempRegion);
91   m_TemporaryPointer->Allocate(true); // initialize buffer to zero
92 
93   // Initialize the queue by adding the start index assuming one of
94   // the m_Seeds is "inside" This might not be true, in which
95   // case it's up to the programmer to specify a correct starting
96   // position later (using FindSeedPixel).  Must make sure that the
97   // seed is inside the buffer before touching pixels.
98   this->m_IsAtEnd = true;
99   for ( unsigned int i = 0; i < m_Seeds.size(); i++ )
100     {
101     if ( m_ImageRegion.IsInside (m_Seeds[i]) )
102       {
103       m_IndexStack.push(m_Seeds[i]);
104       this->m_IsAtEnd = false;
105       }
106     }
107 }
108 
109 template< typename TImage, typename TFunction >
110 void
111 FloodFilledFunctionConditionalConstIterator< TImage, TFunction >
FindSeedPixel()112 ::FindSeedPixel()
113 {
114   // Create an iterator that will walk the input image
115   using IRIType = typename itk::ImageRegionConstIterator< TImage >;
116   IRIType it = IRIType( this->m_Image, this->m_Image->GetBufferedRegion() );
117 
118   // Now we search the input image for the first pixel which is inside
119   // the function of interest
120   m_Seeds.clear();
121   for ( it.GoToBegin(); !it.IsAtEnd(); ++it )
122     {
123     if ( this->IsPixelIncluded( it.GetIndex() ) )
124       {
125       m_Seeds.push_back ( it.GetIndex() );
126 
127       // We need to reset the "beginning" now that we have a real seed
128       this->GoToBegin();
129 
130       return;
131       }
132     }
133 }
134 
135 template< typename TImage, typename TFunction >
136 void
137 FloodFilledFunctionConditionalConstIterator< TImage, TFunction >
FindSeedPixels()138 ::FindSeedPixels()
139 {
140   // Create an iterator that will walk the input image
141   using IRIType = typename itk::ImageRegionConstIterator< TImage >;
142   IRIType it = IRIType( this->m_Image, this->m_Image->GetBufferedRegion() );
143 
144   // Now we search the input image for the first pixel which is inside
145   // the function of interest
146   m_Seeds.clear();
147   bool found = false;
148   for ( it.GoToBegin(); !it.IsAtEnd(); ++it )
149     {
150     if ( this->IsPixelIncluded( it.GetIndex() ) )
151       {
152       m_Seeds.push_back ( it.GetIndex() );
153       found = true;
154       }
155     }
156   if ( found )
157     {
158     // We need to reset the "beginning" now that we have a real seed
159     this->GoToBegin();
160     }
161 }
162 
163 template< typename TImage, typename TFunction >
164 void
165 FloodFilledFunctionConditionalConstIterator< TImage, TFunction >
DoFloodStep()166 ::DoFloodStep()
167 {
168   // The index in the front of the queue should always be
169   // valid and be inside since this is what the iterator
170   // uses in the Set/Get methods. This is ensured by the
171   // GoToBegin() method.
172 
173   // Take the index in the front of the queue
174   const IndexType & topIndex = m_IndexStack.front();
175 
176   // Iterate through all possible dimensions
177   // NOTE: Replace this with a ShapeNeighborhoodIterator
178   for ( unsigned int i = 0; i < NDimensions; i++ )
179     {
180     // The j loop establishes either left or right neighbor (+-1)
181     for ( int j = -1; j <= 1; j += 2 )
182       {
183       IndexType tempIndex;
184 
185       // build the index of a neighbor
186       for ( unsigned int k = 0; k < NDimensions; k++ )
187         {
188         if ( i != k )
189           {
190           tempIndex.m_InternalArray[k] = topIndex[k];
191           }
192         else
193           {
194           tempIndex.m_InternalArray[k] = topIndex[k] + j;
195           }
196         } // end build the index of a neighbor
197 
198       // If this is a valid index and have not been tested,
199       // then test it.
200       if ( m_ImageRegion.IsInside(tempIndex) )
201         {
202         if ( m_TemporaryPointer->GetPixel(tempIndex) == 0 )
203           {
204           // if it is inside, push it into the queue
205           if ( this->IsPixelIncluded(tempIndex) )
206             {
207             m_IndexStack.push(tempIndex);
208             m_TemporaryPointer->SetPixel(tempIndex, 2);
209             }
210           else  // If the pixel is outside
211             {
212             // Mark the pixel as outside and remove it from the queue.
213             m_TemporaryPointer->SetPixel(tempIndex, 1);
214             }
215           }
216         }
217       } // end left/right neighbor loop
218     }   // end check all neighbors
219 
220   // Now that all the potential neighbors have been
221   // inserted we can get rid of the pixel in the front
222   m_IndexStack.pop();
223 
224   if ( m_IndexStack.empty() )
225     {
226     this->m_IsAtEnd = true;
227     }
228 }
229 } // end namespace itk
230 
231 #endif
232