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 itkAnchorOpenCloseLine_hxx
19 #define itkAnchorOpenCloseLine_hxx
20
21 #include "itkAnchorOpenCloseLine.h"
22
23 namespace itk
24 {
25 template< typename TInputPix, typename TCompare >
26 AnchorOpenCloseLine< TInputPix, TCompare >
AnchorOpenCloseLine()27 ::AnchorOpenCloseLine()
28 {
29 m_Size = 2;
30 }
31
32 template< typename TInputPix, typename TCompare >
33 void
34 AnchorOpenCloseLine< TInputPix, TCompare >
DoLine(std::vector<InputImagePixelType> & buffer,unsigned bufflength)35 ::DoLine(std::vector<InputImagePixelType> & buffer, unsigned bufflength)
36 {
37 // TFunction1 will be >= for openings
38 // TFunction2 will be <=
39 // TFunction3 will be >
40
41 // the initial version will adopt the methodology of loading a line
42 // at a time into a buffer vector, carrying out the opening or
43 // closing, and then copy the result to the output. Hopefully this
44 // will improve cache performance when working along non raster
45 // directions.
46 if ( bufflength <= m_Size / 2 )
47 {
48 // No point doing anything fancy - just look for the extreme value
49 // This is important for angled structuring elements
50 InputImagePixelType Extreme = buffer[0];
51 for ( unsigned i = 0; i < bufflength; i++ )
52 {
53 if ( Compare1(Extreme, buffer[i]) )
54 {
55 Extreme = buffer[i];
56 }
57 }
58
59 for ( unsigned i = 0; i < bufflength; i++ )
60 {
61 buffer[i] = Extreme;
62 }
63 return;
64 }
65
66 // start the real work - everything here will be done with index
67 // arithmetic rather than pointer arithmetic
68 unsigned outLeftP = 0, outRightP = bufflength - 1;
69 // left side
70 while ( ( outLeftP < outRightP ) && Compare1(buffer[outLeftP], buffer[outLeftP + 1]) )
71 {
72 ++outLeftP;
73 }
74 while ( ( outLeftP < outRightP ) && Compare2(buffer[outRightP - 1], buffer[outRightP]) )
75 {
76 --outRightP;
77 }
78 InputImagePixelType Extreme;
79 while ( StartLine(buffer, Extreme, outLeftP, outRightP) )
80 {}
81
82 FinishLine(buffer, Extreme, outLeftP, outRightP);
83 // this section if to make the edge behaviour the same as the more
84 // traditional approaches. It isn't part of the core anchor method.
85 // Note that the index calculations include some extra factors that
86 // relate to the padding at either end to allow users to set
87 // borders.
88 // compat
89 // fix left border
90 Extreme = buffer[m_Size / 2 + 1];
91 for ( int i = m_Size / 2; i >= 0; i-- )
92 {
93 if ( Compare1(Extreme, buffer[i]) )
94 {
95 Extreme = buffer[i];
96 }
97 // std::cout << i << " " << (int)Extreme << " " << (int)buffer[i] <<
98 // std::endl;
99 buffer[i] = Extreme;
100 }
101 // fix right border
102 Extreme = buffer[bufflength - m_Size / 2 - 2];
103 for ( int i = (int)bufflength - m_Size / 2 - 1; i < (int)bufflength; i++ )
104 {
105 if ( Compare1(Extreme, buffer[i]) )
106 {
107 Extreme = buffer[i];
108 }
109 // std::cout << (int)Extreme << " " << (int)buffer[i] << std::endl;
110 buffer[i] = Extreme;
111 }
112 }
113
114 template< typename TInputPix, typename TCompare >
115 bool
116 AnchorOpenCloseLine< TInputPix, TCompare >
StartLine(std::vector<InputImagePixelType> & buffer,InputImagePixelType & Extreme,unsigned & outLeftP,unsigned & outRightP)117 ::StartLine(std::vector<InputImagePixelType> & buffer,
118 InputImagePixelType & Extreme,
119 unsigned & outLeftP,
120 unsigned & outRightP
121 )
122 {
123 // This returns true to indicate return to startLine label in pseudo
124 // code, and false to indicate finshLine
125 Extreme = buffer[outLeftP];
126 unsigned currentP = outLeftP + 1;
127 unsigned sentinel, endP;
128
129 while ( ( currentP < outRightP ) && Compare2(buffer[currentP], Extreme) )
130 {
131 Extreme = buffer[currentP];
132 ++outLeftP;
133 ++currentP;
134 }
135
136 sentinel = outLeftP + m_Size;
137 if ( sentinel > outRightP )
138 {
139 // finish
140 return ( false );
141 }
142 ++currentP;
143 // ran m_Size pixels ahead
144 while ( currentP < sentinel )
145 {
146 if ( Compare2(buffer[currentP], Extreme) )
147 {
148 endP = currentP;
149 for ( unsigned PP = outLeftP + 1; PP < endP; ++PP )
150 {
151 buffer[PP] = Extreme;
152 }
153 outLeftP = currentP;
154 return ( true );
155 }
156 ++currentP;
157 }
158 // We didn't find a smaller (for opening) value in the segment of
159 // reach of outLeftP. currentP is the first position outside the
160 // reach of outLeftP
161 HistogramType histo;
162 if ( Compare2(buffer[currentP], Extreme) )
163 {
164 endP = currentP;
165 for ( unsigned PP = outLeftP + 1; PP < endP; ++PP )
166 {
167 buffer[PP] = Extreme;
168 }
169 outLeftP = currentP;
170 return ( true );
171 }
172 else
173 {
174 // Now we need a histogram
175 // Initialise it
176 outLeftP++;
177 for ( unsigned aux = outLeftP; aux <= currentP; ++aux )
178 {
179 histo.AddPixel(buffer[aux]);
180 }
181 // find the minimum value. The version
182 // in the paper assumes integer pixel types and initializes the
183 // search to the current extreme. Hopefully the latter is an
184 // optimization step.
185 Extreme = histo.GetValue();
186 histo.RemovePixel(buffer[outLeftP]);
187 buffer[outLeftP] = Extreme;
188 histo.AddPixel(Extreme);
189 }
190
191 while ( currentP < outRightP )
192 {
193 ++currentP;
194 if ( Compare2(buffer[currentP], Extreme) )
195 {
196 // Found a new extrem
197 endP = currentP;
198 for ( unsigned PP = outLeftP + 1; PP < endP; PP++ )
199 {
200 buffer[PP] = Extreme;
201 }
202 outLeftP = currentP;
203 return ( true );
204 }
205 else
206 {
207 /* histogram update */
208 histo.AddPixel(buffer[currentP]);
209 histo.RemovePixel(buffer[outLeftP]);
210 Extreme = histo.GetValue();
211 ++outLeftP;
212 histo.RemovePixel(buffer[outLeftP]);
213 buffer[outLeftP] = Extreme;
214 histo.AddPixel(Extreme);
215 }
216 }
217 // Finish the line
218 while ( outLeftP < outRightP )
219 {
220 histo.RemovePixel(buffer[outLeftP]);
221 Extreme = histo.GetValue();
222 ++outLeftP;
223 histo.RemovePixel(buffer[outLeftP]);
224 buffer[outLeftP] = Extreme;
225 histo.AddPixel(Extreme);
226 }
227 return ( false );
228 }
229
230 template< typename TInputPix, typename TCompare >
231 void
232 AnchorOpenCloseLine< TInputPix, TCompare >
FinishLine(std::vector<InputImagePixelType> & buffer,InputImagePixelType & Extreme,unsigned & outLeftP,unsigned & outRightP)233 ::FinishLine(std::vector<InputImagePixelType> & buffer,
234 InputImagePixelType & Extreme,
235 unsigned & outLeftP,
236 unsigned & outRightP
237 )
238 {
239 while ( outLeftP < outRightP )
240 {
241 if ( Compare2(buffer[outLeftP], buffer[outRightP]) )
242 {
243 Extreme = buffer[outRightP];
244 --outRightP;
245 if ( !Compare2(buffer[outRightP], Extreme) )
246 {
247 buffer[outRightP] = Extreme;
248 }
249 }
250 else
251 {
252 Extreme = buffer[outLeftP];
253 ++outLeftP;
254 if ( !Compare2(buffer[outLeftP], Extreme) )
255 {
256 buffer[outLeftP] = Extreme;
257 }
258 }
259 }
260 }
261
262 template< typename TInputPix, typename TCompare >
263 void
264 AnchorOpenCloseLine< TInputPix, TCompare >
PrintSelf(std::ostream & os,Indent indent) const265 ::PrintSelf(std::ostream & os, Indent indent) const
266 {
267 os << indent << "Size: " << m_Size << std::endl;
268 }
269 } // end namespace itk
270
271 #endif
272