DGtalTools  1.5.beta
contourGenerator.cpp
1 
32 #include <cmath>
33 #include <iostream>
34 #include <iomanip>
35 #include <vector>
36 #include <string>
37 
38 #include "CLI11.hpp"
39 
40 #include "DGtal/base/Common.h"
41 #include "DGtal/kernel/domains/HyperRectDomain.h"
42 
43 #include "DGtal/shapes/ShapeFactory.h"
44 #include "DGtal/shapes/Shapes.h"
45 #include "DGtal/helpers/StdDefs.h"
46 
47 
48 #include "DGtal/io/colormaps/GrayscaleColorMap.h"
49 #include "DGtal/images/imagesSetsUtils/ImageFromSet.h"
50 #include "DGtal/images/imagesSetsUtils/SetFromImage.h"
51 #include "DGtal/images/ImageContainerBySTLVector.h"
52 #include "DGtal/io/boards/Board2D.h"
53 
54 #include "DGtal/shapes/GaussDigitizer.h"
55 #include "DGtal/geometry/curves/GridCurve.h"
56 #include "DGtal/geometry/curves/estimation/TrueLocalEstimatorOnPoints.h"
57 #include "DGtal/geometry/curves/estimation/TrueGlobalEstimatorOnPoints.h"
58 #include "DGtal/geometry/curves/estimation/ParametricShapeCurvatureFunctor.h"
59 #include "DGtal/geometry/curves/estimation/ParametricShapeTangentFunctor.h"
60 #include "DGtal/geometry/curves/estimation/ParametricShapeArcLengthFunctor.h"
61 
62 #include "DGtal/topology/helpers/Surfaces.h"
63 
64 
65 using namespace DGtal;
66 
146 std::vector<std::string> shapes2D;
147 std::vector<std::string> shapesDesc;
148 std::vector<std::string> shapesParam1;
149 std::vector<std::string> shapesParam2;
150 std::vector<std::string> shapesParam3;
151 std::vector<std::string> shapesParam4;
152 
153 
158 void createList()
159 {
160  shapes2D.push_back("ball");
161  shapesDesc.push_back("Ball for the Euclidean metric.");
162  shapesParam1.push_back("--radius [-R]");
163  shapesParam2.push_back("");
164  shapesParam3.push_back("");
165  shapesParam4.push_back("");
166 
167  shapes2D.push_back("square");
168  shapesDesc.push_back("square (no signature).");
169  shapesParam1.push_back("--width [-w]");
170  shapesParam2.push_back("");
171  shapesParam3.push_back("");
172  shapesParam4.push_back("");
173 
174  shapes2D.push_back("lpball");
175  shapesDesc.push_back("Ball for the l_power metric (no signature).");
176  shapesParam1.push_back("--radius [-R],");
177  shapesParam2.push_back("--power [-p]");
178  shapesParam3.push_back("");
179  shapesParam4.push_back("");
180 
181  shapes2D.push_back("flower");
182  shapesDesc.push_back("Flower with k petals with radius ranging from R+/-v.");
183  shapesParam1.push_back("--radius [-R],");
184  shapesParam2.push_back("--varsmallradius [-v],");
185  shapesParam3.push_back("--k [-k],");
186  shapesParam4.push_back("--phi");
187 
188  shapes2D.push_back("ngon");
189  shapesDesc.push_back("Regular k-gon.");
190  shapesParam1.push_back("--radius [-R],");
191  shapesParam2.push_back("--k [-k],");
192  shapesParam3.push_back("--phi");
193  shapesParam4.push_back("");
194 
195  shapes2D.push_back("accflower");
196  shapesDesc.push_back("Accelerated Flower with k petals.");
197  shapesParam1.push_back("--radius [-R],");
198  shapesParam2.push_back("--varsmallradius [-v],");
199  shapesParam3.push_back("--k [-k],");
200  shapesParam4.push_back("--phi");
201 
202  shapes2D.push_back("ellipse");
203  shapesDesc.push_back("Ellipse.");
204  shapesParam1.push_back("--axis1 [-A],");
205  shapesParam2.push_back("--axis2 [-a],");
206  shapesParam3.push_back("--phi");
207  shapesParam4.push_back("");
208 }
209 
214 void displayList()
215 {
216  trace.emphase()<<"2D Shapes:"<<std::endl;
217  for(unsigned int i=0; i<shapes2D.size(); ++i)
218  trace.info()<<"\t"<<shapes2D[i]<<"\t"
219  << shapesDesc[i]<<std::endl
220  <<"\t\tRequired parameter(s): "
221  << shapesParam1[i]<<" "
222  << shapesParam2[i]<<" "
223  << shapesParam3[i]<<" "
224  << shapesParam4[i]<<std::endl;
225 }
226 
227 
236 unsigned int checkAndReturnIndex(const std::string &shapeName)
237 {
238  unsigned int pos=0;
239 
240  while ((pos < shapes2D.size()) && (shapes2D[pos] != shapeName))
241  pos++;
242 
243  if (pos == shapes2D.size())
244  {
245  trace.error() << "The specified shape has not found.";
246  trace.info()<<std::endl;
247  exit(1);
248  }
249 
250  return pos;
251 }
252 
253 
265 template <typename Shape, typename Range, typename Point, typename Quantity>
266 void
267 estimateGeometry(Shape& s,
268  const double& h,
269  const Range& r,
270  std::vector<Point>& points,
271  std::vector<Point>& tangents,
272  std::vector<Quantity>& curvatures) {
273 
274  typedef typename Range::ConstIterator ConstIterator;
275  for (ConstIterator i = r.begin(); i != r.end(); ++i)
276  {
277  Point p( *i );
278  p *= h;
279  points.push_back(p);
280  }
281 
282  typedef typename Range::ConstCirculator ConstCirculator;
283 
284  typedef ParametricShapeTangentFunctor< Shape > TangentFunctor;
286  trueTangentEstimator;
287  trueTangentEstimator.attach( s );
288  trueTangentEstimator.eval( r.c(), r.c(), std::back_inserter(tangents), h );
289 
290  typedef ParametricShapeCurvatureFunctor< Shape > CurvatureFunctor;
292  trueCurvatureEstimator;
293  trueCurvatureEstimator.attach( s );
294  trueCurvatureEstimator.eval( r.c(), r.c(), std::back_inserter(curvatures), h );
295 }
296 
297 template <typename Space, typename Shape>
298 bool
299 generateContour(
300  Shape & aShape,
301  double h,
302  const std::string & outputFormat,
303  bool withGeom,
304  const std::string & outputFileName )
305 {
306  // Types
307  typedef typename Space::Point Point;
308  typedef typename Space::Vector Vector;
309  typedef typename Space::RealPoint RealPoint;
310  typedef typename Space::Integer Integer;
313  typedef typename KSpace::SCell SCell;
314  typedef typename GridCurve<KSpace>::PointsRange Range;
315  typedef typename Range::ConstIterator ConstIteratorOnPoints;
316  typedef typename GridCurve<KSpace>::MidPointsRange MidPointsRange;
317 
318  // Digitizer
320  dig.attach( aShape ); // attaches the shape.
321  Vector vlow(-1,-1); Vector vup(1,1);
322  dig.init( aShape.getLowerBound()+vlow, aShape.getUpperBound()+vup, h );
323  Domain domain = dig.getDomain();
324  // Create cellular space
325  KSpace K;
326  bool ok = K.init( dig.getLowerBound(), dig.getUpperBound(), true );
327  if ( ! ok )
328  {
329  std::cerr << "[generateContour]"
330  << " error in creating KSpace." << std::endl;
331  return false;
332  }
333  try
334  {
335  // Extracts shape boundary
337  SCell bel = Surfaces<KSpace>::findABel( K, dig, 10000 );
338  // Getting the consecutive surfels of the 2D boundary
339  std::vector<Point> points;
340  Surfaces<KSpace>::track2DBoundaryPoints( points, K, SAdj, dig, bel );
341  // Create GridCurve
342  GridCurve<KSpace> gridcurve;
343  gridcurve.initFromVector( points );
344  // gridcurve contains the digital boundary to analyze.
345  Range r = gridcurve.getPointsRange(); //building range
346 
347  if ( outputFormat == "pts" )
348  {
349  for ( ConstIteratorOnPoints it = r.begin(), it_end = r.end();
350  it != it_end; ++it )
351  {
352  Point p = *it;
353  std::cout << p[ 0 ] << " " << p[ 1 ] << std::endl;
354  }
355  }
356  else if ( outputFormat == "fc" )
357  {
358  ConstIteratorOnPoints it = r.begin();
359  Point p = *it++;
360  std::cout << p[ 0 ] << " " << p[ 1 ] << " ";
361  for ( ConstIteratorOnPoints it_end = r.end(); it != it_end; ++it )
362  {
363  Point p2 = *it;
364  Vector v = p2 - p;
365  if ( v[0 ]== 1 ) std::cout << '0';
366  if ( v[ 1 ] == 1 ) std::cout << '1';
367  if ( v[ 0 ] == -1 ) std::cout << '2';
368  if ( v[ 1 ] == -1 ) std::cout << '3';
369  p = p2;
370  }
371  // close freemanchain if necessary.
372  Point p2= *(r.begin());
373  Vector v = p2 - p;
374  if ( v.norm1() == 1 )
375  {
376  if ( v[ 0 ] == 1 ) std::cout << '0';
377  if ( v[ 1 ] == 1 ) std::cout << '1';
378  if ( v[ 0 ] == -1 ) std::cout << '2';
379  if ( v[ 1 ] == -1 ) std::cout << '3';
380  }
381  std::cout << std::endl;
382  }
383 
384  if (withGeom)
385  {
386  // write geometry of the shape
387  std::stringstream s;
388  s << outputFileName << ".geom";
389  std::ofstream outstream(s.str().c_str()); //output stream
390  if (!outstream.is_open()) return false;
391  else
392  {
393  outstream << "# " << outputFileName << std::endl;
394  outstream << "# Pointel (x,y), Midpoint of the following linel (x',y')" << std::endl;
395  outstream << "# id x y tangentx tangenty curvaturexy"
396  << " x' y' tangentx' tangenty' curvaturex'y'" << std::endl;
397 
398  std::vector<RealPoint> truePoints, truePoints2;
399  std::vector<RealPoint> trueTangents, trueTangents2;
400  std::vector<double> trueCurvatures, trueCurvatures2;
401 
402  estimateGeometry<Shape, Range, RealPoint, double>
403  (aShape, h, r, truePoints, trueTangents, trueCurvatures);
404 
405  estimateGeometry<Shape, MidPointsRange, RealPoint, double>
406  (aShape, h, gridcurve.getMidPointsRange(), truePoints2, trueTangents2, trueCurvatures2);
407 
408 
409  unsigned int n = (unsigned int)r.size();
410  for (unsigned int i = 0; i < n; ++i )
411  {
412  outstream << std::setprecision( 15 ) << i
413  << " " << truePoints[ i ][ 0 ]
414  << " " << truePoints[ i ][ 1 ]
415  << " " << trueTangents[ i ][ 0 ]
416  << " " << trueTangents[ i ][ 1 ]
417  << " " << trueCurvatures[ i ]
418  << " " << truePoints2[ i ][ 0 ]
419  << " " << truePoints2[ i ][ 1 ]
420  << " " << trueTangents2[ i ][ 0 ]
421  << " " << trueTangents2[ i ][ 1 ]
422  << " " << trueCurvatures2[ i ]
423  << std::endl;
424  }
425  }
426  outstream.close();
427  }
428 
430 
431  }
432  catch ( InputException e )
433  {
434  std::cerr << "[generateContour]"
435  << " error in finding a bel." << std::endl;
436  return false;
437  }
438  return true;
439 }
440 
446 void missingParam(std::string param)
447 {
448  trace.error() <<" Parameter: "<<param<<" is required..";
449  trace.info()<<std::endl;
450  exit(1);
451 }
452 
454 
455 int main( int argc, char** argv )
456 {
457  // parse command line CLI ----------------------------------------------
458  CLI::App app;
459  std::string shapeName;
460  std::string outputFileName;
461  std::string outputFormat {"pts"};
462  double radius;
463  double power {2.0};
464  double smallradius {5};
465  double varsmallradius {5};
466  double cx {0.0}, cy {0.0};
467  double h {1.0};
468  unsigned int k {3};
469  double phi {0.0};
470  double width {10.0};
471  double axis1, axis2;
472 
473  app.description("Generates multigrid contours of 2d digital shapes using DGtal library.\n Typical use example:\n \t contourGenerator --shape <shapeName> [requiredParam] [otherOptions]\n");
474  auto listOpt = app.add_flag("--list,-l","List all available shapes");
475  auto shapeNameOpt = app.add_option("--shape,-s", shapeName, "Shape name");
476  auto radiusOpt = app.add_option("--radius,-R", radius, "Radius of the shape" );
477  auto axis1Opt = app.add_option("--axis1,-A", axis1, "Half big axis of the shape (ellipse)" );
478  auto axis2Opt = app.add_option("--axis2,-a", axis2, "Half small axis of the shape (ellipse)" );
479  auto smallradiusOpt = app.add_option("--smallradius,-r", smallradius, "Small radius of the shape (default 5)", true);
480  auto varsmallradiusOpt = app.add_option("--varsmallradius,-v", varsmallradius, "Variable small radius of the shape (default 5)", true );
481  auto kOpt = app.add_option("-k", k, "Number of branches or corners the shape (default 3)", true );
482  auto phiOpt = app.add_option("--phi", phi, "Phase of the shape (in radian, default 0.0)", true );
483  auto widthOpt = app.add_option("--width,-w", width, "Width of the shape (default 10.0)", true );
484  auto powerOpt = app.add_option("--power,-p", power, "Power of the metric (default 2.0)", true );
485  app.add_option("--center_x,-x", cx, "x-coordinate of the shape center (default 0.0)", true );
486  app.add_option("--center_y,-y", cy, "y-coordinate of the shape center (default 0.0)", true );
487  app.add_option("--gridstep,-g", h, "Gridstep for the digitization (default 1.0)", true );
488  auto outputFormatOpt = app.add_option("--format,-f", outputFormat, "Output format:\n\t List of pointel coordinates {pts}\n\t Freeman chaincode Vector {fc} (default pts)", true );
489  auto outputFileNameOpt = app.add_option("--outputGeometry,-o", outputFileName, "Base name of the file containing the shape geometry (points, tangents, curvature)" );
490 
491  app.get_formatter()->column_width(40);
492  CLI11_PARSE(app, argc, argv);
493  // END parse command line using CLI ----------------------------------------------
494 
495  //List creation
496  createList();
497 
498  if ( listOpt->count() > 0 )
499  {
500  displayList();
501  return 0;
502  }
503 
504  if(shapeNameOpt->count()==0) missingParam("--shape");
505  bool withGeom = true;
506  if (outputFileNameOpt->count()==0) withGeom = false;
507 
508  //We check that the shape is known
509  unsigned int id = checkAndReturnIndex(shapeName);
510 
511  // standard types
512  typedef Z2i::Space Space;
513  typedef Space::RealPoint RealPoint;
514 
515  RealPoint center( cx, cy );
516 
517  if (id ==0)
518  {
519  if (radiusOpt->count()==0) missingParam("--radius");
520  Ball2D<Space> ball(Z2i::Point(0,0), radius);
521  generateContour<Space>( ball, h, outputFormat, withGeom, outputFileName );
522  }
523  else if (id == 1)
524  {
525  //if (widthOpt->count()==0) missingParam("--width");
526  ImplicitHyperCube<Space> object(Z2i::Point(0,0), width/2);
527  trace.error()<< "Not available.";
528  trace.info()<<std::endl;
529  }
530  else if (id == 2)
531  {
532  //if (powerOpt->count()==0) missingParam("--power");
533  if (radiusOpt->count()==0) missingParam("--radius");
534  ImplicitRoundedHyperCube<Space> ball(Z2i::Point(0,0), radius, power);
535  trace.error()<< "Not available.";
536  trace.info()<<std::endl;
537  }
538  else if (id == 3)
539  {
540  //if (varsmallradiusOpt->count()==0) missingParam("--varsmallradius");
541  if (radiusOpt->count()==0) missingParam("--radius");
542  //if (kOpt->count()==0) missingParam("--k");
543  //if (phiOpt->count()==0) missingParam("--phi");
544  Flower2D<Space> flower( center, radius, varsmallradius, k, phi );
545  generateContour<Space>( flower, h, outputFormat, withGeom, outputFileName );
546  }
547  else if (id == 4)
548  {
549  if (radiusOpt->count()==0) missingParam("--radius");
550  //if (kOpt->count()==0) missingParam("--k");
551  //if (phiOpt->count()==0) missingParam("--phi");
552  NGon2D<Space> object( center, radius, k, phi );
553  generateContour<Space>( object, h, outputFormat, withGeom, outputFileName );
554  }
555  else if (id == 5)
556  {
557  //if (varsmallradiusOpt->count()==0) missingParam("--varsmallradius");
558  if (radiusOpt->count()==0) missingParam("--radius");
559  //if (kOpt->count()==0) missingParam("--k");
560  //if (phiOpt->count()==0) missingParam("--phi");
561  AccFlower2D<Space> accflower( center, radius, varsmallradius, k, phi );
562  generateContour<Space>( accflower, h, outputFormat, withGeom, outputFileName );
563  }
564  else if (id == 6)
565  {
566  if (axis1Opt->count()==0) missingParam("--axis1");
567  if (axis2Opt->count()==0) missingParam("--axis2");
568  //if (phiOpt->count()==0) missingParam("--phi");
569  Ellipse2D<Space> ellipse( center, axis1, axis2, phi );
570  generateContour<Space>( ellipse, h, outputFormat, withGeom, outputFileName );
571  }
572 }
int main(int argc, char **argv)
ConstIterator begin() const
void attach(const EuclideanShape &shape)
Domain getDomain() const
const Point & getUpperBound() const
void init(const RealPoint &xLow, const RealPoint &xUp, typename RealVector::Component gridStep)
const Point & getLowerBound() const
MidPointsRange getMidPointsRange() const
PointsRange getPointsRange() const
bool initFromVector(const std::vector< Point > &aVectorOfPoints)
typename Self::Domain Domain
typename Self::Point Point
bool init(const Point &lower, const Point &upper, bool isClosed)
static void track2DBoundaryPoints(std::vector< Point > &aVectorOfPoints, const KSpace &K, const SurfelAdjacency< KSpace::dimension > &surfel_adj, const PointPredicate &pp, const SCell &start_surfel)
static SCell findABel(const KSpace &K, const PointPredicate &pp, unsigned int nbtries=1000)
std::ostream & error()
std::ostream & emphase()
std::ostream & info()
void attach(ParametricShape *aShapePtr)
Quantity eval(const ConstIterator &it) const
DGtal::int32_t Integer
Space::Vector Vector
SpaceND< 2, Integer > Space
T power(const T &aVal, const unsigned int exponent)
Trace trace(traceWriterTerm)