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 itkStreamingImageFilter_hxx
19 #define itkStreamingImageFilter_hxx
20 #include "itkStreamingImageFilter.h"
21 #include "itkCommand.h"
22 #include "itkImageAlgorithm.h"
23 #include "itkImageRegionSplitterSlowDimension.h"
24
25 namespace itk
26 {
27 /**
28 *
29 */
30 template< typename TInputImage, typename TOutputImage >
31 StreamingImageFilter< TInputImage, TOutputImage >
StreamingImageFilter()32 ::StreamingImageFilter()
33 {
34 // default to 10 divisions
35 m_NumberOfStreamDivisions = 10;
36
37 // create default region splitter
38 m_RegionSplitter = ImageRegionSplitterSlowDimension::New();
39 }
40
41 /**
42 *
43 */
44 template< typename TInputImage, typename TOutputImage >
45 void
46 StreamingImageFilter< TInputImage, TOutputImage >
PrintSelf(std::ostream & os,Indent indent) const47 ::PrintSelf(std::ostream & os, Indent indent) const
48 {
49 Superclass::PrintSelf(os, indent);
50
51 os << indent << "Number of stream divisions: " << m_NumberOfStreamDivisions
52 << std::endl;
53
54 itkPrintSelfObjectMacro( RegionSplitter );
55 }
56
57 /**
58 *
59 */
60 template< typename TInputImage, typename TOutputImage >
61 void
62 StreamingImageFilter< TInputImage, TOutputImage >
PropagateRequestedRegion(DataObject * output)63 ::PropagateRequestedRegion(DataObject *output)
64 {
65 /**
66 * check flag to avoid executing forever if there is a loop
67 */
68 if ( this->m_Updating )
69 {
70 return;
71 }
72
73 /**
74 * Give the subclass a chance to indicate that it will provide
75 * more data than required for the output. This can happen, for
76 * example, when a source can only produce the whole output.
77 * Although this is being called for a specific output, the source
78 * may need to enlarge all outputs.
79 */
80 this->EnlargeOutputRequestedRegion(output);
81
82 /**
83 * Give the subclass a chance to define how to set the requested
84 * regions for each of its outputs, given this output's requested
85 * region. The default implementation is to make all the output
86 * requested regions the same. A subclass may need to override this
87 * method if each output is a different resolution.
88 */
89 this->GenerateOutputRequestedRegion(output);
90
91 // we don't call GenerateInputRequestedRegion since the requested
92 // regions are manage when the pipeline is execute
93
94 // we don't call inputs PropagateRequestedRegion either
95 // because the pipeline managed later
96 }
97
98 /**
99 *
100 */
101 template< typename TInputImage, typename TOutputImage >
102 void
103 StreamingImageFilter< TInputImage, TOutputImage >
UpdateOutputData(DataObject * itkNotUsed (output))104 ::UpdateOutputData( DataObject *itkNotUsed(output) )
105 {
106
107 /**
108 * prevent chasing our tail
109 */
110 if ( this->m_Updating )
111 {
112 return;
113 }
114
115 /**
116 * Prepare all the outputs. This may deallocate previous bulk data.
117 */
118 this->PrepareOutputs();
119
120 /**
121 * Make sure we have the necessary inputs
122 */
123 const itk::ProcessObject::DataObjectPointerArraySizeType &ninputs = this->GetNumberOfValidRequiredInputs();
124 if ( ninputs < this->GetNumberOfRequiredInputs() )
125 {
126 itkExceptionMacro(
127 << "At least " << static_cast< unsigned int >( this->GetNumberOfRequiredInputs() )
128 << " inputs are required but only " << ninputs << " are specified.");
129 return;
130 }
131
132 /**
133 * Tell all Observers that the filter is starting, before emiting
134 * the 0.0 Progress event
135 */
136 this->InvokeEvent( StartEvent() );
137
138
139 this->SetAbortGenerateData(0);
140 this->UpdateProgress(0.0);
141 this->m_Updating = true;
142
143
144 /**
145 * Allocate the output buffer.
146 */
147 OutputImageType *outputPtr = this->GetOutput(0);
148 const OutputImageRegionType outputRegion = outputPtr->GetRequestedRegion();
149 outputPtr->SetBufferedRegion(outputRegion);
150 outputPtr->Allocate();
151
152 /**
153 * Grab the input
154 */
155 auto * inputPtr = const_cast< InputImageType * >( this->GetInput(0) );
156
157 /**
158 * Determine of number of pieces to divide the input. This will be the
159 * minimum of what the user specified via SetNumberOfStreamDivisions()
160 * and what the Splitter thinks is a reasonable value.
161 */
162 unsigned int numDivisions, numDivisionsFromSplitter;
163
164 numDivisions = m_NumberOfStreamDivisions;
165 numDivisionsFromSplitter =
166 m_RegionSplitter
167 ->GetNumberOfSplits(outputRegion, m_NumberOfStreamDivisions);
168 if ( numDivisionsFromSplitter < numDivisions )
169 {
170 numDivisions = numDivisionsFromSplitter;
171 }
172
173 /**
174 * Loop over the number of pieces, execute the upstream pipeline on each
175 * piece, and copy the results into the output image.
176 */
177 unsigned int piece=0;
178 for (;
179 piece < numDivisions && !this->GetAbortGenerateData();
180 piece++ )
181 {
182 InputImageRegionType streamRegion = outputRegion;
183 m_RegionSplitter->GetSplit(piece, numDivisions, streamRegion);
184
185 inputPtr->SetRequestedRegion(streamRegion);
186 inputPtr->PropagateRequestedRegion();
187 inputPtr->UpdateOutputData();
188
189 // copy the result to the proper place in the output. the input
190 // requested region determined by the RegionSplitter (as opposed
191 // to what the pipeline might have enlarged it to) is used to
192 // copy the regions from the input to output
193 ImageAlgorithm::Copy( inputPtr, outputPtr, streamRegion, streamRegion );
194
195
196 this->UpdateProgress( static_cast<float>(piece) / static_cast<float>(numDivisions) );
197 }
198
199 /**
200 * If we ended due to aborting, push the progress up to 1.0 (since
201 * it probably didn't end there)
202 */
203 if ( !this->GetAbortGenerateData() )
204 {
205 this->UpdateProgress(1.0);
206 }
207
208 // Notify end event observers
209 this->InvokeEvent( EndEvent() );
210
211 /**
212 * Now we have to mark the data as up to data.
213 */
214 for (auto &outputName : this->GetOutputNames() )
215 {
216 if (this->ProcessObject::GetOutput(outputName))
217 {
218 this->ProcessObject::GetOutput(outputName)->DataHasBeenGenerated();
219 }
220 }
221
222 /**
223 * Release any inputs if marked for release
224 */
225 this->ReleaseInputs();
226
227 // Mark that we are no longer updating the data in this filter
228 this->m_Updating = false;
229 }
230 } // end namespace itk
231
232 #endif
233