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