DGtal  0.9.3beta
testNeighborhoodConfigurations.cpp
1 
32 #include "DGtalCatch.h"
34 #include "DGtal/helpers/StdDefs.h"
35 #include "DGtal/shapes/Shapes.h"
36 #include "DGtal/base/Common.h"
37 #include "DGtal/topology/NeighborhoodConfigurations.h"
38 #include "DGtal/topology/tables/NeighborhoodTables.h"
39 using namespace std;
40 using namespace DGtal;
41 using namespace DGtal::functions;
42 
43 template <typename TObject>
44 TObject
45 Object3D(const typename TObject::DigitalTopology &dt)
46 {
47  using namespace DGtal;
48  using namespace Z3i;
49  Point p1( -10, -10, -10 );
50  Point p2( 10, 10, 10 );
51  Domain domain( p1, p2 );
52  Point c( 0, 0, 0 );
53  Point r( 3, 0, 0 );
54  DigitalSet diamond_set( domain );
55  for ( auto it = domain.begin(); it != domain.end(); ++it )
56  {
57  if ( (*it - c ).norm1() <= 3 ) diamond_set.insertNew( *it );
58  }
59  diamond_set.erase( c );
60  KSpace K;
61  K.init( domain.lowerBound(),
62  domain.upperBound(), true);
63 
64  return TObject(dt, diamond_set);
65 }
66 
67 TEST_CASE("Check that each neighborhood point in 3D (26 points) has associated a bit in an unsigned integer (NeighborhoodConfiguration).", "[map][mask][3D]" )
68 {
69  using namespace Z3i;
70  using Map = unordered_map<Point, NeighborhoodConfiguration>;
71  auto pointToMask3D =
72  mapZeroPointNeighborhoodToConfigurationMask< typename Object26_6::Point >();
73  Map truth3D;
74  truth3D[Point{ -1, -1, -1 }] = 1; // 0000 x x 0000 x x 0000 0001
75  truth3D[Point{ 0, -1, -1 }] = 2; // x x x x x x x 0010
76  truth3D[Point{ 1, -1, -1 }] = 4; // x x x x x x x 0100
77  truth3D[Point{ -1, 0, -1 }] = 8; // x x x x x x x 1000
78  truth3D[Point{ 0, 0, -1 }] = 16; // x x x x x x 0001 x
79  truth3D[Point{ 1, 0, -1 }] = 32; // x x x x x x 0010 x
80  truth3D[Point{ -1, 1, -1 }] = 64; // x x x x x x 0100 x
81  truth3D[Point{ 0, 1, -1 }] = 128; // x x x x x x 1000 x
82  truth3D[Point{ 1, 1, -1 }] = 256; // x x x x x 0001 x x
83  truth3D[Point{ -1, -1, 0 }] = 512; // x x x x x 0010 x x
84  truth3D[Point{ 0, -1, 0 }] = 1024; // x x x x x 0100 x x
85  truth3D[Point{ 1, -1, 0 }] = 2048; // x x x x x 1000 x x
86  truth3D[Point{ -1, 0, 0 }] = 4096; // x x x x 0001 x x x
87  truth3D[Point{ 1, 0, 0 }] = 8192; // x x x x 0010 x x x
88  truth3D[Point{ -1, 1, 0 }] = 16384; // x x x x 0100 x x x
89  truth3D[Point{ 0, 1, 0 }] = 32768; // x x x x 1000 x x x
90  truth3D[Point{ 1, 1, 0 }] = 65536; // x x x 0001 x x x x
91  truth3D[Point{ -1, -1, 1 }] = 131072; // x x x 0010 x x x x
92  truth3D[Point{ 0, -1, 1 }] = 262144; // x x x 0100 x x x x
93  truth3D[Point{ 1, -1, 1 }] = 524288; // x x x 1000 x x x x
94  truth3D[Point{ -1, 0, 1 }] = 1048576; // x x 0001 x x x x x
95  truth3D[Point{ 0, 0, 1 }] = 2097152; // x x 0010 x x x x x
96  truth3D[Point{ 1, 0, 1 }] = 4194304; // x x 0100 x x x x x
97  truth3D[Point{ -1, 1, 1 }] = 8388608; // x x 1000 x x x x x
98  truth3D[Point{ 0, 1, 1 }] = 16777216; // x 0001 x x x x x x
99  truth3D[Point{ 1, 1, 1 }] = 33554432; // x 0010 x x x x x x
100  CHECK(*pointToMask3D == truth3D);
101 
102 }
103 SCENARIO("Simplicity tables match on-the-fly calculations for all 3D topologies", "[simple][object][diamond][3D]" )
104 {
105  auto mapZeroNeighborhoodToMask = mapZeroPointNeighborhoodToConfigurationMask<Z3i::Point>();
106  using namespace Z3i;
107 
108  SECTION("26_6 topology using loadTable from string and default table size (2^26)"){
109  auto obj = Object3D<Object26_6>(dt26_6);
110  const auto & filename = simplicity::tableSimple26_6;
111  auto ptable = loadTable( filename );
112  CHECK(ptable->size() == 67108864);
113  const auto & table = *ptable;
114  auto & objSet = obj.pointSet();
115  size_t nsimples{0};
116  size_t nsimples_tables{0};
117  for( const auto & p : objSet){
118  auto simple = obj.isSimple(p);
119  if( simple ) ++nsimples;
120  auto cfg = obj.getNeighborhoodConfigurationOccupancy(p, *mapZeroNeighborhoodToMask);
121  auto simple_from_table = table[cfg];
122  if( simple_from_table ) ++nsimples_tables;
123  INFO("Point: " << p << " cfg: " << cfg);
124  CHECK(simple == simple_from_table);
125  }
126  CHECK(nsimples == nsimples_tables);
127  auto border_size = obj.border().size();
128  CHECK(nsimples == border_size);
129  }
130  SECTION("18_6 topology using load table with explicit size (2^26)"){
131  auto obj = Object3D<Object18_6>(dt18_6);
132  const auto & filename = simplicity::tableSimple18_6;
133  // known_size is 2^26 (default)
134  auto ptable = loadTable(filename, 67108864);
135  const auto & table = *ptable;
136  auto & objSet = obj.pointSet();
137  size_t nsimples{0};
138  size_t nsimples_tables{0};
139  for( const auto & p : objSet){
140  auto simple = obj.isSimple(p);
141  if( simple ) ++nsimples;
142  auto cfg = obj.getNeighborhoodConfigurationOccupancy(p, *mapZeroNeighborhoodToMask);
143  auto simple_from_table = table[cfg];
144  if( simple_from_table ) ++nsimples_tables;
145  INFO("Point: " << p << " cfg: " << cfg);
146  CHECK(simple == simple_from_table);
147  }
148  CHECK(nsimples == nsimples_tables);
149  auto border_size = obj.border().size();
150  CHECK(nsimples == border_size);
151  }
152 
153  SECTION("6_26 topology using loadTable with template parameter N=3 (dimension)"){
154  auto obj = Object3D<Object6_26>(dt6_26);
155  const auto & filename = simplicity::tableSimple6_26;
156  auto ptable = loadTable<3>(filename);
157  const auto & table = *ptable;
158  auto & objSet = obj.pointSet();
159  size_t nsimples{0};
160  size_t nsimples_tables{0};
161  for( const auto & p : objSet){
162  auto simple = obj.isSimple(p);
163  if( simple ) ++nsimples;
164  auto cfg = obj.getNeighborhoodConfigurationOccupancy(p, *mapZeroNeighborhoodToMask);
165  auto simple_from_table = table[cfg];
166  if( simple_from_table ) ++nsimples_tables;
167  INFO("Point: " << p << " cfg: " << cfg);
168  CHECK(simple == simple_from_table);
169  }
170  CHECK(nsimples == nsimples_tables);
171 
172  auto border_size = obj.border().size();
173  CHECK(nsimples != border_size);
174  }
175 
176  SECTION("6_18 topology"){
177  auto obj = Object3D<Object6_18>(dt6_18);
178  const auto & filename = simplicity::tableSimple6_18;
179  auto ptable = loadTable(filename);
180  const auto & table = *ptable;
181  auto & objSet = obj.pointSet();
182  size_t nsimples{0};
183  size_t nsimples_tables{0};
184  for( const auto & p : objSet){
185  auto simple = obj.isSimple(p);
186  if( simple ) ++nsimples;
187  auto cfg = obj.getNeighborhoodConfigurationOccupancy(p, *mapZeroNeighborhoodToMask);
188  auto simple_from_table = table[cfg];
189  if( simple_from_table ) ++nsimples_tables;
190  INFO("Point: " << p << " cfg: " << cfg);
191  CHECK(simple == simple_from_table);
192  }
193  CHECK(nsimples == nsimples_tables);
194 
195  auto border_size = obj.border().size();
196  CHECK(nsimples != border_size);
197  }
198 }
199 
200 
201 struct Objects2D{
204  Object8_4 obj8_4;
205  Object4_8 obj4_8;
206 
207  Objects2D()
208  {
209  using namespace DGtal;
210  using namespace Z2i;
211  Point p1( -17, -17 );
212  Point p2( 17, 17 );
213  Domain domain( p1, p2 );
214  DigitalSet shape_set( domain );
215  Shapes<Domain>::addNorm1Ball( shape_set, Point( -10, -8 ), 7 );
216  Shapes<Domain>::addNorm1Ball( shape_set, Point( 10, 8 ), 7 );
217  Shapes<Domain>::addNorm1Ball( shape_set, Point( 3, 0 ), 6 );
218  Shapes<Domain>::addNorm1Ball( shape_set, Point( 0, -3 ), 7 );
219  Shapes<Domain>::addNorm1Ball( shape_set, Point( -10, 0 ), 6 );
220  Shapes<Domain>::addNorm1Ball( shape_set, Point( -8, 8 ), 6 );
221  Shapes<Domain>::addNorm1Ball( shape_set, Point( 0, 9 ), 6 );
222  Shapes<Domain>::addNorm1Ball( shape_set, Point( 15, -2 ), 6 );
223  Shapes<Domain>::addNorm1Ball( shape_set, Point( 12, -10 ), 4 );
224  shape_set.erase( Point( 5, 0 ) );
225  shape_set.erase( Point( -1, -2 ) );
226  obj8_4 = Object8_4( dt8_4, shape_set );
227  obj4_8 = Object4_8( dt4_8, shape_set );
228  }
229 
230 };
231 
232 TEST_CASE("Check that each neighborhood point in 2D (8 points) has associated a bit in an unsigned integer (NeighborhoodConfiguration).", "[map][mask][2D]" )
233 {
234  using namespace Z2i;
235  using Map = unordered_map<Point, NeighborhoodConfiguration>;
236  auto pointToMask2D =
237  mapZeroPointNeighborhoodToConfigurationMask< typename Object8_4::Point >();
238  Map truth2D;
239  truth2D[Point{ -1, -1 }] = 1; // 0000 x x 0000 x x 0000 0001
240  truth2D[Point{ 0, -1 }] = 2; // x x x x x x x 0010
241  truth2D[Point{ 1, -1 }] = 4; // x x x x x x x 0100
242  truth2D[Point{ -1, 0 }] = 8; // x x x x x x x 1000
243  truth2D[Point{ 1, 0 }] = 16; // x x x x x x 0001 x
244  truth2D[Point{ -1, 1 }] = 32; // x x x x x x 0010 x
245  truth2D[Point{ 0, 1 }] = 64; // x x x x x x 0100 x
246  truth2D[Point{ 1, 1 }] = 128; // x x x x x x 1000 x
247 
248  CHECK(*pointToMask2D == truth2D);
249 }
250 
251 TEST_CASE_METHOD(Objects2D, "Simplicity tables match on-the-fly calculations for all 2D topologies", "[simple][object][balls][2D]" )
252 {
253  auto mapZeroNeighborhoodToMask = mapZeroPointNeighborhoodToConfigurationMask<Z2i::Point>();
254 
255  SECTION("8_4 and 4_8 topologies using loadTable with specific table size (2^8) and with template parameter N=2 (dimension)"){
256  // 8_4
257  {
258  const auto & filename = simplicity::tableSimple8_4;
259  auto ptable = loadTable(filename, 256);
260  const auto & table = *ptable;
261  auto & obj = obj8_4;
262  auto & objSet = obj.pointSet();
263  size_t nsimples{0};
264  size_t nsimples_tables{0};
265  for( const auto & p : objSet){
266  auto simple = obj.isSimple(p);
267  if( simple ) ++nsimples;
268  auto cfg = obj.getNeighborhoodConfigurationOccupancy(p, *mapZeroNeighborhoodToMask);
269  auto simple_from_table = table[cfg];
270  if( simple_from_table ) ++nsimples_tables;
271  INFO("Point: " << p << " cfg: " << cfg);
272  CHECK(simple == simple_from_table);
273  }
274  CHECK(nsimples == nsimples_tables);
275  }
276 
277  // 4_8
278  {
279  const auto & filename = simplicity::tableSimple4_8;
280  auto ptable = loadTable<2>(filename);
281  CHECK(ptable->size() == 256);
282  const auto & table = *ptable;
283  auto & obj = obj4_8;
284  auto & objSet = obj.pointSet();
285  size_t nsimples{0};
286  size_t nsimples_tables{0};
287  for( const auto & p : objSet){
288  auto simple = obj.isSimple(p);
289  if( simple ) ++nsimples;
290  auto cfg = obj.getNeighborhoodConfigurationOccupancy(p, *mapZeroNeighborhoodToMask);
291  auto simple_from_table = table[cfg];
292  if( simple_from_table ) ++nsimples_tables;
293  INFO("Point: " << p << " cfg: " << cfg);
294  CHECK(simple == simple_from_table);
295  }
296  CHECK(nsimples == nsimples_tables);
297  }
298  }
299 }
DigitalSetSelector< Domain, BIG_DS+HIGH_BEL_DS >::Type DigitalSet
Definition: StdDefs.h:100
const ConstIterator & begin() const
const ConstIterator & end() const
Object< DT4_8, DigitalSet > Object4_8
Definition: StdDefs.h:101
KhalimskySpaceND< 2, Integer > KSpace
Definition: StdDefs.h:77
STL namespace.
Object< DT8_4, DigitalSet > Object8_4
Definition: StdDefs.h:105
DGtal::CountedPtr< boost::dynamic_bitset<> > loadTable(const std::string &input_filename, unsigned int known_size)
const Point & upperBound() const
DGtal is the top-level namespace which contains all DGtal functions and types.
functions namespace gathers all DGtal functionsxs.
Definition: SetFunctions.h:768
const Point & lowerBound() const
Aim: A utility class for constructing different shapes (balls, diamonds, and others).