DGtal  0.6.devel
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
greedy-plane-segmentation-ex2.cpp
1 
30 
31 #include <iostream>
32 #include <vector>
33 #include <set>
34 #include <map>
35 #include <queue>
36 #include <boost/program_options/options_description.hpp>
37 #include <boost/program_options/parsers.hpp>
38 #include <boost/program_options/variables_map.hpp>
39 
40 #include <QtGui/qapplication.h>
41 #include "DGtal/base/Common.h"
42 #include "DGtal/io/readers/VolReader.h"
43 #include "DGtal/io/viewers/Viewer3D.h"
44 #include "DGtal/io/Display3D.h"
45 
46 #include "DGtal/io/DrawWithDisplay3DModifier.h"
47 #include "DGtal/images/ImageSelector.h"
48 #include "DGtal/images/imagesSetsUtils/SetFromImage.h"
49 #include "DGtal/topology/DigitalSurface.h"
50 #include "DGtal/topology/DigitalSetBoundary.h"
51 #include "DGtal/topology/BreadthFirstVisitor.h"
52 #include "DGtal/geometry/surfaces/COBANaivePlane.h"
53 #include "DGtal/helpers/StdDefs.h"
54 #include "ConfigExamples.h"
55 
57 
58 using namespace std;
59 using namespace DGtal;
60 namespace po = boost::program_options;
61 
63 using namespace Z3i;
64 typedef DGtal::int64_t InternalInteger;
66 // We choose the DigitalSetBoundary surface container in order to
67 // segment connected or unconnected surfaces.
70 typedef MyDigitalSurface::ConstIterator ConstIterator;
71 typedef MyDigitalSurface::Vertex Vertex;
72 typedef MyDigitalSurface::SurfelSet SurfelSet;
73 typedef SurfelSet::iterator SurfelSetIterator;
82 };
83 struct VertexSize {
84  Vertex v;
85  unsigned int size;
86  inline VertexSize( const Vertex & aV, unsigned int aSize )
87  : v( aV ), size( aSize )
88  {}
89 };
90 
91 inline
92 bool operator<( const VertexSize & vs1, const VertexSize & vs2 )
93 {
94  return vs1.size < vs2.size;
95 }
97 
99 
100 int main( int argc, char** argv )
101 {
103  // parse command line ----------------------------------------------
104  po::options_description general_opt("Allowed options are: ");
105  general_opt.add_options()
106  ("help,h", "display this message")
107  ("input-file,i", po::value<std::string>()->default_value( examplesPath + "samples/Al.100.vol" ), "the volume file (.vol)" )
108  ("threshold,t", po::value<unsigned int>()->default_value(1), "the value that defines the isosurface in the image (an integer between 0 and 255)." )
109  ("width-num,w", po::value<unsigned int>()->default_value(1), "the numerator of the rational width (a non-null integer)." )
110  ("width-den,d", po::value<unsigned int>()->default_value(1), "the denominator of the rational width (a non-null integer)." );
111 
112  bool parseOK = true;
113  po::variables_map vm;
114  try {
115  po::store(po::parse_command_line(argc, argv, general_opt), vm);
116  } catch ( const std::exception & ex ) {
117  parseOK = false;
118  trace.info() << "Error checking program options: "<< ex.what()<< endl;
119  }
120  po::notify(vm);
121  if ( ! parseOK || vm.count("help") || ( argc <= 1 ) )
122  {
123  std::cout << "Usage: " << argv[0]
124  << " [-i <fileName.vol>] [-t <threshold>] [-w <num>] [-d <den>]" << std::endl
125  << "Segments the surface at given threshold within given volume into digital planes of rational width num/den." << std::endl
126  << general_opt << std::endl;
127  return 0;
128  }
129  string inputFilename = vm["input-file"].as<std::string>();
130  unsigned int threshold = vm["threshold"].as<unsigned int>();
131  unsigned int widthNum = vm["width-num"].as<unsigned int>();
132  unsigned int widthDen = vm["width-den"].as<unsigned int>();
134 
136  QApplication application(argc,argv);
138  Image image = VolReader<Image>::importVol(inputFilename);
139  DigitalSet set3d (image.domain());
140  SetFromImage<DigitalSet>::append<Image>(set3d, image, threshold,255);
142 
144  trace.beginBlock( "Set up digital surface." );
145  // We initializes the cellular grid space used for defining the
146  // digital surface.
147  KSpace ks;
148  bool ok = ks.init( set3d.domain().lowerBound(),
149  set3d.domain().upperBound(), true );
150  if ( ! ok ) std::cerr << "[KSpace.init] Failed." << std::endl;
151  SurfelAdjacency<KSpace::dimension> surfAdj( true ); // interior in all directions.
152  MyDigitalSurfaceContainer* ptrSurfContainer =
153  new MyDigitalSurfaceContainer( ks, set3d, surfAdj );
154  MyDigitalSurface digSurf( ptrSurfContainer ); // acquired
155  trace.endBlock();
157 
159  Point p;
160  Dimension axis;
161  unsigned int j = 0;
162  unsigned int nb = digSurf.size();
163 
164  // First pass to find biggest planes.
165  trace.beginBlock( "1) Segmentation first pass. Computes all planes so as to sort vertices by the plane size." );
166  std::map<Vertex,unsigned int> v2size;
167  NaivePlaneComputer planeComputer;
168  std::priority_queue<VertexSize> Q;
169  for ( ConstIterator it = digSurf.begin(), itE= digSurf.end(); it != itE; ++it )
170  {
171  if ( ( (++j) % 50 == 0 ) || ( j == nb ) ) trace.progressBar( j, nb );
172  Vertex v = *it;
173  axis = ks.sOrthDir( v );
174  planeComputer.init( axis, 500, widthNum, widthDen );
175  // The visitor takes care of all the breadth-first traversal.
176  Visitor visitor( digSurf, v );
177  while ( ! visitor.finished() )
178  {
179  Visitor::Node node = visitor.current();
180  v = node.first;
181  axis = ks.sOrthDir( v );
182  p = ks.sCoords( ks.sDirectIncident( v, axis ) );
183  bool isExtended = planeComputer.extend( p );
184  if ( isExtended )
185  // surfel is in plane.
186  visitor.expand();
187  else // surfel is not in plane and should not be used in the visit.
188  visitor.ignore();
189  }
190  Q.push( VertexSize( v, planeComputer.size() ) );
191  }
192  trace.endBlock();
193 
194  trace.beginBlock( "2) Segmentation second pass. Visits vertices from the one with biggest plane to the one with smallest plane." );
195  std::set<Vertex> processedVertices;
196  std::vector<SegmentedPlane*> segmentedPlanes;
197  std::map<Vertex,SegmentedPlane*> v2plane;
198  j = 0;
199  while ( ! Q.empty() )
200  {
201  if ( ( (++j) % 50 == 0 ) || ( j == nb ) ) trace.progressBar( j, nb );
202  Vertex v = Q.top().v;
203  Q.pop();
204  if ( processedVertices.find( v ) != processedVertices.end() ) // already in set
205  continue; // process to next vertex
206 
207  SegmentedPlane* ptrSegment = new SegmentedPlane;
208  segmentedPlanes.push_back( ptrSegment ); // to delete them afterwards.
209  axis = ks.sOrthDir( v );
210  ptrSegment->plane.init( axis, 500, widthNum, widthDen );
211  // The visitor takes care of all the breadth-first traversal.
212  Visitor visitor( digSurf, v );
213  while ( ! visitor.finished() )
214  {
215  Visitor::Node node = visitor.current();
216  v = node.first;
217  if ( processedVertices.find( v ) == processedVertices.end() )
218  { // Vertex is not in processedVertices
219  axis = ks.sOrthDir( v );
220  p = ks.sCoords( ks.sDirectIncident( v, axis ) );
221  bool isExtended = ptrSegment->plane.extend( p );
222  if ( isExtended )
223  { // surfel is in plane.
224  processedVertices.insert( v );
225  v2plane[ v ] = ptrSegment;
226  visitor.expand();
227  }
228  else // surfel is not in plane and should not be used in the visit.
229  visitor.ignore();
230  }
231  else // surfel is already in some plane.
232  visitor.ignore();
233  }
234  // Assign random color for each plane.
235  ptrSegment->color = Color( random() % 256, random() % 256, random() % 256, 255 );
236  }
237  trace.endBlock();
239 
241  Viewer3D viewer;
242  viewer.show();
243  for ( std::map<Vertex,SegmentedPlane*>::const_iterator
244  it = v2plane.begin(), itE = v2plane.end();
245  it != itE; ++it )
246  {
247  viewer << CustomColors3D( it->second->color, it->second->color );
248  viewer << ks.unsigns( it->first );
249  }
250  viewer << Display3D::updateDisplay;
252 
254  for ( std::vector<SegmentedPlane*>::iterator
255  it = segmentedPlanes.begin(), itE = segmentedPlanes.end();
256  it != itE; ++it )
257  delete *it;
258  segmentedPlanes.clear();
259  v2plane.clear();
261 
262  return application.exec();
263 }