DGtal  0.6.devel
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
testFMM.cpp
1 
29 
30 #include <iostream>
31 #include <iomanip>
32 #include <functional>
33 
34 #include "DGtal/base/Common.h"
35 
36 #include "DGtal/kernel/SpaceND.h"
37 #include "DGtal/kernel/domains/HyperRectDomain.h"
38 #include "DGtal/kernel/BasicPointPredicates.h"
39 #include "DGtal/kernel/domains/DomainPredicate.h"
40 #include "DGtal/kernel/sets/SetPredicate.h"
41 #include "DGtal/kernel/sets/DigitalSetFromMap.h"
42 #include "DGtal/images/ImageContainerBySTLMap.h"
43 #include "DGtal/images/imagesSetsUtils/SimpleThresholdForegroundPredicate.h"
44 
45 //DT
46 #include "DGtal/images/ImageSelector.h"
47 #include "DGtal/geometry/volumes/distance/DistanceTransformation.h"
48 
49 //FMM
50 #include "DGtal/geometry/volumes/distance/FMM.h"
51 
52 //Display
53 #include "DGtal/io/colormaps/HueShadeColorMap.h"
54 #include "DGtal/io/boards/Board2D.h"
55 
56 //shape and digitizer
57 #include "DGtal/shapes/ShapeFactory.h"
58 #include "DGtal/shapes/Shapes.h"
59 #include "DGtal/topology/helpers/Surfaces.h"
60 #include "DGtal/shapes/GaussDigitizer.h"
61 #include "DGtal/geometry/curves/GridCurve.h"
62 
64 
65 using namespace std;
66 using namespace DGtal;
67 
69 //
70 template <typename TImage, typename TSet, int norm>
72 {
74 };
75 //partial specialization
76 template <typename TImage, typename TSet>
77 struct DistanceTraits<TImage, TSet, 1>
78 {
80 };
81 
83 // digital circle generator
84 template <typename TPoint>
86 {
87 public:
88  typedef TPoint Point;
89 
90 public:
91 
92  BallPredicate(double aCx, double aCy, double aR ):
93  myCx(aCx), myCy(aCy), myR(aR)
94  { ASSERT(myR > 0); };
95 
96  bool operator()(const TPoint& aPoint) const
97  {
98  double d = std::sqrt( std::pow( (myCx-aPoint[0] ), 2)
99  + std::pow( (myCy-aPoint[1] ), 2) );
100  if (d <= myR) return true;
101  else return false;
102  };
103 private:
104  double myCx, myCy, myR;
105 };
106 
107 template <typename TPoint>
109 {
110 public:
111  typedef TPoint Point;
112  typedef double Value;
113 public:
114 
115  BallFunctor(double aCx, double aCy, double aR ):
116  myCx(aCx), myCy(aCy), myR(aR)
117  { ASSERT(myR > 0); };
118 
119  Value operator()(const TPoint& aPoint) const
120  {
121  double d = std::sqrt( std::pow( (myCx-aPoint[0] ), 2)
122  + std::pow( (myCy-aPoint[1] ), 2) );
123  return (d - myR);
124  };
125 private:
126  double myCx, myCy, myR;
127 };
128 
129 
130 template<typename TKSpace>
131 void
132 ballGenerator(const int& size, double aCx, double aCy, double aR, GridCurve<TKSpace>& gc)
133 {
134 
135  ASSERT( aR < (double) size );
136 
137  // Types
138  typedef TKSpace KSpace;
139  typedef typename KSpace::SCell SCell;
140  typedef GridCurve<KSpace> GridCurve;
141  typedef typename KSpace::Space Space;
142  typedef typename Space::Point Point;
143 
144  KSpace K;
145  bool ok = K.init( Point(-size,-size), Point(size,size), true );
146  if ( ! ok )
147  {
148  std::cerr << " error in creating KSpace." << std::endl;
149  }
150  try
151  {
152  BallPredicate<Point> dig(aCx, aCy, aR);
153  // Extracts shape boundary
155  SCell bel = Surfaces<KSpace>::findABel( K, dig, 10000 );
156  // Getting the consecutive surfels of the 2D boundary
157  std::vector<Point> points;
158  Surfaces<KSpace>::track2DBoundaryPoints( points, K, SAdj, dig, bel );
159  gc.initFromVector(points);
160  }
161  catch ( InputException e )
162  {
163  std::cerr << " error in finding a bel." << std::endl;
164  }
165 }
166 
167 template< typename TIterator >
168 void draw( const TIterator& itb, const TIterator& ite, const int& size, std::string basename)
169 {
170  typedef typename std::iterator_traits<TIterator>::value_type Pair;
171  typedef typename Pair::first_type Point;
172  typedef typename Pair::second_type Value;
173  HueShadeColorMap<unsigned char, 2> colorMap(0,3*size);
174 
175  Board2D b;
177 
178  TIterator it = itb;
179  for ( ; it != ite; ++it)
180  {
181  Point p = it->first;
182  b << CustomStyle( p.className(), new CustomFillColor( colorMap( it->second) ) );
183  b << p;
184  }
185 
186  std::stringstream s;
187  s << basename << ".eps";
188  b.saveEPS(s.str().c_str());
189 }
190 
191 
196 bool testDisplayDT2d(int size, int area, double distance)
197 {
198 
199  static const DGtal::Dimension dimension = 2;
200 
201  //Domain
203  typedef Domain::Point Point;
204  Domain d(Point::diagonal(-size), Point::diagonal(size));
206 
207  //Image and set
209  Image map( d, (size*size) );
210  map.setValue( Point::diagonal(0), 0.0 );
211  typedef DigitalSetFromMap<Image> Set;
212  Set set(map);
213 
214  //computation
215  trace.beginBlock ( "Display 2d FMM results " );
216 
218  FMM fmm(map, set, dp, area, distance);
219  fmm.compute();
220  trace.info() << fmm << std::endl;
221 
222  trace.endBlock();
223 
224  //display
225  std::stringstream s;
226  s << "DTFrom2dPt-" << size << "-" << area << "-" << distance;
227  draw(map.begin(), map.end(), size, s.str());
228 
229  return fmm.isValid();
230 }
231 
232 
234 bool accuracyTest(int size)
235 {
236 
237  static const DGtal::Dimension dimension = 2;
238 
239  //Domain
241  typedef Domain::Point Point;
242  Domain d(Point::diagonal(-size), Point::diagonal(size));
243  double h = 1.0/(double)size;
244 
245  //predicate
246  int radius = (size/2);
247  typedef BallPredicate<Point> Predicate;
248  Predicate predicate( 0, 0, radius );
249 
250  trace.beginBlock ( "test of accuracy" );
251  trace.info() << " # circle of radius 0.5 "
252  << "digitized in a square of size 1 "
253  << "at step h=" << h << endl;
254 
255  //Digital circle generation
256  typedef KhalimskySpaceND< dimension, int > KSpace;
257  KSpace K; K.init( Point::diagonal(-size), Point::diagonal(size), true);
259  KSpace::SCell bel = Surfaces<KSpace>::findABel( K, predicate, 10000 );
260  std::vector<KSpace::SCell> vSCells;
261  Surfaces<KSpace>::track2DBoundary( vSCells, K, SAdj, predicate, bel );
262 
263  double diff1, diff2, diff3 = 0.0;
264  {
265  //Image and set
267  typedef DigitalSetFromMap<Image> Set;
268  Image map( d );
269  Set set(map);
270 
271  //initialisation
273  typedef FMM<Image, Set, Predicate > FMM;
275 
277  FMM::initFromBelsRange( K,
278  vSCells.begin(), vSCells.end(),
279  map, set, 0.5 );
281 
282  //computation
284  FMM fmm(map, set, predicate);
285  fmm.compute();
286  trace.info() << fmm << std::endl;
288 
289  //max
290  double truth = radius*h;
291  double found = ( std::max(std::abs(fmm.max()),std::abs(fmm.min())) )*h;
292  double diff = std::abs(found-truth);
293  trace.info() << " # radius (low accuracy)" << std::endl;
294  trace.info() << " # truth: " << truth << std::endl;
295  trace.info() << " # found: " << found << std::endl;
296  trace.info() << " # diff.: " << diff << std::endl;
297 
298  diff1 = diff;
299  }
300 
301  {
302  //Image and set
304  typedef DigitalSetFromMap<Image> Set;
305  Image map( d );
306  Set set(map);
307 
308  //initialisation
309  typedef FMM<Image, Set, Predicate > FMM;
310 
311  typedef BallFunctor<Point> Functor;
312  Functor functor( 0, 0, radius );
314  FMM::initFromBelsRange( K,
315  vSCells.begin(), vSCells.end(),
316  functor, map, set );
318 
319  //computation
320  FMM fmm(map, set, predicate);
321  fmm.compute();
322  trace.info() << fmm << std::endl;
323 
324  //max
325  double truth = radius*h;
326  double found = ( std::max(std::abs(fmm.max()),std::abs(fmm.min())) )*h;
327  double diff = std::abs(found-truth);
328  trace.info() << " # radius (medium accuracy)" << std::endl;
329  trace.info() << " # truth: " << truth << std::endl;
330  trace.info() << " # found: " << found << std::endl;
331  trace.info() << " # diff.: " << diff << std::endl;
332 
333  diff2 = diff;
334  }
335 
336  {
337  //Image and set
339  typedef DigitalSetFromMap<Image> Set;
340  Image map( d );
341  Set set(map);
342 
343  //initialisation
345  typedef L2SecondOrderLocalDistance<Image, Set> Distance;
348 
349  typedef BallFunctor<Point> Functor;
350  Functor functor( 0, 0, radius );
351 
352  FMM::initFromBelsRange( K,
353  vSCells.begin(), vSCells.end(),
354  functor, map, set );
355 
356  //computation
357  Distance distance(map, set);
358  FMM fmm(map, set, predicate, distance);
359  fmm.compute();
360  trace.info() << fmm << std::endl;
361 
362  //max
363  double truth = radius*h;
364  double found = ( std::max(std::abs(fmm.max()),std::abs(fmm.min())) )*h;
365  double diff = std::abs(found-truth);
366  trace.info() << " # radius (high accuracy)" << std::endl;
367  trace.info() << " # truth: " << truth << std::endl;
368  trace.info() << " # found: " << found << std::endl;
369  trace.info() << " # diff.: " << diff << std::endl;
370 
371  diff3 = diff;
372  }
373 
374  trace.endBlock();
375 
376  return ( (diff1 >= diff2)&&(diff2 >= diff3) );
377 }
378 
383 bool testDisplayDT3d(int size, int area, double distance)
384 {
385 
386  static const DGtal::Dimension dimension = 3;
387 
388  //Domain
390  typedef Domain::Point Point;
391  Domain d(Point::diagonal(-size), Point::diagonal(size));
393 
394  //Image and set
396  Image map( d, 0.0 );
397  map.setValue( Point::diagonal(0), 0.0 );
398  typedef DigitalSetFromMap<Image> Set;
399  Set set(map);
400 
401  //computation
402  trace.beginBlock ( "Display 3d FMM results " );
403 
405  FMM fmm(map, set, dp, area, distance);
406  fmm.compute();
407  trace.info() << fmm << std::endl;
408 
409  trace.endBlock();
410 
411  { //display
412  HueShadeColorMap<unsigned char, 2> colorMap(0,2*size);
413 
414  Board2D b;
416 
417  Domain::ConstIterator it = d.begin();
418  for ( ; it != d.end(); ++it)
419  {
420  Point p3 = *it;
421  if (p3[2] == 0)
422  {
423  PointVector<2,Point::Coordinate> p2(p3[0], p3[1]);
424  b << CustomStyle( p2.className(),
425  new CustomFillColor( colorMap(map(p3)) ) )
426  << p2;
427  }
428  }
429 
430  std::stringstream s;
431  s << "DTFrom3dPt-" << size << "-" << area << "-" << distance
432  << ".eps";
433  b.saveEPS(s.str().c_str());
434  }
435 
436  return fmm.isValid();
437 }
438 
439 bool testDisplayDTFromCircle(int size)
440 {
441 
442  static const DGtal::Dimension dimension = 2;
443 
444  //Domain
446  typedef Domain::Point Point;
447  Domain d(Point::diagonal(-size), Point::diagonal(size));
449 
450  //Image and set
452  typedef DigitalSetFromMap<Image> Set;
453 
454  //Digital circle generation
455  typedef KhalimskySpaceND< dimension, int > KSpace;
456  GridCurve<KSpace> gc;
457  double radius = (rand()%size);
458  trace.info() << " #ball c(" << 0 << "," << 0 << ") r=" << radius << endl;
459  ballGenerator<KSpace>( size, 0, 0, radius, gc );
460 
461 
462  unsigned int nbok = 0;
463  unsigned int nb = 0;
464 
465  double dmaxInt = 0;
466  trace.beginBlock ( "Interior " );
467  {
468  typedef BallPredicate<Point> Predicate;
469  typedef FMM<Image, Set, Predicate > FMM;
470 
471  //init
472  Image map( d );
473  Set set(map);
475  FMM::initFromPointsRange(r.begin(), r.end(), map, set, 0.5);
476 
477  //computation
478  Predicate bp(0,0,radius);
479  FMM fmm(map, set, bp);
480  fmm.compute();
481  trace.info() << fmm << std::endl;
482  nbok += (fmm.isValid()?1:0);
483  trace.info() << nbok << "/" << ++nb << std::endl;
484 
485  //max
486  dmaxInt = fmm.getMax();
487 
488  //display
489  std::stringstream s;
490  s << "DTInCircle-" << size;
491  draw(map.begin(), map.end(), size, s.str());
492 
493  }
494  trace.endBlock();
495 
496  double dmaxExt = 0;
497  trace.beginBlock ( "Exterior " );
498  {
499  typedef NotPointPredicate<BallPredicate<Point> > PointPredicate;
500  typedef BinaryPointPredicate<PointPredicate,
501  DomainPredicate<Domain> > Predicate;
502  typedef FMM<Image, Set, Predicate > FMM;
503 
504  //init
505  Image map( d );
506  Set set(map);
508  FMM::initFromPointsRange(r.begin(), r.end(), map, set, 0.5);
509 
510  //computation
511  PointPredicate bp( BallPredicate<Point>(0,0,radius) );
512  Predicate pred( bp, dp, andBF2 );
513  FMM fmm(map, set, pred);
514  fmm.compute();
515  trace.info() << fmm << std::endl;
516  nbok += (fmm.isValid()?1:0);
517  trace.info() << nbok << "/" << ++nb << std::endl;
518 
519  //max
520  dmaxExt = fmm.getMax();
521 
522  //display
523  std::stringstream s;
524  s << "DTOutCircle-" << size;
525  draw(map.begin(), map.end(), size, s.str());
526  }
527  trace.endBlock();
528 
529  double dmin = 2*size*size;
530  double dmax = 0;
531  trace.beginBlock ( "Both " );
532  {
533  typedef DomainPredicate<Domain> Predicate;
534  typedef FMM<Image, Set, Predicate > FMM;
535 
536  //init
537  Image map( d );
538  Set set(map);
540  FMM::initFromIncidentPointsRange(r.begin(), r.end(), map, set, 0.5, true);
541 
542  //computation
543  FMM fmm(map, set, dp);
544  fmm.compute();
545  trace.info() << fmm << std::endl;
546  nbok += (fmm.isValid()?1:0);
547  trace.info() << nbok << "/" << ++nb << std::endl;
548 
549  //min, max
550  dmin = fmm.getMin();
551  dmax = fmm.getMax();
552 
553  //display
554  std::stringstream s;
555  s << "DTfromCircle-" << size;
556  draw(map.begin(), map.end(), size, s.str());
557  }
558  trace.endBlock();
559 
560  trace.beginBlock ( "Comparison " );
561  {
562  double epsilon = 0.0001;
563  nbok += ( ( (std::abs(-dmaxInt - dmin) < epsilon)
564  && (std::abs(dmaxExt - dmax) < epsilon) )?1:0);
565  trace.info() << nbok << "/" << ++nb << std::endl;
566  }
567  trace.endBlock();
568 
569  return (nb == nbok);
570 
571 }
572 
573 
578 template<Dimension dim, int norm>
579 bool testComparison(int size, int area, double dist)
580 {
581 
582  static const DGtal::Dimension dimension = dim;
583 
584  //Domain
586  typedef typename Domain::Point Point;
587  Domain d(Point::diagonal(-size), Point::diagonal(size));
589 
590  //Image and set for FMM
592  Image map( d );
593  map.setValue( Point::diagonal(0), 0.0 );
594  typedef DigitalSetBySTLSet<Domain> Set;
595  Set set( d );
596  set.insert( Point::diagonal(0) );
597 
598  //Image for separable DT
599  typedef Image Image2;
600  Image2 image ( d );
601  typename Domain::Iterator dit = d.begin();
602  typename Domain::Iterator ditEnd = d.end();
603  for ( ; dit != ditEnd; ++dit)
604  {
605  image.setValue(*dit, 128);
606  }
607  image.setValue(Point::diagonal(0), 0);
608 
609  //computation
610  trace.beginBlock ( " FMM computation " );
611 
612  typedef typename DistanceTraits<Image,Set,norm>::Distance Distance;
613  typedef FMM<Image, Set, DomainPredicate<Domain>, Distance > FMM;
614  Distance distance(map, set);
615  FMM fmm( map, set, dp, area, dist, distance );
616  fmm.compute();
617  trace.info() << fmm << std::endl;
618 
619  trace.endBlock();
620 
621  trace.beginBlock ( " DT computation " );
623  Predicate aPredicate(image,0);
624  typedef DistanceTransformation<SpaceND<dimension,int>, Predicate, norm> DT;
625  DT dt(d,aPredicate);
626  typename DT::OutputImage resultImage = dt.compute ( );
627  trace.info() << resultImage << std::endl;
628 
629  trace.endBlock();
630 
631  bool flagIsOk = true;
632 
633  trace.beginBlock ( " Comparison " );
634  //all points of result must be in map and have the same distance
635  typename Domain::ConstIterator it = d.begin();
636  typename Domain::ConstIterator itEnd = d.end();
637  for ( ; ( (it != itEnd)&&(flagIsOk) ); ++it)
638  {
639  if (set.find(*it) == set.end())
640  flagIsOk = false;
641  else
642  {
643  if (resultImage(*it) != map(*it))
644  flagIsOk = false;
645  }
646  }
647  trace.endBlock();
648 
649  return flagIsOk;
650 
651 }
652 
653 
654 
656 // Standard services - public :
657 
658 int main ( int argc, char** argv )
659 {
660  trace.beginBlock ( "Testing FMM" );
661  trace.info() << "Args:";
662  for ( int i = 0; i < argc; ++i )
663  trace.info() << " " << argv[ i ];
664  trace.info() << endl;
665 
666  //2d L2 tests
667  int size = 50;
668  int area = int( std::pow(double(2*size+1),2) )+1;
669  bool res
670  = testDisplayDT2d( size, area, std::sqrt(2*size*size) )
671  && testDisplayDT2d( size, area, size )
672  && testDisplayDT2d( size, 2*area, std::sqrt(2*size*size) )
673  && testDisplayDTFromCircle(size)
674  && accuracyTest(size)
675  ;
676 
677  size = 25;
678  area = 4*int( std::pow(double(size),3) );
679  //3d L2 test
680  res = res && testDisplayDT3d( size, area, std::sqrt(size*size*size) )
681  ;
682 
683  //3d L1 and Linf comparison
684  size = 20;
685  area = int( std::pow(double(2*size+1),3) )+1;
686  res = res
687  && testComparison<3,1>( size, area, 3*size+1 )
688  && testComparison<3,0>( size, area, size+1 )
689  ;
690  size = 5;
691  area = int( std::pow(double(2*size+1),4) ) + 1;
692  res = res
693  && testComparison<4,1>( size, area, 4*size+1 )
694  && testComparison<4,0>( size, area, size+1 )
695  ;
696 
697  //&& ... other tests
698  trace.emphase() << ( res ? "Passed." : "Error." ) << endl;
699  trace.endBlock();
700  return res ? 0 : 1;
701 }
702 // //