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