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 itkMovingHistogramImageFilter_hxx
19 #define itkMovingHistogramImageFilter_hxx
20
21 #include "itkMovingHistogramImageFilter.h"
22 #include "itkImageRegionIteratorWithIndex.h"
23 #include "itkOffset.h"
24 #include "itkProgressReporter.h"
25 #include "itkNumericTraits.h"
26 #include "itkImageRegionIterator.h"
27 #include "itkImageLinearConstIteratorWithIndex.h"
28
29 namespace itk
30 {
31 template< typename TInputImage, typename TOutputImage, typename TKernel, typename THistogram >
32 MovingHistogramImageFilter< TInputImage, TOutputImage, TKernel, THistogram >
MovingHistogramImageFilter()33 ::MovingHistogramImageFilter()
34 {
35 this->DynamicMultiThreadingOn();
36 }
37
38 // a modified version that uses line iterators and only moves the
39 // histogram in one direction. Hopefully it will be a bit simpler and
40 // faster due to improved memory access and a tighter loop.
41 template< typename TInputImage, typename TOutputImage, typename TKernel, typename THistogram >
42 void
43 MovingHistogramImageFilter< TInputImage, TOutputImage, TKernel, THistogram >
DynamicThreadedGenerateData(const OutputImageRegionType & outputRegionForThread)44 ::DynamicThreadedGenerateData(const OutputImageRegionType & outputRegionForThread)
45 {
46 HistogramType histogram;
47 this->ConfigureHistogram( histogram );
48
49 OutputImageType * outputImage = this->GetOutput();
50 const InputImageType *inputImage = this->GetInput();
51 RegionType inputRegion = inputImage->GetRequestedRegion();
52
53 // initialize the histogram
54 for ( auto listIt = this->m_KernelOffsets.begin();
55 listIt != this->m_KernelOffsets.end();
56 listIt++ )
57 {
58 IndexType idx = outputRegionForThread.GetIndex() + ( *listIt );
59 if ( inputRegion.IsInside(idx) )
60 {
61 histogram.AddPixel( inputImage->GetPixel(idx) );
62 }
63 else
64 {
65 histogram.AddBoundary();
66 }
67 }
68
69 // now move the histogram
70 FixedArray< short, ImageDimension > direction;
71 direction.Fill(1);
72 int axis = ImageDimension - 1;
73 OffsetType offset;
74 offset.Fill(0);
75 RegionType stRegion;
76 stRegion.SetSize( this->m_Kernel.GetSize() );
77 stRegion.PadByRadius(1); // must pad the region by one because of the translation
78
79 OffsetType centerOffset;
80 unsigned int i;
81 for ( i = 0; i < ImageDimension; i++ )
82 {
83 centerOffset[i] = stRegion.GetSize()[i] / 2;
84 }
85
86 int BestDirection = this->m_Axes[axis];
87 int LineLength = inputRegion.GetSize()[BestDirection];
88
89 // init the offset and get the lists for the best axis
90 offset[BestDirection] = direction[BestDirection];
91 // it's very important for performances to get a pointer and not a copy
92 const OffsetListType *addedList = &this->m_AddedOffsets[offset];
93 const OffsetListType *removedList = &this->m_RemovedOffsets[offset];
94
95 using InputLineIteratorType = ImageLinearConstIteratorWithIndex< InputImageType >;
96 InputLineIteratorType InLineIt(inputImage, outputRegionForThread);
97 InLineIt.SetDirection(BestDirection);
98
99 InLineIt.GoToBegin();
100 IndexType LineStart;
101 //PrevLineStart = InLineIt.GetIndex();
102 InLineIt.GoToBegin();
103
104 using HistVecType = typename std::vector< HistogramType >;
105 HistVecType HistVec(ImageDimension);
106 using IndexVecType = typename std::vector< IndexType >;
107 IndexVecType PrevLineStartVec(ImageDimension);
108
109 // Steps is used to keep track of the order in which the line
110 // iterator passes over the various dimensions.
111 auto * Steps = new int[ImageDimension];
112
113 for ( i = 0; i < ImageDimension; i++ )
114 {
115 HistVec[i] = histogram;
116 PrevLineStartVec[i] = InLineIt.GetIndex();
117 Steps[i] = 0;
118 }
119
120 while ( !InLineIt.IsAtEnd() )
121 {
122 HistogramType & histRef = HistVec[BestDirection];
123 IndexType PrevLineStart = InLineIt.GetIndex();
124 for ( InLineIt.GoToBeginOfLine(); !InLineIt.IsAtEndOfLine(); ++InLineIt )
125 {
126 // Update the historgram
127 IndexType currentIdx = InLineIt.GetIndex();
128 outputImage->SetPixel( currentIdx,
129 static_cast< OutputPixelType >( histRef.GetValue( inputImage->GetPixel(currentIdx) ) ) );
130 stRegion.SetIndex(currentIdx - centerOffset);
131 PushHistogram(histRef, addedList, removedList, inputRegion,
132 stRegion, inputImage, currentIdx);
133 }
134 Steps[BestDirection] += LineLength;
135 InLineIt.NextLine();
136 if ( InLineIt.IsAtEnd() )
137 {
138 break;
139 }
140 LineStart = InLineIt.GetIndex();
141 // This section updates the histogram for the next line
142 // Since we aren't zig zagging we need to figure out which
143 // histogram to update and the direction in which to push
144 // it. Then we need to copy that histogram to the relevant
145 // places
146 OffsetType LineOffset, Changes;
147 // Figure out which stored histogram to move and in
148 // which direction
149 int LineDirection = 0;
150 // This function deals with changing planes etc
151 this->GetDirAndOffset(LineStart, PrevLineStart,
152 LineOffset, Changes, LineDirection);
153 ++( Steps[LineDirection] );
154 IndexType PrevLineStartHist = LineStart - LineOffset;
155 const OffsetListType *addedListLine = &this->m_AddedOffsets[LineOffset];
156 const OffsetListType *removedListLine = &this->m_RemovedOffsets[LineOffset];
157 HistogramType & tmpHist = HistVec[LineDirection];
158 stRegion.SetIndex(PrevLineStart - centerOffset);
159 // Now move the histogram
160 PushHistogram(tmpHist, addedListLine, removedListLine, inputRegion,
161 stRegion, inputImage, PrevLineStartHist);
162
163 //PrevLineStartVec[LineDirection] = LineStart;
164 // copy the updated histogram and line start entries to the
165 // relevant directions. When updating direction 2, for example,
166 // new copies of directions 0 and 1 should be made.
167 for ( i = 0; i < ImageDimension; i++ )
168 {
169 if ( Steps[i] > Steps[LineDirection] )
170 {
171 //PrevLineStartVec[i] = LineStart;
172 HistVec[i] = HistVec[LineDirection];
173 }
174 }
175 }
176 delete[] Steps;
177 }
178
179 template< typename TInputImage, typename TOutputImage, typename TKernel, typename THistogram >
180 void
181 MovingHistogramImageFilter< TInputImage, TOutputImage, TKernel, THistogram >
PushHistogram(HistogramType & histogram,const OffsetListType * addedList,const OffsetListType * removedList,const RegionType & inputRegion,const RegionType & kernRegion,const InputImageType * inputImage,const IndexType currentIdx)182 ::PushHistogram(HistogramType & histogram,
183 const OffsetListType *addedList,
184 const OffsetListType *removedList,
185 const RegionType & inputRegion,
186 const RegionType & kernRegion,
187 const InputImageType *inputImage,
188 const IndexType currentIdx)
189 {
190 if ( inputRegion.IsInside(kernRegion) )
191 {
192 // update the histogram
193 for ( auto addedIt = addedList->begin(); addedIt != addedList->end(); addedIt++ )
194 {
195 histogram.AddPixel( inputImage->GetPixel( currentIdx + ( *addedIt ) ) );
196 }
197 for ( auto removedIt = removedList->begin();
198 removedIt != removedList->end();
199 removedIt++ )
200 {
201 histogram.RemovePixel( inputImage->GetPixel( currentIdx + ( *removedIt ) ) );
202 }
203 }
204 else
205 {
206 // update the histogram
207 for ( auto addedIt = addedList->begin(); addedIt != addedList->end(); addedIt++ )
208 {
209 IndexType idx = currentIdx + ( *addedIt );
210 if ( inputRegion.IsInside(idx) )
211 { histogram.AddPixel( inputImage->GetPixel(idx) ); }
212 else
213 { histogram.AddBoundary(); }
214 }
215 for ( auto removedIt = removedList->begin();
216 removedIt != removedList->end();
217 removedIt++ )
218 {
219 IndexType idx = currentIdx + ( *removedIt );
220 if ( inputRegion.IsInside(idx) )
221 { histogram.RemovePixel( inputImage->GetPixel(idx) ); }
222 else
223 { histogram.RemoveBoundary(); }
224 }
225 }
226 }
227
228 } // end namespace itk
229 #endif
230