DGtal  0.9.2
testSurfaceHelper.cpp
1 
30 #include <iostream>
32 #include <fstream>
33 #include "DGtal/base/Common.h"
34 #include "ConfigTest.h"
35 #include "DGtal/helpers/StdDefs.h"
36 #include "DGtal/geometry/curves/FreemanChain.h"
37 #include "DGtal/topology/KhalimskySpaceND.h"
38 #include "DGtal/topology/helpers/Surfaces.h"
39 #include "DGtal/topology/SurfelSetPredicate.h"
40 #include "DGtal/shapes/Shapes.h"
41 #include "DGtal/io/boards/Board2D.h"
42 #include "DGtal/io/readers/VolReader.h"
43 #include "DGtal/base/ConstAlias.h"
45 
46 using namespace std;
47 using namespace DGtal;
48 using namespace DGtal::functors;
49 
51 // Functions for testing class SurfaceHelper.
53 
60 bool testComputeInterior()
61 {
62  unsigned int nbok = 0;
63  unsigned int nb = 0;
64  typedef SpaceND<2, int> Space;
67  typedef KSpace::SCell SCell;
68  typedef KSpace::Point Point;
69  typedef ImageContainerBySTLMap< Domain, bool> BoolImage2D;
70 
71 
72  trace.beginBlock ( "Testing computation of interior from a freeman chain ..." );
73  std::string freemanChainFilename = testPath + "samples/contourS.fc";
74  std::string freemanChainFilename2 = testPath + "samples/SmallBall.fc";
75  fstream fst;
76  fst.open (freemanChainFilename.c_str(), ios::in);
78  fst.close();
79  fst.open (freemanChainFilename2.c_str(), ios::in);
81  fst.close();
82  std::set<SCell> boundaryCell;
83  std::set<SCell> boundaryCell2;
84  KSpace K, Ko;
85 
86  int minx, miny, maxx, maxy;
87  fc.computeBoundingBox(minx, miny, maxx, maxy);
88 
89  BoolImage2D::Domain dom(Point(minx-5,miny-5), Point(maxx+5, maxy+5));
90  trace.info() << "Domain defined by :" << dom.lowerBound() << " " << dom.upperBound() << std::endl;
91  K.init(dom.lowerBound(), dom.upperBound(), true);
92  Ko.init(dom.lowerBound(), dom.upperBound(), false);
94 
95  BoolImage2D interiorImage(dom);
96  unsigned int nbInt = Surfaces<KSpace>::uFillInterior(K, SurfelSetPredicate<std::set<SCell>, SCell>(boundaryCell),
97  interiorImage, 1, false);
98  trace.info() << "Interior size: " << nbInt << " (awaited: 3082)" << std::endl;
99 
100  BoolImage2D exteriorImage(dom);
101  unsigned int nbExt = Surfaces< KSpace >::uFillExterior(K ,SurfelSetPredicate<std::set<SCell>, SCell>(boundaryCell),
102  exteriorImage, 1, true);
103  unsigned int nbExto = Surfaces< KSpace >::uFillExterior(Ko ,SurfelSetPredicate<std::set<SCell>, SCell>(boundaryCell),
104  exteriorImage, 1, true);
105  trace.info() << "Exterior size: (KhalimskySpaceND open) " << nbExto << " (awaited: 9182)" << std::endl;
106  trace.info() << "Exterior size: (KhalimskySpaceND close)" << nbExt << " (awaited: 9182)" << std::endl;
107 
108 
109  KSpace K2, K2c;
110  int minx2, miny2, maxx2, maxy2;
111  fc2.computeBoundingBox(minx2, miny2, maxx2, maxy2);
112  BoolImage2D::Domain dom2(Point(minx2-5,miny2-5), Point(maxx2+5, maxy2+5));
113  K2.init(dom2.lowerBound(), dom2.upperBound(), false);
114  K2c.init(dom2.lowerBound(), dom2.upperBound(), true);
115  FreemanChain<Space::Integer>::getInterPixelLinels(K2, fc2, boundaryCell2 );
116 
117  BoolImage2D interiorImage2(dom2);
118  unsigned int nbInt2 = Surfaces< KSpace >::uFillInterior(K2, SurfelSetPredicate<std::set<SCell>,SCell>(boundaryCell2),
119  interiorImage2, 1, false);
120  trace.info() << "Interior size2: (KhalimskySpaceND open) " << nbInt2 << " (awaited: 196316)" << std::endl;
121  unsigned int nbInt2c = Surfaces< KSpace >::uFillInterior(K2c, SurfelSetPredicate<std::set<SCell>,SCell>(boundaryCell2),
122  interiorImage2, 1, false);
123  trace.info() << "Interior size2: (KhalimskySpaceND closed) " << nbInt2c << " (awaited: 196316)" << std::endl;
124 
125  // Displaying interiorCell
126  Board2D aBoard, aBoard2, aBoard3;
127 
128  for( BoolImage2D::Domain::ConstIterator it = interiorImage.domain().begin(); it!= interiorImage.domain().end(); ++it){
129  if(interiorImage(*it)){
130  aBoard << *it;
131  }
132  }
133 
134  for( BoolImage2D::Domain::ConstIterator it = exteriorImage.domain().begin(); it!= exteriorImage.domain().end(); it++){
135  if(exteriorImage(*it)){
136  aBoard3 << *it;
137  }
138  }
139 
140  for( BoolImage2D::Domain::ConstIterator it = interiorImage2.domain().begin(); it!= interiorImage2.domain().end(); it++){
141  if(interiorImage2(*it)){
142  aBoard2 << *it;
143  }
144  }
145 
146  aBoard<< CustomStyle( (*(boundaryCell.begin())).className(),
147  new CustomColors( Color::Red, Color::None ) );
148  aBoard3<< CustomStyle( (*(boundaryCell.begin())).className(),
149  new CustomColors( Color::Red, Color::None ) );
150  aBoard2<< CustomStyle( (*(boundaryCell.begin())).className(),
151  new CustomColors( Color::Red, Color::None ) );
152  for( std::set<SCell>::const_iterator it= boundaryCell.begin(); it!= boundaryCell.end(); it++){
153  aBoard << *it;
154  aBoard3 << *it;
155  }
156 
157  for( std::set<SCell>::const_iterator it= boundaryCell2.begin(); it!= boundaryCell2.end(); it++){
158  aBoard2 << *it;
159  }
160 
161  aBoard << CustomStyle( fc.className(),
162  new CustomColors( Color::Red, Color::None ) );
163  aBoard3 << CustomStyle( fc.className(),
164  new CustomColors( Color::Red, Color::None ) );
165  aBoard2 << CustomStyle( fc.className(),
166  new CustomColors( Color::Red, Color::None ) );
167  aBoard << SetMode( fc.className(), "InterGrid" );
168  aBoard3 << SetMode( fc.className(), "InterGrid" );
169  aBoard2 << SetMode( fc.className(), "InterGrid" );
170  aBoard << fc;
171  aBoard3 << fc;
172  aBoard2 << fc2;
173 
174  aBoard.saveEPS("testSurfaceHelperComputeInterior.eps");
175  aBoard3.saveEPS("testSurfaceHelperComputeExterior.eps");
176  aBoard2.saveEPS("testSurfaceHelperComputeInterior2.eps");
177  nbok += (nbInt == 3082 && nbInt2 == 196316 && nbInt2c == 196316 && nbExt== 9182 && nbExto== 9182)? 1 : 0;
178  nb++;
179  trace.info() << "(" << nbok << "/" << nb << ") "
180  << nbInt << " (interiorCell.size()) == 3014 and "
181  << nbInt2 << " (interiorCell2.size()) == 60196 "
182  << std::endl;
183  trace.endBlock();
184 
185  return nbok == nb;
186 }
187 
188 
189 bool
190 test3dSurfaceHelper()
191 {
193  unsigned int nbok = 0;
194  unsigned int nb = 0;
195 
196  trace.beginBlock ( "Testing extraction of 3D connected component ..." );
197  // import point from a vol file
199  Image3dChar image = VolReader<Image3dChar>::importVol( testPath + "samples/cat10.vol");
200  Set aSet(image.domain());
201  for(auto const &p: image.domain())
202  {
203  if(image(p)>0)
204  {
205  aSet.insert(p);
206  }
207  }
208  Z3i::KSpace Kc;
209  Kc.init(image.domain().lowerBound(),
210  image.domain().upperBound(), true);
211  SurfelAdjacency<3> SAdj( false );
212  std::vector<std::vector<DGtal::Z3i::SCell> > vectConnectedSCell;
213  Surfaces<DGtal::Z3i::KSpace>::extractAllConnectedSCell(vectConnectedSCell,Kc, SAdj, aSet, false);
214  nb++;
215  nbok += vectConnectedSCell.size()==1;
216  trace.info() << "Connected component :" << vectConnectedSCell.size() << " (should be 1) " << std::endl;
217  trace.endBlock();
218 
219  trace.beginBlock("Test 3D filling interior of surface (in an closed KhalimskySpaceND ) ...");
220  Image3dChar imageFilled(image.domain());
221  std::set<Z3i::SCell> setSCell; for (auto const &s: vectConnectedSCell[0]) setSCell.insert(s);
223 
224  unsigned int nbFilled = DGtal::Surfaces<DGtal::Z3i::KSpace>::uFillInterior(Kc, surfacePred, imageFilled, 1);
225  trace.info() << "Nb voxel filled:" << nbFilled << " (should be " << aSet.size() << " )" << std::endl;
226  nb++;
227  nbok += nbFilled == aSet.size();
228  trace.endBlock();
229 
230 
231  trace.beginBlock("Test 3D filling interior of surface (in an open KhalimskySpaceND ) ...");
232  Z3i::KSpace ko;
233  ko.init(image.domain().lowerBound(),
234  image.domain().upperBound(), false);
235  unsigned int nbFilled2 = DGtal::Surfaces<DGtal::Z3i::KSpace>::uFillInterior(ko, surfacePred, imageFilled, 1);
236  trace.info() << "Nb voxel filled:" << nbFilled2 << " (should be " << aSet.size() << " )" << std::endl;
237  nb++;
238  nbok += nbFilled2 == aSet.size();
239  trace.endBlock();
240 
241 
242  trace.beginBlock("Test 3D filling exterior of surface (in an closed KhalimskySpaceND ) ...");
243  unsigned int nbFilled3 = DGtal::Surfaces<DGtal::Z3i::KSpace>::uFillExterior(Kc, surfacePred, imageFilled, 1);
244  trace.info() << "Nb voxel filled:" << nbFilled3 << " (should be " << aSet.size() << " )" << std::endl;
245  nb++;
246  nbok += nbFilled3 == imageFilled.size()-aSet.size();
247  trace.endBlock();
248 
249 
250 
251  trace.beginBlock("Test 3D filling exterior of surface (in an open KhalimskySpaceND ) ...");
252  unsigned int nbFilled4 = DGtal::Surfaces<DGtal::Z3i::KSpace>::uFillExterior(ko, surfacePred, imageFilled, 1);
253  trace.info() << "Nb voxel filled:" << nbFilled4 << " (should be " << aSet.size() << " )" << std::endl;
254  nb++;
255  nbok += nbFilled4 == imageFilled.size()-aSet.size();
256  trace.endBlock();
257 
258 
259 
260 
261  return nb == nbok;
262 }
263 
264 
270 template <typename KSpace3D>
271 bool testFindABel()
272 {
273  typedef KSpace3D KSpace;
274  typedef typename KSpace::Space Space;
275  typedef typename KSpace::Point Point;
276  typedef typename KSpace::SCell SCell;
277  typedef HyperRectDomain<Space> Domain;
279  unsigned int nbok = 0;
280  unsigned int nb = 0;
281  trace.beginBlock ( "Testing Surfaces::findABel." );
282  Point pts[ 8 ];
283  Point p1( -5, -5, -5 );
284  Point p2( 5, 5, 5 );
285  pts[ 0 ] = p1;
286  pts[ 1 ] = p2;
287  pts[ 2 ] = Point( 5, -5, -5 );
288  pts[ 3 ] = Point( -5, 5, -5 );
289  pts[ 4 ] = Point( 5, 5, -5 );
290  pts[ 5 ] = Point( -5, -5, 5 );
291  pts[ 6 ] = Point( 5, -5, 5 );
292  pts[ 7 ] = Point( -5, 5, 5 );
293  KSpace K; K.init( p1, p2, true );
294  Domain domain( p1, p2 );
295  DigitalSet aSet( domain );
296  Shapes<Domain>::addNorm2Ball( aSet, Point::zero, 2 );
297  for ( unsigned int i = 0; i < 8; ++i )
298  {
299  SCell bel = Surfaces<KSpace>::findABel( K, aSet, pts[ i ], Point::zero );
300  trace.info() << "- Exterior point is " << pts[ i ] << std::endl;
301  trace.info() << " - Found bel = " << bel << std::endl;
302  ++nb, nbok += K.sDim( bel ) == 2;
303  trace.info() << "(" << nbok << "/" << nb << ") "
304  << " K.sDim( bel ) == " << K.sDim( bel ) << " (should be 2)" << std::endl;
305  SCell vox_in = K.sDirectIncident( bel, K.sOrthDir( bel ) );
306  SCell vox_out = K.sIndirectIncident( bel, K.sOrthDir( bel ) );
307  ++nb, nbok += aSet( K.sCoords( vox_in ) ) ? 1 : 0;
308  trace.info() << "(" << nbok << "/" << nb << ") "
309  << " vox_in should be inside the shape." << std::endl;
310  ++nb, nbok += aSet( K.sCoords( vox_out ) ) ? 0 : 1;
311  trace.info() << "(" << nbok << "/" << nb << ") "
312  << " vox_out should be outside the shape." << std::endl;
313  }
314  return nbok == nb;
315 }
316 
317 
319 // Standard services - public :
320 
321 int main( int argc, char** argv )
322 {
323  trace.beginBlock ( "Testing class SurfaceHelper" );
324  trace.info() << "Args:";
325  for ( int i = 0; i < argc; ++i )
326  trace.info() << " " << argv[ i ];
327  trace.info() << endl;
328 
329  bool res = testComputeInterior()
330  && testFindABel< KhalimskySpaceND<3,int> >() && test3dSurfaceHelper();
331  trace.emphase() << ( res ? "Passed." : "Error." ) << endl;
332  trace.endBlock();
333  return res ? 0 : 1;
334 }
335 // //
void beginBlock(const std::string &keyword="")
DigitalSetSelector< Domain, BIG_DS+HIGH_BEL_DS >::Type DigitalSet
Definition: StdDefs.h:100
Trace trace
Definition: Common.h:130
Aim: SpaceND is a utility class that defines the fundamental structure of a Digital Space in ND...
Definition: SpaceND.h:95
Aim: A utility class for constructing surfaces (i.e. set of (n-1)-cells).
Definition: Surfaces.h:78
KhalimskySpaceND< 2, Integer > KSpace
Definition: StdDefs.h:77
Aim: Represent adjacencies between surfel elements, telling if it follows an interior to exterior ord...
STL namespace.
double endBlock()
Custom style class redefining the pen color and the fill color. You may use Board2D::Color::None for ...
Definition: Board2D.h:278
KSpace K2
Definition: StdDefs.h:78
functors namespace gathers all DGtal functors.
std::ostream & emphase()
bool init(const Point &lower, const Point &upper, bool isClosed)
Aim: implements methods to read a "Vol" file format.
Definition: VolReader.h:88
DGtal is the top-level namespace which contains all DGtal functions and types.
std::ostream & info()
Represents a signed cell in a cellular grid space by its Khalimsky coordinates and a boolean value...
void saveEPS(const char *filename, PageSize size=Board::BoundingBox, double margin=10.0) const
Definition: Board.cpp:805
unsigned static int uFillInterior(const KSpace &aKSpace, const TSurfelPredicate &aSurfPred, TImageContainer &anImage, const typename TImageContainer::Value &aValue, bool empty_is_inside=false, bool incrementMode=true)
Modifier class in a Board2D stream. Useful to choose your own mode for a given class. Realizes the concept CDrawableWithBoard2D.
Definition: Board2D.h:247
unsigned static int uFillExterior(const KSpace &aKSpace, const SurfelPredicate &aSurfPred, TImageContainer &anImage, const typename TImageContainer::Value &aValue, bool empty_is_outside=true, bool incrementMode=true)
Aim: The predicate returning true iff the point is in the domain given at construction.
Aim: A utility class for constructing different shapes (balls, diamonds, and others).
Aim: This class is a model of CCellularGridSpaceND. It represents the cubical grid as a cell complex...
Aim: A container class for storing sets of digital points within some given domain.
Aim: This class specializes a 'Board' class so as to display DGtal objects more naturally (with <<)...
Definition: Board2D.h:70