DGtal  0.6.devel
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
greedy-plane-segmentation-ex3.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;
79 struct SegmentedPlane {
80  NaivePlaneComputer plane;
81  Color color;
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  std::vector<Point> layer;
170  for ( ConstIterator it = digSurf.begin(), itE= digSurf.end(); it != itE; ++it )
171  {
172  if ( ( (++j) % 50 == 0 ) || ( j == nb ) ) trace.progressBar( j, nb );
173  Vertex v = *it;
174  axis = ks.sOrthDir( v );
175  planeComputer.init( axis, 500, widthNum, widthDen );
176  // The visitor takes care of all the breadth-first traversal.
177  Visitor visitor( digSurf, v );
178  layer.clear();
179  Visitor::Size currentSize = visitor.current().second;
180  while ( ! visitor.finished() )
181  {
182  Visitor::Node node = visitor.current();
183  v = node.first;
184  axis = ks.sOrthDir( v );
185  p = ks.sCoords( ks.sDirectIncident( v, axis ) );
186  if ( node.second != currentSize )
187  {
188  // std::cerr << "Layer " << currentSize << ", size=" << layer.size() << std::endl;
189  bool isExtended = planeComputer.extend( layer.begin(), layer.end() );
190  if ( ! isExtended )
191  break;
192  layer.clear();
193  currentSize = node.second;
194  }
195  layer.push_back( p );
196  visitor.expand();
197  }
198  // std::cerr << v << " -> " << planeComputer.size() << std::endl;
199  Q.push( VertexSize( v, planeComputer.size() ) );
200  }
201  trace.endBlock();
202 
203  trace.beginBlock( "2) Segmentation second pass. Visits vertices from the one with biggest plane to the one with smallest plane." );
204  std::set<Vertex> processedVertices;
205  std::map<Vertex,SegmentedPlane*> v2plane;
206  std::vector<SegmentedPlane*> segmentedPlanes;
207  j = 0;
208  while ( ! Q.empty() )
209  {
210  if ( ( (++j) % 50 == 0 ) || ( j == nb ) ) trace.progressBar( j, nb );
211  Vertex v = Q.top().v;
212  Q.pop();
213  if ( processedVertices.find( v ) != processedVertices.end() ) // already in set
214  continue; // process to next vertex
215 
216  SegmentedPlane* ptrSegment = new SegmentedPlane;
217  segmentedPlanes.push_back( ptrSegment ); // to delete them afterwards.
218  axis = ks.sOrthDir( v );
219  ptrSegment->plane.init( axis, 500, widthNum, widthDen );
220  // The visitor takes care of all the breadth-first traversal.
221  Visitor visitor( digSurf, v );
222  while ( ! visitor.finished() )
223  {
224  Visitor::Node node = visitor.current();
225  v = node.first;
226  if ( processedVertices.find( v ) == processedVertices.end() )
227  { // Vertex is not in processedVertices
228  axis = ks.sOrthDir( v );
229  p = ks.sCoords( ks.sDirectIncident( v, axis ) );
230  bool isExtended = ptrSegment->plane.extend( p );
231  if ( isExtended )
232  { // surfel is in plane.
233  processedVertices.insert( v );
234  v2plane[ v ] = ptrSegment;
235  visitor.expand();
236  }
237  else // surfel is not in plane and should not be used in the visit.
238  visitor.ignore();
239  }
240  else // surfel is already in some plane.
241  visitor.ignore();
242  }
243  // Assign random color for each plane.
244  ptrSegment->color = Color( random() % 256, random() % 256, random() % 256, 255 );
245  }
246  trace.endBlock();
248 
250  Viewer3D viewer;
251  viewer.show();
252  Color col( 255, 255, 120 );
253  for ( std::map<Vertex,SegmentedPlane*>::const_iterator
254  it = v2plane.begin(), itE = v2plane.end();
255  it != itE; ++it )
256  {
257  viewer << CustomColors3D( it->second->color, it->second->color );
258  viewer << ks.unsigns( it->first );
259  }
260  viewer << Display3D::updateDisplay;
262 
264  for ( std::vector<SegmentedPlane*>::iterator
265  it = segmentedPlanes.begin(), itE = segmentedPlanes.end();
266  it != itE; ++it )
267  delete *it;
268  segmentedPlanes.clear();
269  v2plane.clear();
271 
272  return application.exec();
273 }