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