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