DGtal  0.6.devel
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
DistanceTransformation.ih
1 
30 
31 #include <cstdlib>
32 #include <boost/lexical_cast.hpp>
34 
36 // IMPLEMENTATION of inline methods.
38 
40 // ----------------------- Standard services ------------------------------
41 
45 template <typename S,typename P,DGtal::uint32_t p, typename IntLong>
46 inline
48  const PointPredicate & aPredicate):
49  myDomain(aDomain), myPointPredicate(aPredicate)
50 {
51 }
52 
53 
57 template <typename S, typename P,DGtal::uint32_t p, typename IntLong>
58 inline
60 {
61 }
62 
63 
64 
65 
66 template <typename S, typename P,DGtal::uint32_t p, typename IntLong>
67 inline
68 bool
70 {
71  typename Point::UnsignedComponent maxExtent = ( myDomain.upperBound() -
72  myDomain.lowerBound() ).normInfinity();
73 
74  //Estimate worst-case bit size (special case for p=0 == Linfinity
75  double bitSize;
76 
77  if (SeparableMetric::p != 0)
78  bitSize = SeparableMetric::p * (log ((double) S::dimension * 2 * maxExtent ) / log(2.0));
79  else
80  bitSize = sizeof ( typename OutputImage::Value ) * 8;
81 
82  if ( bitSize > sizeof ( typename OutputImage::Value ) * 8 )
83  {
84  trace.warning() << "(DistanceTransformation) The output image value range may"
85  <<" not be sufficient to store the exact values according to"
86  <<" the input domain extent." << endl;
87  return false;
88  }
89  return true;
90 }
91 
92 
93 template <typename S, typename P, DGtal::uint32_t p, typename IntLong>
94 inline
97 {
98 
99  //We trace type validdity check result;
100  checkTypesValidity ( );
101 
102  //We copy the image extent and translate the image domains to (0,..0)x(Upper-Lower)
103  myLowerBoundCopy = Point(); //(O,O,...O)
104  myUpperBoundCopy = myDomain.upperBound() - myDomain.lowerBound();
105  myDisplacementVector = myDomain.lowerBound();
106 
107  myExtent = myUpperBoundCopy - myLowerBoundCopy;
108  myInfinity = myMetric.power(static_cast<typename S::Integer>(S::dimension) *
109  myExtent.normInfinity() + 1);
110 
111  Domain workingDomain(myLowerBoundCopy, myUpperBoundCopy);
112  OutputImage output ( workingDomain );
113  OutputImage swap ( workingDomain );
114  bool isSwap = true;
115 
116  //First step
117  computeFirstStep ( output );
118 
119  //We process the dimensions swaping the temporary buffers
120  for ( Dimension dim = 1; dim < S::dimension ; dim++ )
121  {
122  if ( isSwap )
123  computeOtherSteps ( output, swap, dim );
124  else
125  computeOtherSteps ( swap, output, dim );
126 
127  isSwap = !isSwap;
128  }
129 
130  //We translate the output image to the correct position and return.
131  if ( !isSwap )
132  {
133  swap.translateDomain(myDisplacementVector);
134  return swap;
135  }
136 
137  else
138  {
139  output.translateDomain(myDisplacementVector);
140  return output;
141  }
142 }
143 
144 
145 template <typename S, typename P,DGtal::uint32_t p, typename IntLong>
146 inline
147 void
149 {
150  trace.beginBlock ( "DT dimension 0" );
151  Point startingPoint = myLowerBoundCopy;
152 
153  typedef typename Domain::ConstSubRange::ConstIterator ConstDomIt;
154 
155  //We setup the subdomain iterator
156  //the iterator will scan dimension using the order:
157  // {n-1, n-2, ... 1} (we skip the '0' dimension.
158  std::vector<Size> subdomain;
159  subdomain.reserve(S::dimension - 1);
160  for (Dimension k = S::dimension-1; k>0 ; --k)
161  subdomain.push_back( k );
162 
163  Domain localDomain(myLowerBoundCopy, myUpperBoundCopy);
164 
165  //We process the dimensions to construct a Point
166  for (ConstDomIt it = localDomain.subRange( subdomain ).begin(),
167  itend = localDomain.subRange( subdomain ).end(); it != itend; ++it)
168  {
169  // trace.info() << "Processing 1D slice starting at =" << (*it) << endl;
170  computeFirstStep1D (output, (*it) );
171  }
172 
173  trace.endBlock();
174 }
175 
176 
177 template <typename S, typename P,DGtal::uint32_t p, typename IntLong>
178 inline
179 void
181  OutputImage &output,
182  const Dimension dim ) const
183 {
184  std::string title = "DT dimension " + boost::lexical_cast<string>( dim ) ;
185  trace.beginBlock ( title );
186 
187  typedef typename Domain::ConstSubRange::ConstIterator ConstDomIt;
188 
189  //We setup the subdomain iterator
190  //the iterator will scan dimension using the order:
191  // {n-1, n-2, ... 1} (we skip the '0' dimension.
192 
193  std::vector<Size> subdomain;
194  subdomain.reserve(S::dimension - 1);
195  for (unsigned int k = 0; k < S::dimension ; k++)
196  if ( (S::dimension - 1 - k) != dim)
197  subdomain.push_back( S::dimension - 1 - k );
198 
199  Domain localDomain(myLowerBoundCopy, myUpperBoundCopy);
200  Size maxSize = myExtent.normInfinity();
201 
202  //Stacks used in the envelope computation
203  Abscissa *s = new Abscissa[maxSize+1];
204  Abscissa *t = new Abscissa[maxSize+1];
205 
206  ASSERT( s != NULL);
207  ASSERT( t != NULL);
208 
209  //We process the dimensions to construct a Point
210  for (ConstDomIt it = localDomain.subRange( subdomain ).begin(),
211  itend = localDomain.subRange( subdomain ).end();
212  it != itend; ++it)
213  {
214  computeOtherStep1D ( input, output, (*it), dim, s, t );
215  }
216 
217  delete[] s;
218  delete[] t;
219  trace.endBlock();
220 
221 }
222 
225 template <typename S, typename P,DGtal::uint32_t p, typename IntLong>
226 void
228  const Point &startingPoint ) const
229 {
230  Point prec = startingPoint;
231  Point point = startingPoint;
232 
233  //PRECOND : output can store 2*(myUpperBoundCopy[0] - myLowerBoundCopy[0]) in its valuetype
234  //INFTY = something > myUpperBoundCopy[0] - myLowerBoundCopy[0]
235  if ( myPointPredicate ( point + myDisplacementVector ) )
236  output.setValue ( point, myInfinity );
237  else
238  output.setValue ( point, 0 );
239 
240  //Forward scan
241  for ( point[0] = 1; point[0] <= myUpperBoundCopy[0]; point[0]++ )
242  {
243  // trace.warning() << point << " ";
244  if ( myPointPredicate ( point + myDisplacementVector ))
245  output.setValue ( point, 1 + output ( prec ) );
246  else
247  output.setValue ( point, 0 );
248 
249  prec[0] = point[0];
250  }
251 
252 
253  //prec is the the rightmost point of "point'
254  prec[0] = myUpperBoundCopy[0];
255 
256  //Backward scan
257  for ( point[0] = myUpperBoundCopy[0] - 1; point[0] >= 0 ; point[0]-- )
258  {
259  if ( output ( prec ) < output ( point ) )
260  output.setValue ( point, 1 + output ( prec ) );
261  prec[0] = point[0];
262  }
263 
264  //final computation
265  for ( point[0] = 0; point[0] <= myUpperBoundCopy[0]; point[0]++ )
266  if (output( point ) < myInfinity)
267  output.setValue ( point, myMetric.power( (const int)output ( point ) ));
268  else
269  output.setValue ( point, myInfinity);
270 }
271 
272 
275 template <typename S,typename P, DGtal::uint32_t p, typename IntLong>
276 void
278  OutputImage & output,
279  const Point &startingPoint,
280  const Size dim,
281  Abscissa s[],
282  Abscissa t[] ) const
283 {
284  Abscissa w;
285  Abscissa q = 0; //index for the stack "head"
286 
287  Point sQ = startingPoint;
288  Point pU = startingPoint;
289 
290  // We look for the first point in the 1D column with distance different from
291  // myInfinity
292  pU[dim] = myLowerBoundCopy[dim];
293  while ((pU[dim] <= myUpperBoundCopy[dim]) && (input ( pU ) == myInfinity))
294  pU[dim] ++;
295 
296 
297  // All points are set to +infinity, we just copy the infinity value and return
298  if ( pU[dim] > myUpperBoundCopy[dim] )
299  {
300  for(typename OutputImage::SpanIterator it= output.spanBegin(startingPoint,dim),
301  itend=output.spanEnd(startingPoint,dim);
302  it != itend; ++it)
303  output.setValue(it, myInfinity);
304  return;
305  }
306 
307  //Stack structure
308  q = 0;
309  s[q] = pU[dim]; // first point with DT!=infinity
310  sQ[dim] = s[q]; // nD Point corresponding to the head of the stack
311  t[q] = myLowerBoundCopy[dim];
312 
313  //Forward Scan
314  //We scan all the pixels
315  for ( Abscissa u = pU[dim] + 1; u <= myUpperBoundCopy[dim] ; u++ )
316  {
317  pU[ dim ] = u;
318  if ( input( pU ) == myInfinity )
319  {
320  continue;
321  }
322 
323  while ( ( q >= 0 ) &&
324  ( myMetric.F ( t[q], s[q], input ( sQ ) ) >
325  myMetric.F ( t[q], u, input ( pU ) ) ) )
326  {
327  q--;
329  if (q>=0)
330  sQ[dim] = s[q];
331  }
332 
333  if ( q < 0 )
334  {
335  q = 0;
336  s[0] = u;
337  sQ[dim] = u;
338  t[0] = myLowerBoundCopy[dim];
339  }
340  else
341  {
342  sQ[dim] = s[q];
343  w = 1 + myMetric.Sep ( s[q],
344  input ( sQ ),
345  u,
346  input ( pU ) );
347 
348  if (( w <= myUpperBoundCopy[dim] )
349  && (w>= myLowerBoundCopy[dim]))
350  {
351  q++;
352  s[q] = u;
353  sQ[dim] = u;
354  t[q] = w;
355  }
356  }
357  }
358 
359  Point last = startingPoint;
360 
361  ASSERT(q>=0);
362 
363  sQ[dim] = s[q];
364 
365  //Backward Scan
366  for (last[dim] = myUpperBoundCopy[dim];
367  last[dim] >= myLowerBoundCopy[dim] ;
368  last[dim]-- )
369  {
370  output.setValue ( last, myMetric.F ( last[dim] , s[q], input ( sQ ) ) );
371  if (( last[dim] == t[q] ) && (q > 0))
372  {
373  q--;
374  sQ[dim] = s[q];
375  }
376  }
377 }
378 
379 
380 // //
382 
383