ITK  5.0.0
Insight Segmentation and Registration Toolkit
itkParabolicMorphUtils.h
Go to the documentation of this file.
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 itkParabolicMorphUtils_h
19 #define itkParabolicMorphUtils_h
20 
21 #include <itkArray.h>
22 
23 namespace itk
24 {
25 // contact point algorithm
26 template< class LineBufferType, class RealType, bool doDilate >
27 void DoLineCP(LineBufferType & LineBuf, LineBufferType & tmpLineBuf,
28  const RealType magnitude, const RealType m_Extreme)
29 {
30  // contact point algorithm
31  long koffset = 0, newcontact = 0; // how far away the search starts.
32 
33  const long LineLength = LineBuf.size();
34 
35  // negative half of the parabola
36  for ( long pos = 0; pos < LineLength; pos++ )
37  {
38  auto BaseVal = (RealType)m_Extreme; // the base value for
39  // comparison
40  for ( long krange = koffset; krange <= 0; krange++ )
41  {
42  // difference needs to be paramaterised
43  RealType T = LineBuf[pos + krange] - magnitude * krange * krange;
44  // switch on template parameter - hopefully gets optimized away.
45  if ( doDilate ? ( T >= BaseVal ) : ( T <= BaseVal ) )
46  {
47  BaseVal = T;
48  newcontact = krange;
49  }
50  }
51  tmpLineBuf[pos] = BaseVal;
52  koffset = newcontact - 1;
53  }
54  // positive half of parabola
55  koffset = newcontact = 0;
56  for ( long pos = LineLength - 1; pos >= 0; pos-- )
57  {
58  auto BaseVal = (RealType)m_Extreme; // the base value for comparison
59  for ( long krange = koffset; krange >= 0; krange-- )
60  {
61  RealType T = tmpLineBuf[pos + krange] - magnitude * krange * krange;
62  if ( doDilate ? ( T >= BaseVal ) : ( T <= BaseVal ) )
63  {
64  BaseVal = T;
65  newcontact = krange;
66  }
67  }
68  LineBuf[pos] = BaseVal;
69  koffset = newcontact + 1;
70  }
71 }
72 
73 // intersection algorithm
74 // This algorithm has been described a couple of times. First by van
75 // den Boomgaard and more recently by Felzenszwalb and Huttenlocher,
76 // in the context of generalized distance transform
77 template< class LineBufferType, class IndexBufferType,
78  class EnvBufferType, class RealType, bool doDilate >
79 void DoLineIntAlg(LineBufferType & LineBuf, EnvBufferType & F,
80  IndexBufferType & v, EnvBufferType & z,
81  const RealType magnitude)
82 {
83  int k; /* Index of rightmost parabola in lower envelope */
84  /* Locations of parabolas in lower envelope */
85  /* these need to be int, rather than unsigned, to make boundary
86  conditions easy to test */
87 
88  // v stores locations of parabolas in the lower envelope
89  // z stores thr location of boundaries between parabolas
90 
91  // I've gone nuts with the static casts etc, because I seemed to
92  // have strange behaviour when I didn't do this. Also managed to get
93  // rid of all the warnings by sticking to size_t and equivalents.
94  RealType s;
95 
96  /* holds precomputed scale*f(q) + q^2 for speedup */
97 // LineBufferType F(LineBuf.size());
98 
99  // initialize
100  k = 0;
101  v[0] = 0;
103  z[1] = NumericTraits< int >::max();
104  F[0] = LineBuf[0] / magnitude;
105  const size_t N( LineBuf.size() );
106 
107  for ( size_t q = 1; q < N; q++ ) /* main loop */
108  {
109  if ( doDilate )
110  {
111  /* precompute f(q) + q^2 for speedup */
112  F[q] = ( LineBuf[q] / magnitude ) - ( static_cast< RealType >( q ) * static_cast< RealType >( q ) );
113  k++;
114  do
115  {
116  /* remove last parabola from surface */
117  k--;
118  /* compute intersection */
119  s = ( F[q] - F[v[k]] ) / ( 2.0 * ( v[k] - static_cast< RealType >( q ) ) );
120  }
121  while ( s <= z[k] );
122  /* bump k to add new parabola */
123  k++;
124  }
125  else
126  {
127  /* precompute f(q) + q^2 for speedup */
128  F[q] = ( LineBuf[q] / magnitude )
129  + ( static_cast< RealType >( q ) * static_cast< RealType >( q ) );
130  k++;
131  do
132  {
133  /* remove last parabola from surface */
134  k--;
135  /* compute intersection */
136  s = ( F[q] - F[v[k]] ) / ( 2.0 * ( static_cast< RealType >( q ) - v[k] ) );
137  }
138  while ( s <= z[k] );
139  /* bump k to add new parabola */
140  k++;
141  }
142  v[k] = q;
143  z[k] = s;
144  itkAssertInDebugAndIgnoreInReleaseMacro( (size_t)( k + 1 ) <= N );
145  z[k + 1] = NumericTraits< int >::max();
146  } /* for q */
147  /* now reconstruct output */
148  if ( doDilate )
149  {
150  k = 0;
151  for ( size_t q = 0; q < N; q++ )
152  {
153  while ( z[k + 1] < static_cast< typename IndexBufferType::ValueType >( q ) )
154  {
155  k++;
156  }
157  itkAssertInDebugAndIgnoreInReleaseMacro(static_cast< size_t >( v[k] ) < N);
158  itkAssertInDebugAndIgnoreInReleaseMacro(static_cast< size_t >( v[k] ) >= 0);
159  LineBuf[q] =
160  static_cast< RealType >( ( F[v[k]]
161  - ( static_cast< RealType >( q )
162  * ( static_cast< RealType >( q ) - 2 * v[k] ) ) ) * magnitude );
163  }
164  }
165  else
166  {
167  k = 0;
168  for ( size_t q = 0; q < N; q++ )
169  {
170  while ( z[k + 1] < static_cast< typename IndexBufferType::ValueType >( q ) )
171  {
172  k++;
173  }
174  itkAssertInDebugAndIgnoreInReleaseMacro(static_cast< size_t >( v[k] ) < N);
175  itkAssertInDebugAndIgnoreInReleaseMacro(static_cast< size_t >( v[k] ) >= 0);
176  LineBuf[q] =
177  ( ( static_cast< RealType >( q ) * ( static_cast< RealType >( q ) - 2 * v[k] ) + F[v[k]] ) * magnitude );
178  }
179  }
180 }
181 
182 template< class TInIter, class TOutIter, class RealType,
183  class OutputPixelType, bool doDilate >
184 void doOneDimension(TInIter & inputIterator, TOutIter & outputIterator,
185  const long LineLength,
186  const unsigned direction,
187  const int m_MagnitudeSign,
188  const bool m_UseImageSpacing,
189  const RealType m_Extreme,
190  const RealType image_scale,
191  const RealType Sigma,
192  int ParabolicAlgorithmChoice)
193 {
194  enum ParabolicAlgorithm {
195  NOCHOICE = 0, // decices based on scale - experimental
196  CONTACTPOINT = 1, // sometimes faster at low scale
197  INTERSECTION = 2 // default
198  };
199 
200 // using LineBufferType = typename std::vector<RealType>;
201 
202  // message from M.Starring suggested performance gain using Array
203  // instead of std::vector.
204  using LineBufferType = typename itk::Array< RealType >;
205  RealType iscale = 1.0;
206  if ( m_UseImageSpacing )
207  {
208  iscale = image_scale;
209  }
210  if ( ParabolicAlgorithmChoice == NOCHOICE )
211  {
212  // both set to true or false - use scale to figure it out
213  if ( ( 2.0 * Sigma ) < 0.2 )
214  {
215  ParabolicAlgorithmChoice = CONTACTPOINT;
216  }
217  else
218  {
219  ParabolicAlgorithmChoice = INTERSECTION;
220  }
221  }
222 
223  if ( ParabolicAlgorithmChoice == CONTACTPOINT )
224  {
225  // using the contact point algorithm
226 
227 // const RealType magnitude = m_MagnitudeSign * 1.0/(2.0 *
228 // Sigma/(iscale*iscale));
229  // restructure equation to reduce numerical error
230  const RealType magnitudeCP = ( m_MagnitudeSign * iscale * iscale ) / ( 2.0 * Sigma );
231 
232  LineBufferType LineBuf(LineLength);
233  LineBufferType tmpLineBuf(LineLength);
234  inputIterator.SetDirection(direction);
235  outputIterator.SetDirection(direction);
236  inputIterator.GoToBegin();
237  outputIterator.GoToBegin();
238 
239  unsigned count = 0;
240  while ( !inputIterator.IsAtEnd() && !outputIterator.IsAtEnd() )
241  {
242  // process this direction
243  // fetch the line into the buffer - this methodology is like
244  // the gaussian filters
245 
246  unsigned int i = 0;
247  while ( !inputIterator.IsAtEndOfLine() )
248  {
249  LineBuf[i++] = static_cast< RealType >( inputIterator.Get() );
250  ++inputIterator;
251  }
252 
253  DoLineCP< LineBufferType, RealType, doDilate >(LineBuf, tmpLineBuf, magnitudeCP, m_Extreme);
254  // copy the line back
255  unsigned int j = 0;
256  while ( !outputIterator.IsAtEndOfLine() )
257  {
258  outputIterator.Set( static_cast< OutputPixelType >( LineBuf[j++] ) );
259  ++outputIterator;
260  }
261 
262  ++count;
263  // now onto the next line
264  inputIterator.NextLine();
265  outputIterator.NextLine();
266  }
267  }
268  else
269  {
270  // using the Intersection algorithm
271  using IndexBufferType = typename itk::Array< int >;
272 
273  const RealType magnitudeInt = ( iscale * iscale ) / ( 2.0 * Sigma );
274  LineBufferType LineBuf(LineLength);
275  LineBufferType Fbuf(LineLength);
276  IndexBufferType Vbuf(LineLength);
277  LineBufferType Zbuf(LineLength + 1);
278 
279  inputIterator.SetDirection(direction);
280  outputIterator.SetDirection(direction);
281  inputIterator.GoToBegin();
282  outputIterator.GoToBegin();
283 
284  unsigned count = 0;
285  while ( !inputIterator.IsAtEnd() && !outputIterator.IsAtEnd() )
286  {
287  // process this direction
288  // fetch the line into the buffer - this methodology is like
289  // the gaussian filters
290 
291  unsigned int i = 0;
292  while ( !inputIterator.IsAtEndOfLine() )
293  {
294  LineBuf[i++] = static_cast< RealType >( inputIterator.Get() );
295  ++inputIterator;
296  }
297  DoLineIntAlg< LineBufferType, IndexBufferType,
298  LineBufferType, RealType, doDilate >(LineBuf, Fbuf, Vbuf, Zbuf, magnitudeInt);
299  // copy the line back
300  unsigned int j = 0;
301  while ( !outputIterator.IsAtEndOfLine() )
302  {
303  outputIterator.Set( static_cast< OutputPixelType >( LineBuf[j++] ) );
304  ++outputIterator;
305  }
306 
307  ++count;
308  // now onto the next line
309  inputIterator.NextLine();
310  outputIterator.NextLine();
311  }
312  }
313 }
314 }
315 #endif
void DoLineCP(LineBufferType &LineBuf, LineBufferType &tmpLineBuf, const RealType magnitude, const RealType m_Extreme)
Define numeric traits for std::vector.
void DoLineIntAlg(LineBufferType &LineBuf, EnvBufferType &F, IndexBufferType &v, EnvBufferType &z, const RealType magnitude)
void doOneDimension(TInIter &inputIterator, TOutIter &outputIterator, const long LineLength, const unsigned direction, const int m_MagnitudeSign, const bool m_UseImageSpacing, const RealType m_Extreme, const RealType image_scale, const RealType Sigma, int ParabolicAlgorithmChoice)